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         struct ippp_struct *ipts = ippp_table[lp->netdev->local.ppp_minor];
 806 
 807         /* If packet is to be resent, it has already been processed and
 808          * therefore it's first bytes are already initialized. In this case
 809          * send it immediately ...
 810          */
 811         if (*((unsigned long *)skb->data) != 0)
 812           return (isdn_net_send_skb(dev , lp , skb));
 813 
 814         /* ... else packet needs processing. */
 815 
 816 /* future: step to next 'lp' when this lp is 'tbusy' */
 817 
 818 #if 0
 819         printk(KERN_DEBUG  "xmit, skb %d\n",skb->len);
 820 #endif
 821 
 822 #ifdef CONFIG_ISDN_PPP_VJ
 823         if (ipt->pppcfg & SC_COMP_TCP) {
 824                 u_char *buf = skb->data;
 825                 int pktlen;
 826                 int len = 4;
 827 #ifdef CONFIG_ISDN_MPP
 828                 if (ipt->mpppcfg & SC_MP_PROT) /* sigh */ 
 829                         if (ipt->mpppcfg & SC_OUT_SHORT_SEQ)
 830                                 len += 3;
 831                         else
 832                                 len += 5;
 833 #endif
 834                 buf += len;
 835                 pktlen = slhc_compress(ipts->slcomp, buf, skb->len-len, ipts->cbuf,
 836                                 &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
 837                 skb_trim(skb,pktlen+len);
 838                 if(buf != skb->data+len) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*)  */
 839                         memcpy(skb->data+len,buf,pktlen);
 840                 }
 841                 if (skb->data[len] & SL_TYPE_COMPRESSED_TCP) {  /* cslip? style -> PPP */
 842                         proto = PPP_VJC_COMP;
 843                         skb->data[len] ^= SL_TYPE_COMPRESSED_TCP;
 844                 } else {
 845                         if (skb->data[len] >= SL_TYPE_UNCOMPRESSED_TCP)
 846                                 proto = PPP_VJC_UNCOMP;
 847                         skb->data[len] = (skb->data[len] & 0x0f) | 0x40;
 848                 }
 849         }
 850 #endif
 851 
 852 #if 0
 853         printk(KERN_DEBUG  "xmit, skb %d %04x\n",skb->len,proto);
 854 #endif
 855 
 856 #ifdef CONFIG_ISDN_MPP
 857         if (ipt->mpppcfg & SC_MP_PROT) {
 858                 /* we get mp_seqno from static isdn_net_local */
 859                 long mp_seqno = ipts->mp_seqno;
 860                 ipts->mp_seqno++;
 861                 nd->queue = nd->queue->next;
 862                 if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
 863                         /* skb_push(skb, 3); Done in isdn_net_header() */
 864                         mp_seqno &= 0xfff;
 865                         skb->data[4] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8);   /* (B)egin & (E)ndbit .. */
 866                         skb->data[5] = mp_seqno & 0xff;
 867                         skb->data[6] = proto;   /* PID compression */
 868                 } else {
 869                         /* skb_push(skb, 5); Done in isdn_net_header () */
 870                         skb->data[4] = MP_BEGIN_FRAG | MP_END_FRAG;     /* (B)egin & (E)ndbit .. */
 871                         skb->data[5] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
 872                         skb->data[6] = (mp_seqno >> 8) & 0xff;
 873                         skb->data[7] = (mp_seqno >> 0) & 0xff;
 874                         skb->data[8] = proto;   /* PID compression */
 875                 }
 876                 proto = PPP_MP; /* MP Protocol, 0x003d */
 877         }
 878 #endif
 879         skb->data[0] = 0xff;        /* All Stations */
 880         skb->data[1] = 0x03;        /* Unnumbered information */
 881         skb->data[2] = proto >> 8;
 882         skb->data[3] = proto & 0xff;
 883 
 884         lp->huptimer = 0;
 885         if (!(ipt->pppcfg & SC_ENABLE_IP)) {    /* PPP connected ? */
 886                 printk(KERN_INFO "isdn, xmit: Packet blocked: %d %d\n", lp->isdn_device, lp->isdn_channel);
 887                 return 1;
 888         }
 889         /* tx-stats are now updated via BSENT-callback */
 890         return (isdn_net_send_skb(dev , lp , skb));
 891 }
 892 
 893 void isdn_ppp_free_mpqueue(isdn_net_dev * p)
     /* [previous][next][first][last][top][bottom][index][help] */
 894 {
 895         struct mpqueue *ql, *q = p->mp_last;
 896         while (q) {
 897                 ql = q->next;
 898                 dev_kfree_skb(q->skb,FREE_WRITE);
 899                 kfree(q);
 900                 q = ql;
 901         }
 902 }
 903 
 904 #ifdef CONFIG_ISDN_MPP
 905 
 906 static int isdn_ppp_bundle(int minor, int unit)
     /* [previous][next][first][last][top][bottom][index][help] */
 907 {
 908         char ifn[IFNAMSIZ + 1];
 909         long flags;
 910         isdn_net_dev *p;
 911         isdn_net_local *lp,*nlp;
 912 
 913         sprintf(ifn, "ippp%d", unit);
 914         p = isdn_net_findif(ifn);
 915         if (!p)
 916                 return -1;
 917 
 918         isdn_timer_ctrl(ISDN_TIMER_IPPP, 1);    /* enable timer for ippp/MP */
 919 
 920         save_flags(flags);
 921         cli();
 922 
 923         nlp = ippp_table[minor]->lp;
 924 
 925         lp = p->queue;
 926         p->ib.bundled = 1;
 927         nlp->last = lp->last;
 928         lp->last->next = nlp;
 929         lp->last = nlp;
 930         nlp->next = lp;
 931         p->queue = nlp;
 932 
 933         nlp->netdev = lp->netdev;
 934 
 935         ippp_table[nlp->ppp_minor]->unit = ippp_table[lp->ppp_minor]->unit;
 936 /* maybe also SC_CCP stuff */
 937         ippp_table[nlp->ppp_minor]->pppcfg |= ippp_table[lp->ppp_minor]->pppcfg &
 938             (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
 939 
 940         ippp_table[nlp->ppp_minor]->mpppcfg |= ippp_table[lp->ppp_minor]->mpppcfg &
 941             (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
 942 #if 0
 943         if (ippp_table[nlp->ppp_minor]->mpppcfg != ippp_table[lp->ppp_minor]->mpppcfg) {
 944                 printk(KERN_WARNING "isdn_ppp_bundle: different MP options %04x and %04x\n",
 945                        ippp_table[nlp->ppp_minor]->mpppcfg, ippp_table[lp->ppp_minor]->mpppcfg);
 946         }
 947 #endif
 948 
 949         restore_flags(flags);
 950         return 0;
 951 }
 952 
 953 
 954 static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 955 {
 956         struct mpqueue *q = dev->mp_last;
 957         while (q) {
 958                 q->sqno &= mask;
 959                 q = q->next;
 960         }
 961 }
 962 
 963 
 964 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] */
 965 {
 966         struct mpqueue *qe, *q1, *q;
 967         long cnt, flags;
 968         int pktlen, sqno_end;
 969         int sqno = *sqnop;
 970 
 971         q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_KERNEL);
 972         if (!q1) {
 973                 printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n");
 974                 save_flags(flags);
 975                 cli();
 976                 isdn_ppp_cleanup_queue(dev, min_sqno);
 977                 restore_flags(flags);
 978                 return -1;
 979         }
 980         q1->skb = *skb;
 981         q1->sqno = sqno;
 982         q1->BEbyte = BEbyte;
 983         q1->time = jiffies;
 984 
 985         save_flags(flags);
 986         cli();
 987 
 988         if (!(q = dev->mp_last)) {
 989                 dev->mp_last = q1;
 990                 q1->next = NULL;
 991                 q1->last = NULL;
 992                 isdn_ppp_cleanup_queue(dev, min_sqno);  /* not necessary */
 993                 restore_flags(flags);
 994                 return -1;
 995         }
 996         for (;;) {              /* the faster way would be to step from the queue-end to the start */
 997                 if (sqno > q->sqno) {
 998                         if (q->next) {
 999                                 q = q->next;
1000                                 continue;
1001                         }
1002                         q->next = q1;
1003                         q1->next = NULL;
1004                         q1->last = q;
1005                         break;
1006                 }
1007                 if (sqno == q->sqno)
1008                         printk(KERN_WARNING "isdn_fill_mpqueue: illegal sqno received!!\n");
1009                 q1->last = q->last;
1010                 q1->next = q;
1011                 if (q->last) {
1012                         q->last->next = q1;
1013                 } else
1014                         dev->mp_last = q1;
1015                 q->last = q1;
1016                 break;
1017         }
1018 
1019 /* now we check whether we completed a packet with this fragment */
1020         pktlen = -q1->skb->len;
1021         q = q1;
1022         cnt = q1->sqno;
1023         while (!(q->BEbyte & MP_END_FRAG)) {
1024                 cnt++;
1025                 if (!(q->next) || q->next->sqno != cnt) {
1026                         isdn_ppp_cleanup_queue(dev, min_sqno);
1027                         restore_flags(flags);
1028                         return -1;
1029                 }
1030                 pktlen += q->skb->len;
1031                 q = q->next;
1032         }
1033         pktlen += q->skb->len;
1034         qe = q;
1035 
1036         q = q1;
1037         cnt = q1->sqno;
1038         while (!(q->BEbyte & MP_BEGIN_FRAG)) {
1039                 cnt--;
1040                 if (!(q->last) || q->last->sqno != cnt) {
1041                         isdn_ppp_cleanup_queue(dev, min_sqno);
1042                         restore_flags(flags);
1043                         return -1;
1044                 }
1045                 pktlen += q->skb->len;
1046                 q = q->last;
1047         }
1048         pktlen += q->skb->len;
1049 
1050         if (q->last)
1051                 q->last->next = qe->next;
1052         else
1053                 dev->mp_last = qe->next;
1054 
1055         if (qe->next)
1056                 qe->next->last = q->last;
1057         qe->next = NULL;
1058         sqno_end = qe->sqno;
1059         *sqnop = q->sqno;
1060 
1061         isdn_ppp_cleanup_queue(dev, min_sqno);
1062         restore_flags(flags);
1063 
1064         *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
1065 
1066         if (!(*skb)) {
1067                 while (q) {
1068                         struct mpqueue *ql = q->next;
1069                         dev_kfree_skb(q->skb,FREE_WRITE);
1070                         kfree(q);
1071                         q = ql;
1072                 }
1073                 return -2;
1074         }
1075         cnt = 0;
1076         skb_put(*skb,pktlen);
1077         while (q) {
1078                 struct mpqueue *ql = q->next;
1079                 memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
1080                 cnt += q->skb->len;
1081                 dev_kfree_skb(q->skb,FREE_WRITE);
1082                 kfree(q);
1083                 q = ql;
1084         }
1085 
1086         return sqno_end;
1087 }
1088 
1089 /*
1090  * remove stale packets from list
1091  */
1092 
1093 static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min_sqno)
     /* [previous][next][first][last][top][bottom][index][help] */
