root/drivers/isdn/isdn_ppp.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isdn_ppp_free
  2. isdn_ppp_bind
  3. isdn_ppp_hangup
  4. isdn_ppp_open
  5. isdn_ppp_release
  6. get_arg
  7. set_arg
  8. isdn_ppp_ioctl
  9. isdn_ppp_select
  10. isdn_ppp_fill_rq
  11. isdn_ppp_read
  12. isdn_ppp_write
  13. isdn_ppp_init
  14. isdn_ppp_cleanup
  15. isdn_ppp_receive
  16. isdn_ppp_push_higher
  17. isdn_ppp_xmit
  18. isdn_ppp_free_mpqueue
  19. isdn_ppp_bundle
  20. isdn_ppp_mask_queue
  21. isdn_ppp_fill_mpqueue
  22. isdn_ppp_cleanup_queue
  23. isdn_ppp_timer_timeout
  24. isdn_ppp_dev_ioctl
  25. isdn_ppp_if_get_unit
  26. isdn_ppp_dial_slave

   1 /* $Id: isdn_ppp.c,v 1.5 1996/04/20 16:32:32 fritz Exp $
   2  *
   3  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
   4  *
   5  * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
   6  * 
   7  * This program is free software; you can redistribute it and/or modify
   8  * it under the terms of the GNU General Public License as published by
   9  * the Free Software Foundation; either version 2, or (at your option)
  10  * any later version.
  11  *
  12  * This program is distributed in the hope that it will be useful,
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  *
  17  * You should have received a copy of the GNU General Public License
  18  * along with this program; if not, write to the Free Software
  19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  20  *
  21  * $Log: isdn_ppp.c,v $
  22  * Revision 1.5  1996/04/20 16:32:32  fritz
  23  * Changed ippp_table to an array of pointers, allocating each part
  24  * separately.
  25  *
  26  * Revision 1.4  1996/02/19 15:25:50  fritz
  27  * Bugfix: Sync-PPP packets got compressed twice, when resent due to
  28  * send-queue-full reject.
  29  *
  30  * Revision 1.3  1996/02/11 02:27:12  fritz
  31  * Lot of Bugfixes my Michael.
  32  * Moved calls to skb_push() into isdn_net_header()
  33  * Fixed a possible race-condition in isdn_ppp_timer_timeout().
  34  *
  35  * Revision 1.2  1996/01/22 05:08:06  fritz
  36  * Merged in Michael's patches for MP.
  37  * Minor changes in isdn_ppp_xmit.
  38  *
  39  * Revision 1.1  1996/01/09 04:11:29  fritz
  40  * Initial revision
  41  *
  42  */
  43 
  44 /* TODO: right tbusy handling when using MP */
  45 
  46 #ifndef STANDALONE
  47 #include <linux/config.h>
  48 #endif
  49 #define __NO_VERSION__
  50 #include <linux/module.h>
  51 #include <linux/isdn.h>
  52 #include "isdn_common.h"
  53 #include "isdn_ppp.h"
  54 #include "isdn_net.h"
  55 
  56 #ifndef PPP_IPX
  57 #define PPP_IPX 0x002b 
  58 #endif
  59  
  60 /* Prototypes */
  61 static int isdn_ppp_fill_rq(char *buf, int len, int minor);
  62 static int isdn_ppp_hangup(int);
  63 static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
  64                         struct sk_buff *skb, int proto);
  65 static int isdn_ppp_if_get_unit(char **namebuf);
  66 
  67 #ifdef CONFIG_ISDN_MPP
  68 static int isdn_ppp_bundle(int, int);
  69 static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask);
  70 static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min);
  71 static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
  72                 int BEbyte, int *sqno, int min_sqno);
  73 #endif
  74 
  75 char *isdn_ppp_revision              = "$Revision: 1.5 $";
  76 struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
  77 
  78 extern int isdn_net_force_dial_lp(isdn_net_local *);
  79 
  80 int isdn_ppp_free(isdn_net_local * lp)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82         if (lp->ppp_minor < 0)
  83                 return 0;
  84 
  85 #ifdef CONFIG_ISDN_MPP
  86         if(lp->master)
  87         {
  88                 isdn_net_dev *p = dev->netdev;
  89                 lp->last->next = lp->next;
  90                 lp->next->last = lp->last;
  91                 if(lp->netdev->queue == lp)
  92                         lp->netdev->queue = lp->next;
  93                 lp->next = lp->last = lp;
  94                 while(p) {
  95                         if(lp == &p->local) {
  96                                 lp->netdev = p;
  97                                 break;
  98                         }
  99                         p=p->next;
 100                 }
 101         } else {
 102                 lp->netdev->ib.bundled = 0;
 103                 /* last link: free mpqueue, free sqqueue ? */
 104         }
 105 
 106 #endif
 107 
 108         isdn_ppp_hangup(lp->ppp_minor);
 109 #if 0
 110         printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_minor, (long) lp,(long) ippp_table[lp->ppp_minor]->lp);
 111 #endif
 112         ippp_table[lp->ppp_minor]->lp = NULL;
 113         return 0;
 114 }
 115 
 116 int isdn_ppp_bind(isdn_net_local * lp)
     /* [previous][next][first][last][top][bottom][index][help] */
 117 {
 118         int i;
 119         int unit = 0;
 120         char *name;
 121         long flags;
 122 
 123         if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
 124                 return 0;
 125 
 126         save_flags(flags);
 127         cli();
 128 
 129         /* 
 130          * search a free device 
 131          */
 132         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 133                 if (ippp_table[i]->state == IPPP_OPEN) {                /* OPEN, but not connected! */
 134 #if 0
 135                         printk(KERN_DEBUG "find_minor, %d lp: %08lx\n", i, (long) lp);
 136 #endif
 137                         break;
 138                 }
 139         }
 140 
 141         if (i >= ISDN_MAX_CHANNELS) {
 142                 restore_flags(flags);
 143                 printk(KERN_WARNING "isdn_ppp_bind: Can't find usable ippp device.\n");
 144                 return -1;
 145         }
 146         lp->ppp_minor = i;
 147         ippp_table[lp->ppp_minor]->lp = lp;
 148 
 149         name = lp->name;
 150         unit = isdn_ppp_if_get_unit(&name); /* get unit number from interface name .. ugly! */
 151         ippp_table[lp->ppp_minor]->unit = unit;
 152 
 153         ippp_table[lp->ppp_minor]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
 154 
 155         restore_flags(flags);
 156 
 157         /*
 158          * kick the ipppd on the new device 
 159          */
 160         if (ippp_table[lp->ppp_minor]->wq)
 161                 wake_up_interruptible(&ippp_table[lp->ppp_minor]->wq);
 162 
 163         return lp->ppp_minor;
 164 }
 165 
 166 static int isdn_ppp_hangup(int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168         if (minor < 0 || minor >= ISDN_MAX_CHANNELS)
 169                 return 0;
 170 
 171         if (ippp_table[minor]->state && ippp_table[minor]->wq)
 172                 wake_up_interruptible(&ippp_table[minor]->wq);
 173 
 174         ippp_table[minor]->state = IPPP_CLOSEWAIT;
 175         return 1;
 176 }
 177 
 178 /*
 179  * isdn_ppp_open 
 180  */
 181 
 182 int isdn_ppp_open(int minor, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184 #if 0
 185         printk(KERN_DEBUG "ippp, open, minor: %d state: %04x\n", minor,ippp_table[minor]->state);
 186 #endif
 187         if (ippp_table[minor]->state)
 188                 return -EBUSY;
 189 
 190         ippp_table[minor]->lp = 0;
 191         ippp_table[minor]->mp_seqno = 0;  /* MP sequence number */
 192         ippp_table[minor]->pppcfg = 0;    /* ppp configuration */
 193         ippp_table[minor]->mpppcfg = 0;   /* mppp configuration */
 194         ippp_table[minor]->range = 0x1000000;   /* MP: 24 bit range */
 195         ippp_table[minor]->last_link_seqno = -1;        /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
 196         ippp_table[minor]->unit = -1;   /* set, when we have our interface */
 197         ippp_table[minor]->mru = 1524;  /* MRU, default 1524 */
 198         ippp_table[minor]->maxcid = 16; /* VJ: maxcid */
 199         ippp_table[minor]->tk = current;
 200         ippp_table[minor]->wq = NULL;    /* read() wait queue */
 201         ippp_table[minor]->wq1 = NULL;   /* select() wait queue */
 202         ippp_table[minor]->first = ippp_table[minor]->rq + NUM_RCV_BUFFS - 1; /* receive queue */
 203         ippp_table[minor]->last = ippp_table[minor]->rq;
 204 #ifdef CONFIG_ISDN_PPP_VJ
 205         /*
 206          * VJ header compression init
 207          */
 208         ippp_table[minor]->cbuf = kmalloc(ippp_table[minor]->mru + PPP_HARD_HDR_LEN + 2, GFP_KERNEL);
 209 
 210         if (ippp_table[minor]->cbuf == NULL) {
 211                 printk(KERN_DEBUG "ippp: Can't allocate memory buffer for VJ compression.\n");
 212                 return -ENOMEM;
 213         }
 214         ippp_table[minor]->slcomp = slhc_init(16, 16);  /* not necessary for 2. link in bundle */
 215 #endif
 216 
 217         ippp_table[minor]->state = IPPP_OPEN;
 218 
 219         return 0;
 220 }
 221 
 222 void isdn_ppp_release(int minor, struct file *file)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224         int i;
 225 
 226         if (minor < 0 || minor >= ISDN_MAX_CHANNELS)
 227                 return;
 228 
 229 #if 0
 230         printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) ippp_table[minor]->lp);
 231 #endif
 232 
 233         if (ippp_table[minor]->lp) {    /* a lp address says: this link is still up */
 234                 isdn_net_dev *p = dev->netdev;
 235                 while(p) {      /* find interface for our lp; */
 236                         if(&p->local == ippp_table[minor]->lp)
 237                                 break;
 238                         p = p->next;
 239                 }
 240                 if(!p) {
 241                         printk(KERN_ERR "isdn_ppp_release: Can't find device for net_local\n");
 242                         p = ippp_table[minor]->lp->netdev;
 243                 }
 244                 ippp_table[minor]->lp->ppp_minor = -1;
 245                 isdn_net_hangup(&p->dev); /* lp->ppp_minor==-1 => no calling of isdn_ppp_hangup() */
 246                 ippp_table[minor]->lp = NULL;
 247         }
 248         for (i = 0; i < NUM_RCV_BUFFS; i++) {
 249                 if (ippp_table[minor]->rq[i].buf)
 250                         kfree(ippp_table[minor]->rq[i].buf);
 251         }
 252 
 253 #ifdef CONFIG_ISDN_PPP_VJ
 254         slhc_free(ippp_table[minor]->slcomp);
 255         kfree(ippp_table[minor]->cbuf);
 256 #endif
 257 
 258         ippp_table[minor]->state = 0;
 259 }
 260 
 261 static int get_arg(void *b, unsigned long *val)
     /* [previous][next][first][last][top][bottom][index][help] */
 262 {
 263         int r;
 264         if ((r = verify_area(VERIFY_READ, (void *) b, sizeof(unsigned long))))
 265                  return r;
 266         memcpy_fromfs((void *) val, b, sizeof(unsigned long));
 267         return 0;
 268 }
 269 
 270 static int set_arg(void *b, unsigned long val)
     /* [previous][next][first][last][top][bottom][index][help] */
 271 {
 272         int r;
 273         if ((r = verify_area(VERIFY_WRITE, b, sizeof(unsigned long))))
 274                  return r;
 275         memcpy_tofs(b, (void *) &val, sizeof(unsigned long));
 276         return 0;
 277 }
 278 
 279 int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 280 {
 281         unsigned long val;
 282         int r;
 283 
 284 #if 0
 285         printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x",minor,cmd);
 286         printk(KERN_DEBUG " state: %x\n",ippp_table[minor]->state);
 287 #endif
 288 
 289         if (!(ippp_table[minor]->state & IPPP_OPEN))
 290                 return -EINVAL;
 291 
 292         switch (cmd) {
 293 #if 0
 294         case PPPIOCSINPSIG:     /* obsolete: set input ready signal */
 295                 /* usual: sig = SIGIO *//* we always deliver a SIGIO */
 296                 break;
 297 #endif
 298         case PPPIOCBUNDLE:
 299 #ifdef CONFIG_ISDN_MPP
 300                 if ((r = get_arg((void *) arg, &val)))
 301                         return r;
 302                 printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
 303                         (int) minor, (int) ippp_table[minor]->unit, (int) val);
 304                 return isdn_ppp_bundle(minor, val);
 305 #else
 306                 return -1;
 307 #endif
 308                 break;
 309         case PPPIOCGUNIT:       /* get ppp/isdn unit number */
 310                 if ((r = set_arg((void *) arg, ippp_table[minor]->unit)))
 311                         return r;
 312                 break;
 313         case PPPIOCGMPFLAGS:    /* get configuration flags */
 314                 if ((r = set_arg((void *) arg, ippp_table[minor]->mpppcfg)))
 315                         return r;
 316                 break;
 317         case PPPIOCSMPFLAGS:    /* set configuration flags */
 318                 if ((r = get_arg((void *) arg, &val)))
 319                         return r;
 320                 ippp_table[minor]->mpppcfg = val;
 321                 break;
 322         case PPPIOCGFLAGS:      /* get configuration flags */
 323                 if ((r = set_arg((void *) arg, ippp_table[minor]->pppcfg)))
 324                         return r;
 325                 break;
 326         case PPPIOCSFLAGS:      /* set configuration flags */
 327                 if ((r = get_arg((void *) arg, &val))) {
 328                         return r;
 329                 }
 330                 if (val & SC_ENABLE_IP && !(ippp_table[minor]->pppcfg & SC_ENABLE_IP)) {
 331                         ippp_table[minor]->lp->netdev->dev.tbusy = 0;
 332                         mark_bh(NET_BH); /* OK .. we are ready to send the first buffer */
 333                 }
 334                 ippp_table[minor]->pppcfg = val;
 335                 break;
 336 #if 0
 337         case PPPIOCGSTAT:       /* read PPP statistic information */
 338                 break;
 339         case PPPIOCGTIME:       /* read time delta information */
 340                 break;
 341 #endif
 342         case PPPIOCSMRU:        /* set receive unit size for PPP */
 343                 if ((r = get_arg((void *) arg, &val)))
 344                         return r;
 345                 ippp_table[minor]->mru = val;
 346                 break;
 347         case PPPIOCSMPMRU:
 348                 break;
 349         case PPPIOCSMPMTU:
 350                 break;
 351         case PPPIOCSMAXCID:     /* set the maximum compression slot id */
 352                 if ((r = get_arg((void *) arg, &val)))
 353                         return r;
 354                 ippp_table[minor]->maxcid = val;
 355                 break;
 356         case PPPIOCGDEBUG:
 357                 break;
 358         case PPPIOCSDEBUG:
 359                 break;
 360         default:
 361                 break;
 362         }
 363         return 0;
 364 }
 365 
 366 int isdn_ppp_select(int minor, struct file *file, int type, select_table * st)
     /* [previous][next][first][last][top][bottom][index][help] */
 367 {
 368         struct ippp_buf_queue *bf, *bl;
 369         unsigned long flags;
 370 
 371 #if 0
 372         printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",minor,type);
 373 #endif
 374 
 375         if (!(ippp_table[minor]->state & IPPP_OPEN))
 376                 return -EINVAL;
 377 
 378         switch (type) {
 379         case SEL_IN:
 380                 save_flags(flags);
 381                 cli();
 382                 bl = ippp_table[minor]->last;
 383                 bf = ippp_table[minor]->first;
 384                 if (bf->next == bl && !(ippp_table[minor]->state & IPPP_NOBLOCK)) {
 385                         select_wait(&ippp_table[minor]->wq, st);
 386                         restore_flags(flags);
 387                         return 0;
 388                 }
 389                 ippp_table[minor]->state &= ~IPPP_NOBLOCK;
 390                 restore_flags(flags);
 391                 return 1;
 392         case SEL_OUT:
 393                 /* we're always ready to send .. */
 394                 return 1;
 395         case SEL_EX:
 396                 select_wait(&ippp_table[minor]->wq1, st);
 397                 return 0;
 398         }
 399         return 1;
 400 }
 401 
 402 /*
 403  *  fill up isdn_ppp_read() queue ..
 404  */
 405 
 406 static int isdn_ppp_fill_rq(char *buf, int len, int minor)
     /* [previous][next][first][last][top][bottom][index][help] */
 407 {
 408         struct ippp_buf_queue *bf, *bl;
 409         unsigned long flags;
 410 
 411         if (minor < 0 || minor >= ISDN_MAX_CHANNELS) {
 412                 printk(KERN_WARNING "ippp: illegal minor.\n");
 413                 return 0;
 414         }
 415         if (!(ippp_table[minor]->state & IPPP_CONNECT)) {
 416                 printk(KERN_DEBUG "ippp: device not activated.\n");
 417                 return 0;
 418         }
 419         save_flags(flags);
 420         cli();
 421 
 422         bf = ippp_table[minor]->first;
 423         bl = ippp_table[minor]->last;
 424 
 425         if (bf == bl) {
 426                 printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
 427                 bf = bf->next;
 428                 kfree(bf->buf);
 429                 ippp_table[minor]->first = bf;
 430         }
 431         bl->buf = (char *) kmalloc(len, GFP_ATOMIC);
 432         if (!bl->buf) {
 433                 printk(KERN_WARNING "ippp: Can't alloc buf\n");
 434                 restore_flags(flags);
 435                 return 0;
 436         }
 437         bl->len = len;
 438 
 439         memcpy(bl->buf, buf, len);
 440 
 441         ippp_table[minor]->last = bl->next;
 442         restore_flags(flags);
 443 
 444         if (ippp_table[minor]->wq)
 445                 wake_up_interruptible(&ippp_table[minor]->wq);
 446 
 447         return len;
 448 }
 449 
 450 /*
 451  * read() .. non-blocking: ipppd calls it only after select()
 452  *           reports, that there is data
 453  */
 454 
 455 int isdn_ppp_read(int minor, struct file *file, char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 456 {
 457         struct ippp_struct *c = ippp_table[minor];
 458         struct ippp_buf_queue *b;
 459         int r;
 460         unsigned long flags;
 461 
 462         if (!(ippp_table[minor]->state & IPPP_OPEN))
 463                 return 0;
 464 
 465         if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
 466                 return r;
 467 
 468         save_flags(flags);
 469         cli();
 470 
 471         b = c->first->next;
 472         if (!b->buf) {
 473                 restore_flags(flags);
 474                 return -EAGAIN;
 475         }
 476         if (b->len < count)
 477                 count = b->len;
 478         memcpy_tofs(buf, b->buf, count);
 479         kfree(b->buf);
 480         b->buf = NULL;
 481         c->first = b;
 482         restore_flags(flags);
 483 
 484         return count;
 485 }
 486 
 487 /*
 488  * ipppd wanna write a packet to the card .. non-blocking
 489  */
 490  
 491 int isdn_ppp_write(int minor, struct file *file,  const char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 492 {
 493         isdn_net_local *lp;
 494 
 495         if (!(ippp_table[minor]->state & IPPP_CONNECT))
 496                 return 0;
 497 
 498         lp = ippp_table[minor]->lp;
 499 
 500         /* -> push it directly to the lowlevel interface */
 501 
 502         if (!lp)
 503                 printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
 504         else {
 505                 if (lp->isdn_device < 0 || lp->isdn_channel < 0)
 506                         return 0;
 507 
 508                 if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 &&
 509                     (lp->flags & ISDN_NET_CONNECTED))
 510                         isdn_writebuf_stub(lp->isdn_device,lp->isdn_channel,
 511                                            buf, count, 1);
 512         }
 513 
 514         return count;
 515 }
 516 
 517 /*
 518  * init memory, structures etc. 
 519  */
 520 
 521 int isdn_ppp_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 522 {
 523         int i, j;
 524 
 525         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 526                 if (!(ippp_table[i] = (struct ippp_struct *)
 527                         kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
 528                         printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
 529                         for (j = 0; j < i; j++)
 530                           kfree(ippp_table[i]);
 531                         return -1;
 532                 }
 533                 memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
 534                 ippp_table[i]->state = 0;
 535                 ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
 536                 ippp_table[i]->last = ippp_table[i]->rq;
 537 
 538                 for (j = 0; j < NUM_RCV_BUFFS; j++) {
 539                         ippp_table[i]->rq[j].buf = NULL;
 540                         ippp_table[i]->rq[j].last = ippp_table[i]->rq +
 541                             (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
 542                         ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
 543                 }
 544         }
 545         return 0;
 546 }
 547 
 548 void isdn_ppp_cleanup(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 549 {
 550         int i;
 551 
 552         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
 553                 kfree(ippp_table[i]);
 554 }
 555 
 556 /*
 557  * handler for incoming packets on a syncPPP interface
 558  */
 559 
 560 void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 561 {
 562 #if 0
 563         printk(KERN_DEBUG "recv, skb %d\n",skb->len);
 564 #endif
 565 
 566         if(skb->data[0] == 0xff && skb->data[1] == 0x03)
 567                 skb_pull(skb,2);
 568         else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC)
 569                 return;         /* discard it silently */
 570 
 571 #ifdef CONFIG_ISDN_MPP
 572         if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_REJ_MP_PROT)) {
 573                 int proto;
 574                 int sqno_end;
 575                 if (skb->data[0] & 0x1) {
 576                         proto = skb->data[0];
 577                         skb_pull(skb,1);        /* protocol ID is only 8 bit */
 578                 } else {
 579                         proto = ((int) skb->data[0] << 8) + skb->data[1];
 580                         skb_pull(skb,2);
 581                 }
 582                 if (proto == PPP_MP) {
 583                         isdn_net_local *lpq;
 584                         int sqno, min_sqno, tseq;
 585                         u_char BEbyte = skb->data[0];
 586 #if 0
 587                         printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_minor, proto ,
 588                                 (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], 
 589                                 (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
 590 #endif
 591                         if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_IN_SHORT_SEQ)) {
 592                                 sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3];
 593                                 skb_pull(skb,4);
 594                         } else {
 595                                 sqno = (((int) skb->data[0] & 0xf) << 8) + (int) skb->data[1];
 596                                 skb_pull(skb,2);
 597                         }
 598 
 599                         if ((tseq = ippp_table[lp->ppp_minor]->last_link_seqno) >= sqno) {
 600                                 int range = ippp_table[lp->ppp_minor]->range;
 601                                 if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
 602                                         printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %d, last: %d !!!\n", sqno, tseq);
 603                                 else {
 604                                         sqno += range;
 605                                         ippp_table[lp->ppp_minor]->last_link_seqno = sqno;
 606                                 }
 607                         } else
 608                                 ippp_table[lp->ppp_minor]->last_link_seqno = sqno;
 609 
 610                         for (min_sqno = 0, lpq = net_dev->queue;;) {
 611                                 if (ippp_table[lpq->ppp_minor]->last_link_seqno > min_sqno)
 612                                         min_sqno = ippp_table[lpq->ppp_minor]->last_link_seqno;
 613                                 lpq = lpq->next;
 614                                 if (lpq == net_dev->queue)
 615                                         break;
 616                         }
 617                         if (min_sqno >= ippp_table[lpq->ppp_minor]->range) {    /* OK, every link overflowed */
 618                                 int mask = ippp_table[lpq->ppp_minor]->range - 1;       /* range is a power of 2 */
 619                                 isdn_ppp_cleanup_queue(net_dev, min_sqno);
 620                                 isdn_ppp_mask_queue(net_dev, mask);
 621                                 net_dev->ib.next_num &= mask;
 622                                 {
 623                                         struct sqqueue *q = net_dev->ib.sq;
 624                                         while (q) {
 625                                                 q->sqno_start &= mask;
 626                                                 q->sqno_end &= mask;
 627                                         }
 628                                 }
 629                                 min_sqno &= mask;
 630                                 for (lpq = net_dev->queue;;) {
 631                                         ippp_table[lpq->ppp_minor]->last_link_seqno &= mask;
 632                                         lpq = lpq->next;
 633                                         if (lpq == net_dev->queue)
 634                                                 break;
 635                                 }
 636                         }
 637                         if ((BEbyte & (MP_BEGIN_FRAG | MP_END_FRAG)) != (MP_BEGIN_FRAG | MP_END_FRAG)) {
 638                                 printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_minor);
 639                                 if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb , BEbyte, &sqno, min_sqno)) < 0)
 640                                         return;         /* no packet complete */
 641                         } else
 642                                 sqno_end = sqno;
 643 
 644                         /*
 645                          * MP buffer management .. reorders incoming packets ..
 646                          * lotsa mem-copies and not heavily tested.
 647                          *
 648                          * first check whether there is more than one link in the bundle
 649                          * then check whether the number is in order
 650                          */
 651                         net_dev->ib.modify = 1;         /* block timeout-timer */
 652                         if (net_dev->ib.bundled && net_dev->ib.next_num != sqno) {
 653                                 /*
 654                                  * packet is not 'in order'
 655                                  */
 656                                 struct sqqueue *q;
 657 
 658                                 q = (struct sqqueue *) kmalloc(sizeof(struct sqqueue), GFP_ATOMIC);
 659                                 if (!q) {
 660                                         printk(KERN_WARNING "ippp: err, no memory !!\n");
 661                                         net_dev->ib.modify = 0;
 662                                         return;         /* discard */
 663                                 }
 664                                 q->skb = skb;
 665                                 q->sqno_end = sqno_end;
 666                                 q->sqno_start = sqno;
 667                                 q->timer = jiffies + (ISDN_TIMER_1SEC) * 5;     /* timeout after 5 seconds */
 668 
 669                                 if (!net_dev->ib.sq) {
 670                                         net_dev->ib.sq = q;
 671                                         q->next = NULL;
 672                                 } else {
 673                                         struct sqqueue *ql = net_dev->ib.sq;
 674                                         if (ql->sqno_start > q->sqno_start) {
 675                                                 q->next = ql;
 676                                                 net_dev->ib.sq = q;
 677                                         } else {
 678                                                 while (ql->next && ql->next->sqno_start < q->sqno_start)
 679                                                         ql = ql->next;
 680                                                 q->next = ql->next;
 681                                                 ql->next = q;
 682                                         }
 683                                 }
 684                                 net_dev->ib.modify = 0;
 685                                 return;
 686                         } else {
 687                                 /* 
 688                                  * packet was 'in order' .. push it higher
 689                                  */
 690                                 struct sqqueue *q;
 691 
 692                                 net_dev->ib.next_num = sqno_end + 1;
 693                                 isdn_ppp_push_higher(net_dev, lp, skb, -1);
 694 
 695                                 /*
 696                                  * check queue, whether we have still buffered the next packet(s)
 697                                  */
 698                                 while ((q = net_dev->ib.sq) && q->sqno_start == net_dev->ib.next_num) {
 699                                         isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
 700                                         net_dev->ib.sq = q->next;
 701                                         net_dev->ib.next_num = q->sqno_end + 1;
 702                                         kfree(q);
 703                                 }
 704                         }
 705                         net_dev->ib.modify = 0;
 706 
 707                 } else
 708                         isdn_ppp_push_higher(net_dev, lp, skb , proto);
 709         } else
 710 #endif
 711                 isdn_ppp_push_higher(net_dev, lp, skb , -1);
 712 }
 713 
 714 
 715 static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb,int proto)
     /* [previous][next][first][last][top][bottom][index][help] */
 716 {
 717         struct device *dev = &net_dev->dev;
 718 
 719         if (proto < 0) {        /* MP, oder normales Paket bei REJ_MP, MP Pakete gehen bei REJ zum pppd */
 720                 if (skb->data[0] & 0x01) {      /* is it odd? */
 721                         proto = (unsigned char) skb->data[0];
 722                         skb_pull(skb,1);        /* protocol ID is only 8 bit */
 723                 } else {
 724                         proto = ((int) (unsigned char) skb->data[0] << 8) + (unsigned char) skb->data[1];
 725                         skb_pull(skb,2);
 726                 }
 727         }
 728 
 729 #if 0
 730         printk(KERN_DEBUG "push, skb %d %04x\n",skb->len,proto);
 731 #endif
 732 
 733         switch (proto) {
 734         case PPP_IPX: /* untested */
 735                 skb->dev = dev;
 736                 skb->mac.raw = skb->data;
 737                 skb->protocol = htons(ETH_P_IPX);
 738                 break;
 739 #ifdef CONFIG_ISDN_PPP_VJ
 740         case PPP_VJC_UNCOMP:
 741                 slhc_remember(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb->len);
 742 #endif
 743         case PPP_IP:
 744                 skb->dev = dev;
 745                 skb->mac.raw = skb->data;
 746                 skb->protocol = htons(ETH_P_IP);
 747                 break;
 748         case PPP_VJC_COMP:
 749 #ifdef CONFIG_ISDN_PPP_VJ
 750                 {
 751                         struct sk_buff *skb_old = skb;
 752                         int pkt_len;
 753                         skb = dev_alloc_skb(skb_old->len + 40);
 754 
 755                         if (!skb) {
 756                                 printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
 757                                 net_dev->local.stats.rx_dropped++;
 758                                 return;
 759                         }
 760                         skb->dev = dev;
 761                         skb_put(skb,skb_old->len + 40);
 762                         memcpy(skb->data, skb_old->data, skb_old->len);
 763                         skb->mac.raw = skb->data;
 764                         pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_minor]->slcomp,
 765                                                   skb->data, skb_old->len);
 766                         skb_trim(skb, pkt_len);
 767                         dev_kfree_skb(skb_old,FREE_WRITE);
 768                         skb->protocol = htons(ETH_P_IP);
 769                 }
 770 #else
 771                 printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
 772                 lp->stats.rx_dropped++;
 773                 return;
 774 #endif
 775                 break;
 776         default:
 777                 skb_push(skb,4);
 778                 skb->data[0] = 0xff;
 779                 skb->data[1] = 0x03;
 780                 skb->data[2] = (proto>>8);
 781                 skb->data[3] = proto & 0xff;
 782                 isdn_ppp_fill_rq(skb->data, skb->len, lp->ppp_minor);   /* push data to pppd device */
 783                 dev_kfree_skb(skb,FREE_WRITE);
 784                 return;
 785         }
 786 
 787         netif_rx(skb);
 788         net_dev->local.stats.rx_packets++;
 789         /* Reset hangup-timer */
 790         lp->huptimer = 0;
 791 
 792         return;
 793 }
 794 
 795 /*
 796  * send ppp frame .. we expect a PIDCOMPable proto -- 
 797  *  (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
 798  */
 799 int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 800 {
 801         isdn_net_dev *nd = ((isdn_net_local *) dev->priv)->netdev;
 802         isdn_net_local *lp = nd->queue;
 803         int proto = PPP_IP;     /* 0x21 */
 804         struct ippp_struct *ipt = ippp_table[lp->ppp_minor];
 805 #if defined(CONFIG_ISDN_PPP_VJ) || defined(CONFIG_ISDN_MPP)
 806         struct ippp_struct *ipts = ippp_table[lp->netdev->local.ppp_minor];
 807 #endif
 808 
 809         /* If packet is to be resent, it has already been processed and
 810          * therefore its first bytes are already initialized. In this case
 811          * send it immediately ...
 812          */
 813         if (*((unsigned long *)skb->data) != 0)
 814           return (isdn_net_send_skb(dev , lp , skb));
 815 
 816         /* ... else packet needs processing. */
 817 
 818 /* future: step to next 'lp' when this lp is 'tbusy' */
 819 
 820 #if 0
 821         printk(KERN_DEBUG  "xmit, skb %d\n",skb->len);
 822 #endif
 823 
 824 #ifdef CONFIG_ISDN_PPP_VJ
 825         if (ipt->pppcfg & SC_COMP_TCP) {
 826                 u_char *buf = skb->data;
 827                 int pktlen;
 828                 int len = 4;
 829 #ifdef CONFIG_ISDN_MPP
 830                 if (ipt->mpppcfg & SC_MP_PROT) /* sigh */ 
 831                         if (ipt->mpppcfg & SC_OUT_SHORT_SEQ)
 832                                 len += 3;
 833                         else
 834                                 len += 5;
 835 #endif
 836                 buf += len;
 837                 pktlen = slhc_compress(ipts->slcomp, buf, skb->len-len, ipts->cbuf,
 838                                 &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
 839                 skb_trim(skb,pktlen+len);
 840                 if(buf != skb->data+len) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*)  */
 841                         memcpy(skb->data+len,buf,pktlen);
 842                 }
 843                 if (skb->data[len] & SL_TYPE_COMPRESSED_TCP) {  /* cslip? style -> PPP */
 844                         proto = PPP_VJC_COMP;
 845                         skb->data[len] ^= SL_TYPE_COMPRESSED_TCP;
 846                 } else {
 847                         if (skb->data[len] >= SL_TYPE_UNCOMPRESSED_TCP)
 848                                 proto = PPP_VJC_UNCOMP;
 849                         skb->data[len] = (skb->data[len] & 0x0f) | 0x40;
 850                 }
 851         }
 852 #endif
 853 
 854 #if 0
 855         printk(KERN_DEBUG  "xmit, skb %d %04x\n",skb->len,proto);
 856 #endif
 857 
 858 #ifdef CONFIG_ISDN_MPP
 859         if (ipt->mpppcfg & SC_MP_PROT) {
 860                 /* we get mp_seqno from static isdn_net_local */
 861                 long mp_seqno = ipts->mp_seqno;
 862                 ipts->mp_seqno++;
 863                 nd->queue = nd->queue->next;
 864                 if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
 865                         /* skb_push(skb, 3); Done in isdn_net_header() */
 866                         mp_seqno &= 0xfff;
 867                         skb->data[4] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8);   /* (B)egin & (E)ndbit .. */
 868                         skb->data[5] = mp_seqno & 0xff;
 869                         skb->data[6] = proto;   /* PID compression */
 870                 } else {
 871                         /* skb_push(skb, 5); Done in isdn_net_header () */
 872                         skb->data[4] = MP_BEGIN_FRAG | MP_END_FRAG;     /* (B)egin & (E)ndbit .. */
 873                         skb->data[5] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
 874                         skb->data[6] = (mp_seqno >> 8) & 0xff;
 875                         skb->data[7] = (mp_seqno >> 0) & 0xff;
 876                         skb->data[8] = proto;   /* PID compression */
 877                 }
 878                 proto = PPP_MP; /* MP Protocol, 0x003d */
 879         }
 880 #endif
 881         skb->data[0] = 0xff;        /* All Stations */
 882         skb->data[1] = 0x03;        /* Unnumbered information */
 883         skb->data[2] = proto >> 8;
 884         skb->data[3] = proto & 0xff;
 885 
 886         lp->huptimer = 0;
 887         if (!(ipt->pppcfg & SC_ENABLE_IP)) {    /* PPP connected ? */
 888                 printk(KERN_INFO "isdn, xmit: Packet blocked: %d %d\n", lp->isdn_device, lp->isdn_channel);
 889                 return 1;
 890         }
 891         /* tx-stats are now updated via BSENT-callback */
 892         return (isdn_net_send_skb(dev , lp , skb));
 893 }
 894 
 895 void isdn_ppp_free_mpqueue(isdn_net_dev * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 896 {
 897         struct mpqueue *ql, *q = p->mp_last;
 898         while (q) {
 899                 ql = q->next;
 900                 dev_kfree_skb(q->skb,FREE_WRITE);
 901                 kfree(q);
 902                 q = ql;
 903         }
 904 }
 905 
 906 #ifdef CONFIG_ISDN_MPP
 907 
 908 static int isdn_ppp_bundle(int minor, int unit)
     /* [previous][next][first][last][top][bottom][index][help] */
 909 {
 910         char ifn[IFNAMSIZ + 1];
 911         long flags;
 912         isdn_net_dev *p;
 913         isdn_net_local *lp,*nlp;
 914 
 915         sprintf(ifn, "ippp%d", unit);
 916         p = isdn_net_findif(ifn);
 917         if (!p)
 918                 return -1;
 919 
 920         isdn_timer_ctrl(ISDN_TIMER_IPPP, 1);    /* enable timer for ippp/MP */
 921 
 922         save_flags(flags);
 923         cli();
 924 
 925         nlp = ippp_table[minor]->lp;
 926 
 927         lp = p->queue;
 928         p->ib.bundled = 1;
 929         nlp->last = lp->last;
 930         lp->last->next = nlp;
 931         lp->last = nlp;
 932         nlp->next = lp;
 933         p->queue = nlp;
 934 
 935         nlp->netdev = lp->netdev;
 936 
 937         ippp_table[nlp->ppp_minor]->unit = ippp_table[lp->ppp_minor]->unit;
 938 /* maybe also SC_CCP stuff */
 939         ippp_table[nlp->ppp_minor]->pppcfg |= ippp_table[lp->ppp_minor]->pppcfg &
 940             (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
 941 
 942         ippp_table[nlp->ppp_minor]->mpppcfg |= ippp_table[lp->ppp_minor]->mpppcfg &
 943             (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
 944 #if 0
 945         if (ippp_table[nlp->ppp_minor]->mpppcfg != ippp_table[lp->ppp_minor]->mpppcfg) {
 946                 printk(KERN_WARNING "isdn_ppp_bundle: different MP options %04x and %04x\n",
 947                        ippp_table[nlp->ppp_minor]->mpppcfg, ippp_table[lp->ppp_minor]->mpppcfg);
 948         }
 949 #endif
 950 
 951         restore_flags(flags);
 952         return 0;
 953 }
 954 
 955 
 956 static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 957 {
 958         struct mpqueue *q = dev->mp_last;
 959         while (q) {
 960                 q->sqno &= mask;
 961                 q = q->next;
 962         }
 963 }
 964 
 965 
 966 static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int BEbyte, int *sqnop, int min_sqno)
     /* [previous][next][first][last][top][bottom][index][help] */
 967 {
 968         struct mpqueue *qe, *q1, *q;
 969         long cnt, flags;
 970         int pktlen, sqno_end;
 971         int sqno = *sqnop;
 972 
 973         q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_KERNEL);
 974         if (!q1) {
 975                 printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n");
 976                 save_flags(flags);
 977                 cli();
 978                 isdn_ppp_cleanup_queue(dev, min_sqno);
 979                 restore_flags(flags);
 980                 return -1;
 981         }
 982         q1->skb = *skb;
 983         q1->sqno = sqno;
 984         q1->BEbyte = BEbyte;
 985         q1->time = jiffies;
 986 
 987         save_flags(flags);
 988         cli();
 989 
 990         if (!(q = dev->mp_last)) {
 991                 dev->mp_last = q1;
 992                 q1->next = NULL;
 993                 q1->last = NULL;
 994                 isdn_ppp_cleanup_queue(dev, min_sqno);  /* not necessary */
 995                 restore_flags(flags);
 996                 return -1;
 997         }
 998         for (;;) {              /* the faster way would be to step from the queue-end to the start */
 999                 if (sqno > q->sqno) {
1000                         if (q->next) {
1001                                 q = q->next;
1002                                 continue;
1003                         }
1004                         q->next = q1;
1005                         q1->next = NULL;
1006                         q1->last = q;
1007                         break;
1008                 }
1009                 if (sqno == q->sqno)
1010                         printk(KERN_WARNING "isdn_fill_mpqueue: illegal sqno received!!\n");
1011                 q1->last = q->last;
1012                 q1->next = q;
1013                 if (q->last) {
1014                         q->last->next = q1;
1015                 } else
1016                         dev->mp_last = q1;
1017                 q->last = q1;
1018                 break;
1019         }
1020 
1021 /* now we check whether we completed a packet with this fragment */
1022         pktlen = -q1->skb->len;
1023         q = q1;
1024         cnt = q1->sqno;
1025         while (!(q->BEbyte & MP_END_FRAG)) {
1026                 cnt++;
1027                 if (!(q->next) || q->next->sqno != cnt) {
1028                         isdn_ppp_cleanup_queue(dev, min_sqno);
1029                         restore_flags(flags);
1030                         return -1;
1031                 }
1032                 pktlen += q->skb->len;
1033                 q = q->next;
1034         }
1035         pktlen += q->skb->len;
1036         qe = q;
1037 
1038         q = q1;
1039         cnt = q1->sqno;
1040         while (!(q->BEbyte & MP_BEGIN_FRAG)) {
1041                 cnt--;
1042                 if (!(q->last) || q->last->sqno != cnt) {
1043                         isdn_ppp_cleanup_queue(dev, min_sqno);
1044                         restore_flags(flags);
1045                         return -1;
1046                 }
1047                 pktlen += q->skb->len;
1048                 q = q->last;
1049         }
1050         pktlen += q->skb->len;
1051 
1052         if (q->last)
1053                 q->last->next = qe->next;
1054         else
1055                 dev->mp_last = qe->next;
1056 
1057         if (qe->next)
1058                 qe->next->last = q->last;
1059         qe->next = NULL;
1060         sqno_end = qe->sqno;
1061         *sqnop = q->sqno;
1062 
1063         isdn_ppp_cleanup_queue(dev, min_sqno);
1064         restore_flags(flags);
1065 
1066         *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
1067 
1068         if (!(*skb)) {
1069                 while (q) {
1070                         struct mpqueue *ql = q->next;
1071                         dev_kfree_skb(q->skb,FREE_WRITE);
1072                         kfree(q);
1073                         q = ql;
1074                 }
1075                 return -2;
1076         }
1077         cnt = 0;
1078         skb_put(*skb,pktlen);
1079         while (q) {
1080                 struct mpqueue *ql = q->next;
1081                 memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
1082                 cnt += q->skb->len;
1083                 dev_kfree_skb(q->skb,FREE_WRITE);
1084                 kfree(q);
1085                 q = ql;
1086         }
1087 
1088         return sqno_end;
1089 }
1090 
1091 /*
1092  * remove stale packets from list
1093  */
1094 
1095 static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min_sqno)
     /* [previous][next][first][last][top][bottom][index][help] */
