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

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