1094 {
1095 /* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft:
1096    eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen
1097    wenn sqno<min_sqno und Luecken vorhanden sind: auch weg (die koennen nicht mehr gefuellt werden)
1098    bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete 
1099    groesser als mrru ist: raus damit , Pakete muessen allerdings zusammenhaengen sonst koennte
1100    ja ein Paket mit B und eins mit E dazwischenpassen */
1101 
1102         struct mpqueue *ql, *q = dev->mp_last;
1103         while (q) {
1104                 if (q->sqno < min_sqno) {
1105                         if (q->BEbyte & MP_END_FRAG) {
1106                                 printk(KERN_DEBUG "ippp: freeing stale packet!\n");
1107                                 if ((dev->mp_last = q->next))
1108                                         q->next->last = NULL;
1109                                 while (q) {
1110                                         ql = q->last;
1111                                         dev_kfree_skb(q->skb,FREE_WRITE);
1112                                         kfree(q);
1113                                         q = ql;
1114                                 }
1115                                 q = dev->mp_last;
1116                         } else
1117                                 q = q->next;
1118                 } else
1119                         break;
1120         }
1121 }
1122 
1123 /*
1124  * a buffered packet timed-out?
1125  */
1126 
1127 #endif
1128 
1129 void isdn_ppp_timer_timeout(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1130 {
1131 #ifdef CONFIG_ISDN_MPP
1132         isdn_net_dev *net_dev = dev->netdev;
1133         struct sqqueue *q, *ql = NULL, *qn;
1134 
1135         while (net_dev) {
1136                 isdn_net_local *lp = &net_dev->local;
1137                 if (net_dev->ib.modify) {       /* interface locked? */
1138                         net_dev = net_dev->next;
1139                         continue;
1140                 }
1141 
1142                 q = net_dev->ib.sq;
1143                 while (q) {
1144                         if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) {
1145                                 ql = net_dev->ib.sq;
1146                                 net_dev->ib.sq = q->next;
1147                                 net_dev->ib.next_num = q->sqno_end + 1;
1148                                 q->next = NULL;
1149                                 for (; ql;) {
1150                                         isdn_ppp_push_higher(net_dev, lp, ql->skb, -1);
1151                                         qn = ql->next;
1152                                         kfree(ql);
1153                                         ql = qn;
1154                                 }
1155                                 q = net_dev->ib.sq;
1156                         } else
1157                                 q = q->next;
1158                 }
1159                 net_dev = net_dev->next;
1160         }
1161 #endif
1162 }
1163 
1164 int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
1165 {
1166         int error;
1167         char *r;
1168         int len;
1169         isdn_net_local *lp = (isdn_net_local *) dev->priv;
1170 
1171         if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
1172                 return -EINVAL;
1173 
1174         switch (cmd) {
1175         case SIOCGPPPVER:
1176                 r = (char *) ifr->ifr_ifru.ifru_data;
1177                 len = strlen(PPP_VERSION) + 1;
1178                 error = verify_area(VERIFY_WRITE, r, len);
1179                 if (!error)
1180                         memcpy_tofs(r, PPP_VERSION, len);
1181                 break;
1182         default:
1183                 error = -EINVAL;
1184         }
1185         return error;
1186 }
1187 
1188 static int isdn_ppp_if_get_unit(char **namebuf)
     /* [previous][next][first][last][top][bottom][index][help] */