1096 {
1097 /* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft:
1098    eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen
1099    wenn sqno<min_sqno und Luecken vorhanden sind: auch weg (die koennen nicht mehr gefuellt werden)
1100    bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete 
1101    groesser als mrru ist: raus damit , Pakete muessen allerdings zusammenhaengen sonst koennte
1102    ja ein Paket mit B und eins mit E dazwischenpassen */
1103 
1104         struct mpqueue *ql, *q = dev->mp_last;
1105         while (q) {
1106                 if (q->sqno < min_sqno) {
1107                         if (q->BEbyte & MP_END_FRAG) {
1108                                 printk(KERN_DEBUG "ippp: freeing stale packet!\n");
1109                                 if ((dev->mp_last = q->next))
1110                                         q->next->last = NULL;
1111                                 while (q) {
1112                                         ql = q->last;
1113                                         dev_kfree_skb(q->skb,FREE_WRITE);
1114                                         kfree(q);
1115                                         q = ql;
1116                                 }
1117                                 q = dev->mp_last;
1118                         } else
1119                                 q = q->next;
1120                 } else
1121                         break;
1122         }
1123 }
1124 
1125 /*
1126  * a buffered packet timed-out?
1127  */
1128 
1129 #endif
1130 
1131 void isdn_ppp_timer_timeout(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1132 {
1133 #ifdef CONFIG_ISDN_MPP
1134         isdn_net_dev *net_dev = dev->netdev;
1135         struct sqqueue *q, *ql = NULL, *qn;
1136 
1137         while (net_dev) {
1138                 isdn_net_local *lp = &net_dev->local;
1139                 if (net_dev->ib.modify) {       /* interface locked? */
1140                         net_dev = net_dev->next;
1141                         continue;
1142                 }
1143 
1144                 q = net_dev->ib.sq;
1145                 while (q) {
1146                         if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) {
1147                                 ql = net_dev->ib.sq;
1148                                 net_dev->ib.sq = q->next;
1149                                 net_dev->ib.next_num = q->sqno_end + 1;
1150                                 q->next = NULL;
1151                                 for (; ql;) {
1152                                         isdn_ppp_push_higher(net_dev, lp, ql->skb, -1);
1153                                         qn = ql->next;
1154                                         kfree(ql);
1155                                         ql = qn;
1156                                 }
1157                                 q = net_dev->ib.sq;
1158                         } else
1159                                 q = q->next;
1160                 }
1161                 net_dev = net_dev->next;
1162         }
1163 #endif
1164 }
1165 
1166 int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
1167 {
1168         int error;
1169         char *r;
1170         int len;
1171         isdn_net_local *lp = (isdn_net_local *) dev->priv;
1172 
1173         if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
1174                 return -EINVAL;
1175 
1176         switch (cmd) {
1177         case SIOCGPPPVER:
1178                 r = (char *) ifr->ifr_ifru.ifru_data;
1179                 len = strlen(PPP_VERSION) + 1;
1180                 error = verify_area(VERIFY_WRITE, r, len);
1181                 if (!error)
1182                         memcpy_tofs(r, PPP_VERSION, len);
1183                 break;
1184         default:
1185                 error = -EINVAL;
1186         }
1187         return error;
1188 }
1189 
1190 static int isdn_ppp_if_get_unit(char **namebuf)
     /* [previous][next][first][last][top][bottom][index][help] */
1191 {
1192         char *name = *namebuf;
1193         int len, i, unit = 0, deci;
1194 
1195         len = strlen(name);
1196         for (i = 0, deci = 1; i < len; i++, deci *= 10) {
1197                 if (name[len - 1 - i] >= '0' && name[len - 1 - i] <= '9')
1198                         unit += (name[len - 1 - i] - '0') * deci;
1199                 else
1200                         break;
1201         }
1202         if (!i)
1203                 unit = -1;
1204 
1205         *namebuf = name + len - 1 - i;
1206         return unit;
1207 
1208 }
1209 
1210 
1211 int isdn_ppp_dial_slave(char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
1212 {
1213 #ifdef CONFIG_ISDN_MPP
1214         isdn_net_dev *ndev;
1215         isdn_net_local *lp;
1216         struct device *sdev;
1217 
1218         if(!(ndev = isdn_net_findif(name)))
1219                 return 1;
1220         lp = &ndev->local;
1221         if(!(lp->flags & ISDN_NET_CONNECTED))
1222                 return 5;
1223 
1224         sdev = lp->slave;
1225         while(sdev)
1226         {
1227                 isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
1228                 if(!(mlp->flags & ISDN_NET_CONNECTED))
1229                         break;
1230                 sdev = mlp->slave;
1231         }
1232         if(!sdev)
1233                 return 2;
1234 
1235         isdn_net_force_dial_lp((isdn_net_local *) sdev->priv);
1236         return 0;
1237 #else
1238         return -1;
1239 #endif
1240 }
1241 
1242 

/* [previous][next][first][last][top][bottom][index][help] */