1189 {
1190         char *name = *namebuf;
1191         int len, i, unit = 0, deci;
1192 
1193         len = strlen(name);
1194         for (i = 0, deci = 1; i < len; i++, deci *= 10) {
1195                 if (name[len - 1 - i] >= '0' && name[len - 1 - i] <= '9')
1196                         unit += (name[len - 1 - i] - '0') * deci;
1197                 else
1198                         break;
1199         }
1200         if (!i)
1201                 unit = -1;
1202 
1203         *namebuf = name + len - 1 - i;
1204         return unit;
1205 
1206 }
1207 
1208 
1209 int isdn_ppp_dial_slave(char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
1210 {
1211 #ifdef CONFIG_ISDN_MPP
1212         isdn_net_dev *ndev;
1213         isdn_net_local *lp;
1214         struct device *sdev;
1215 
1216         if(!(ndev = isdn_net_findif(name)))
1217                 return 1;
1218         lp = &ndev->local;
1219         if(!(lp->flags & ISDN_NET_CONNECTED))
1220                 return 5;
1221 
1222         sdev = lp->slave;
1223         while(sdev)
1224         {
1225                 isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
1226                 if(!(mlp->flags & ISDN_NET_CONNECTED))
1227                         break;
1228                 sdev = mlp->slave;
1229         }
1230         if(!sdev)
1231                 return 2;
1232 
1233         isdn_net_force_dial_lp((isdn_net_local *) sdev->priv);
1234         return 0;
1235 #else
1236         return -1;
1237 #endif
1238 }
1239 
1240 

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