]> git.ozlabs.org Git - ppp.git/blob - modules/ppp.c
updated
[ppp.git] / modules / ppp.c
1 /*
2  * ppp.c - STREAMS multiplexing pseudo-device driver for PPP.
3  *
4  * Copyright (c) 1994 The Australian National University.
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation is hereby granted, provided that the above copyright
9  * notice appears in all copies.  This software is provided without any
10  * warranty, express or implied. The Australian National University
11  * makes no representations about the suitability of this software for
12  * any purpose.
13  *
14  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
15  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
17  * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
18  * OF SUCH DAMAGE.
19  *
20  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
21  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
24  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
25  * OR MODIFICATIONS.
26  *
27  * $Id: ppp.c,v 1.3 1996/01/01 22:48:39 paulus Exp $
28  */
29
30 /*
31  * This file is used under Solaris 2, SVR4, and SunOS 4.
32  */
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/stat.h>
37 #include <sys/stream.h>
38 #include <sys/stropts.h>
39 #include <sys/errno.h>
40 #include <sys/ioccom.h>
41 #include <sys/time.h>
42 #ifdef SVR4
43 #include <sys/cmn_err.h>
44 #include <sys/conf.h>
45 #include <sys/dlpi.h>
46 #include <sys/ddi.h>
47 #ifdef SOL2
48 #include <sys/kstat.h>
49 #include <sys/sunddi.h>
50 #else
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <net/if.h>
54 #include <netinet/in.h>
55 #endif /* SOL2 */
56 #else /* not SVR4 */
57 #include <sys/user.h>
58 #endif /* SVR4 */
59 #include <net/ppp_defs.h>
60 #include <net/pppio.h>
61 #include "ppp_mod.h"
62
63 #ifdef __STDC__
64 #define __P(x)  x
65 #else
66 #define __P(x)  ()
67 #endif
68
69 /*
70  * The IP module may use this SAP value for IP packets.
71  */
72 #ifndef ETHERTYPE_IP
73 #define ETHERTYPE_IP    0x800
74 #endif
75
76 #ifndef PPP_MAXMTU
77 #define PPP_MAXMTU      65535
78 #endif
79
80 extern time_t time;
81
82 /*
83  * Private information; one per upper stream.
84  */
85 typedef struct upperstr {
86     minor_t mn;                 /* minor device number */
87     struct upperstr *nextmn;    /* next minor device */
88     queue_t *q;                 /* read q associated with this upper stream */
89     int flags;                  /* flag bits, see below */
90     int state;                  /* current DLPI state */
91     int sap;                    /* service access point */
92     int req_sap;                /* which SAP the DLPI client requested */
93     struct upperstr *ppa;       /* control stream for our ppa */
94     struct upperstr *next;      /* next stream for this ppa */
95     uint ioc_id;                /* last ioctl ID for this stream */
96     enum NPmode npmode;         /* what to do with packets on this SAP */
97     /*
98      * There is exactly one control stream for each PPA.
99      * The following fields are only used for control streams.
100      */
101     int ppa_id;
102     queue_t *lowerq;            /* write queue attached below this PPA */
103     struct upperstr *nextppa;   /* next control stream */
104     int mru;
105     int mtu;
106     struct pppstat stats;       /* statistics */
107     time_t last_sent;           /* time last NP packet sent */
108     time_t last_recv;           /* time last NP packet rcvd */
109 #ifdef SOL2
110     kstat_t *kstats;            /* stats for netstat */
111 #endif /* SOL2 */
112 #ifdef LACHTCP
113     int ifflags;
114     char ifname[IFNAMSIZ];
115     struct ifstats ifstats;
116 #endif /* LACHTCP */
117 } upperstr_t;
118
119 /* Values for flags */
120 #define US_PRIV         1       /* stream was opened by superuser */
121 #define US_CONTROL      2       /* stream is a control stream */
122 #define US_BLOCKED      4       /* flow ctrl has blocked lower write stream */
123 #define US_LASTMOD      8       /* no PPP modules below us */
124 #define US_DBGLOG       0x10    /* log various occurrences */
125
126 static upperstr_t *minor_devs = NULL;
127 static upperstr_t *ppas = NULL;
128
129 #ifdef SVR4
130 static int pppopen __P((queue_t *, dev_t *, int, int, cred_t *));
131 static int pppclose __P((queue_t *, int, cred_t *));
132 #else
133 static int pppopen __P((queue_t *, int, int, int));
134 static int pppclose __P((queue_t *, int));
135 #endif /* SVR4 */
136 static int pppuwput __P((queue_t *, mblk_t *));
137 static int pppursrv __P((queue_t *));
138 static int pppuwsrv __P((queue_t *));
139 static int ppplrput __P((queue_t *, mblk_t *));
140 static int ppplwput __P((queue_t *, mblk_t *));
141 static int ppplrsrv __P((queue_t *));
142 static int ppplwsrv __P((queue_t *));
143 #ifndef NO_DLPI
144 static void dlpi_request __P((queue_t *, mblk_t *, upperstr_t *));
145 static void dlpi_error __P((queue_t *, int, int, int));
146 static void dlpi_ok __P((queue_t *, int));
147 #endif
148 static int send_data __P((mblk_t *, upperstr_t *));
149 static void new_ppa __P((queue_t *, mblk_t *));
150 static void attach_ppa __P((queue_t *, mblk_t *));
151 static void detach_ppa __P((queue_t *, mblk_t *));
152 static void debug_dump __P((queue_t *, mblk_t *));
153 static upperstr_t *find_dest __P((upperstr_t *, int));
154 static int putctl2 __P((queue_t *, int, int, int));
155 static int putctl4 __P((queue_t *, int, int, int));
156
157 static struct module_info ppp_info = {
158     0xb1a6, "ppp", 0, 512, 512, 128
159 };
160
161 static struct qinit pppurint = {
162     NULL, pppursrv, pppopen, pppclose, NULL, &ppp_info, NULL
163 };
164
165 static struct qinit pppuwint = {
166     pppuwput, pppuwsrv, NULL, NULL, NULL, &ppp_info, NULL
167 };
168
169 static struct qinit ppplrint = {
170     ppplrput, ppplrsrv, NULL, NULL, NULL, &ppp_info, NULL
171 };
172
173 static struct qinit ppplwint = {
174     ppplwput, ppplwsrv, NULL, NULL, NULL, &ppp_info, NULL
175 };
176
177 #ifdef LACHTCP
178 extern struct ifstats *ifstats;
179 int pppdevflag = 0;
180 #endif
181
182 struct streamtab pppinfo = {
183     &pppurint, &pppuwint,
184     &ppplrint, &ppplwint
185 };
186
187 int ppp_count;
188
189 /*
190  * How we maintain statistics.
191  */
192 #ifdef SOL2
193 #define INCR_IPACKETS(ppa)                              \
194         if (ppa->kstats != 0) {                         \
195             KSTAT_NAMED_PTR(ppa->kstats)[0].value.ul++; \
196         }
197 #define INCR_IERRORS(ppa)                               \
198         if (ppa->kstats != 0) {                         \
199             KSTAT_NAMED_PTR(ppa->kstats)[1].value.ul++; \
200         }
201 #define INCR_OPACKETS(ppa)                              \
202         if (ppa->kstats != 0) {                         \
203             KSTAT_NAMED_PTR(ppa->kstats)[2].value.ul++; \
204         }
205 #define INCR_OERRORS(ppa)                               \
206         if (ppa->kstats != 0) {                         \
207             KSTAT_NAMED_PTR(ppa->kstats)[3].value.ul++; \
208         }
209 #endif
210
211 #ifdef LACHTCP
212 #define INCR_IPACKETS(ppa)      ppa->ifstats.ifs_ipackets++;
213 #define INCR_IERRORS(ppa)       ppa->ifstats.ifs_ierrors++;
214 #define INCR_OPACKETS(ppa)      ppa->ifstats.ifs_opackets++;
215 #define INCR_OERRORS(ppa)       ppa->ifstats.ifs_oerrors++;
216 #endif
217
218 /*
219  * STREAMS driver entry points.
220  */
221 static int
222 #ifdef SVR4
223 pppopen(q, devp, oflag, sflag, credp)
224     queue_t *q;
225     dev_t *devp;
226     int oflag, sflag;
227     cred_t *credp;
228 #else
229 pppopen(q, dev, oflag, sflag)
230     queue_t *q;
231     int dev;                    /* really dev_t */
232     int oflag, sflag;
233 #endif
234 {
235     upperstr_t *up;
236     upperstr_t **prevp;
237     minor_t mn;
238
239     if (q->q_ptr)
240         DRV_OPEN_OK(dev);       /* device is already open */
241
242     if (sflag == CLONEOPEN) {
243         mn = 0;
244         for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
245             if (up->mn != mn)
246                 break;
247             ++mn;
248         }
249     } else {
250 #ifdef SVR4
251         mn = getminor(*devp);
252 #else
253         mn = minor(dev);
254 #endif
255         for (prevp = &minor_devs; (up = *prevp) != 0; prevp = &up->nextmn) {
256             if (up->mn >= mn)
257                 break;
258         }
259         if (up->mn == mn) {
260             /* this can't happen */
261             q->q_ptr = WR(q)->q_ptr = (caddr_t) up;
262             DRV_OPEN_OK(dev);
263         }
264     }
265
266     /*
267      * Construct a new minor node.
268      */
269     up = (upperstr_t *) ALLOC_SLEEP(sizeof(upperstr_t));
270     bzero((caddr_t) up, sizeof(upperstr_t));
271     if (up == 0) {
272         DPRINT("pppopen: out of kernel memory\n");
273         OPEN_ERROR(ENXIO);
274     }
275     up->nextmn = *prevp;
276     *prevp = up;
277     up->mn = mn;
278 #ifdef SVR4
279     *devp = makedevice(getmajor(*devp), mn);
280 #endif
281     up->q = q;
282     if (NOTSUSER() == 0)
283         up->flags |= US_PRIV;
284 #ifndef NO_DLPI
285     up->state = DL_UNATTACHED;
286 #endif
287 #ifdef LACHTCP
288     up->ifflags = IFF_UP | IFF_POINTOPOINT;
289 #endif
290     up->sap = -1;
291     up->last_sent = up->last_recv = time;
292     up->npmode = NPMODE_DROP;
293     q->q_ptr = (caddr_t) up;
294     WR(q)->q_ptr = (caddr_t) up;
295     noenable(WR(q));
296     ++ppp_count;
297
298     qprocson(q);
299     DRV_OPEN_OK(makedev(major(dev), mn));
300 }
301
302 static int
303 #ifdef SVR4
304 pppclose(q, flag, credp)
305     queue_t *q;
306     int flag;
307     cred_t *credp;
308 #else
309 pppclose(q, flag)
310     queue_t *q;
311     int flag;
312 #endif
313 {
314     upperstr_t *up, **upp;
315     upperstr_t *as, *asnext;
316     upperstr_t **prevp;
317
318     qprocsoff(q);
319
320     up = (upperstr_t *) q->q_ptr;
321     if (up->flags & US_DBGLOG)
322         DPRINT2("ppp/%d: close, flags=%x\n", up->mn, up->flags);
323     if (up == 0)
324         return 0;
325     if (up->flags & US_CONTROL) {
326 #ifdef LACHTCP
327         struct ifstats *ifp, *pifp;
328 #endif
329         /*
330          * This stream represents a PPA:
331          * For all streams attached to the PPA, clear their
332          * references to this PPA.
333          * Then remove this PPA from the list of PPAs.
334          */
335         for (as = up->next; as != 0; as = asnext) {
336             asnext = as->next;
337             as->next = 0;
338             as->ppa = 0;
339             if (as->flags & US_BLOCKED) {
340                 as->flags &= ~US_BLOCKED;
341                 flushq(WR(as->q), FLUSHDATA);
342             }
343         }
344         for (upp = &ppas; *upp != 0; upp = &(*upp)->nextppa)
345             if (*upp == up) {
346                 *upp = up->nextppa;
347                 break;
348             }
349 #ifdef LACHTCP
350         /* Remove the statistics from the active list.  */
351         for (ifp = ifstats, pifp = 0; ifp; ifp = ifp->ifs_next) {
352             if (ifp == &up->ifstats) {
353                 if (pifp)
354                     pifp->ifs_next = ifp->ifs_next;
355                 else
356                     ifstats = ifp->ifs_next;
357                 break;
358             }
359             pifp = ifp;
360         }
361 #endif
362     } else {
363         /*
364          * If this stream is attached to a PPA,
365          * remove it from the PPA's list.
366          */
367         if ((as = up->ppa) != 0) {
368             for (; as->next != 0; as = as->next)
369                 if (as->next == up) {
370                     as->next = up->next;
371                     break;
372                 }
373         }
374     }
375
376 #ifdef SOL2
377     if (up->kstats)
378         kstat_delete(up->kstats);
379 #endif
380
381     q->q_ptr = NULL;
382     WR(q)->q_ptr = NULL;
383
384     for (prevp = &minor_devs; *prevp != 0; prevp = &(*prevp)->nextmn) {
385         if (*prevp == up) {
386             *prevp = up->nextmn;
387             break;
388         }
389     }
390     kmem_free(up, sizeof(upperstr_t));
391     --ppp_count;
392
393     return 0;
394 }
395
396 /*
397  * A message from on high.  We do one of three things:
398  *      - qreply()
399  *      - put the message on the lower write stream
400  *      - queue it for our service routine
401  */
402 static int
403 pppuwput(q, mp)
404     queue_t *q;
405     mblk_t *mp;
406 {
407     upperstr_t *us, *usnext, *ppa, *os, *nps;
408     struct iocblk *iop;
409     struct linkblk *lb;
410 #ifdef LACHTCP
411     struct ifreq *ifr;
412     int i;
413 #endif
414     queue_t *lq;
415     int error, n, sap;
416     mblk_t *mq;
417     struct ppp_idle *pip;
418
419     us = (upperstr_t *) q->q_ptr;
420     switch (mp->b_datap->db_type) {
421 #ifndef NO_DLPI
422     case M_PCPROTO:
423     case M_PROTO:
424         dlpi_request(q, mp, us);
425         break;
426 #endif /* NO_DLPI */
427
428     case M_DATA:
429         if (us->flags & US_DBGLOG)
430             DPRINT3("ppp/%d: uwput M_DATA len=%d flags=%x\n",
431                     us->mn, msgdsize(mp), us->flags);
432         if (us->ppa == 0 || msgdsize(mp) > us->ppa->mtu + PPP_HDRLEN
433 #ifndef NO_DLPI
434             || (us->flags & US_CONTROL) == 0
435 #endif /* NO_DLPI */
436             ) {
437             DPRINT1("pppuwput: junk data len=%d\n", msgdsize(mp));
438             freemsg(mp);
439             break;
440         }
441 #ifdef NO_DLPI
442         if ((us->flags & US_CONTROL) == 0)
443             us->ppa->last_sent = time;
444 #endif
445         if (!send_data(mp, us))
446             putq(q, mp);
447         break;
448
449     case M_IOCTL:
450         iop = (struct iocblk *) mp->b_rptr;
451         error = EINVAL;
452         if (us->flags & US_DBGLOG)
453             DPRINT3("ppp/%d: ioctl %x count=%d\n",
454                     us->mn, iop->ioc_cmd, iop->ioc_count);
455         switch (iop->ioc_cmd) {
456         case I_LINK:
457             if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
458                 break;
459             lb = (struct linkblk *) mp->b_cont->b_rptr;
460             us->lowerq = lq = lb->l_qbot;
461             lq->q_ptr = (caddr_t) us;
462             RD(lq)->q_ptr = (caddr_t) us;
463             noenable(RD(lq));
464             flushq(RD(lq), FLUSHALL);
465             iop->ioc_count = 0;
466             error = 0;
467             us->flags &= ~US_LASTMOD;
468             /* Unblock upper streams which now feed this lower stream. */
469             qenable(lq);
470             /* Send useful information down to the modules which
471                are now linked below us. */
472             putctl2(lq, M_CTL, PPPCTL_UNIT, us->ppa_id);
473             putctl4(lq, M_CTL, PPPCTL_MRU, us->mru);
474             putctl4(lq, M_CTL, PPPCTL_MTU, us->mtu);
475             break;
476
477         case I_UNLINK:
478             lb = (struct linkblk *) mp->b_cont->b_rptr;
479 #if DEBUG
480             if (us->lowerq != lb->l_qbot)
481                 DPRINT2("ppp unlink: lowerq=%x qbot=%x\n",
482                         us->lowerq, lb->l_qbot);
483 #endif
484             us->lowerq = 0;
485             iop->ioc_count = 0;
486             error = 0;
487             /* Unblock streams which now feed back up the control stream. */
488             qenable(us->q);
489             break;
490
491         case PPPIO_NEWPPA:
492             if (us->flags & US_CONTROL)
493                 break;
494             if ((us->flags & US_PRIV) == 0) {
495                 error = EPERM;
496                 break;
497             }
498             /* Arrange to return an int */
499             if ((mq = mp->b_cont) == 0
500                 || mq->b_datap->db_lim - mq->b_rptr < sizeof(int)) {
501                 mq = allocb(sizeof(int), BPRI_HI);
502                 if (mq == 0) {
503                     error = ENOSR;
504                     break;
505                 }
506                 if (mp->b_cont != 0)
507                     freemsg(mp->b_cont);
508                 mp->b_cont = mq;
509                 mq->b_cont = 0;
510             }
511             iop->ioc_count = sizeof(int);
512             mq->b_wptr = mq->b_rptr + sizeof(int);
513             qwriter(q, mp, new_ppa, PERIM_OUTER);
514             error = -1;
515             break;
516
517         case PPPIO_ATTACH:
518             /* like dlpi_attach, for programs which can't write to
519                the stream (like pppstats) */
520             if (iop->ioc_count != sizeof(int) || us->ppa != 0)
521                 break;
522             n = *(int *)mp->b_cont->b_rptr;
523             for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
524                 if (ppa->ppa_id == n)
525                     break;
526             if (ppa == 0)
527                 break;
528             us->ppa = ppa;
529             iop->ioc_count = 0;
530             qwriter(q, mp, attach_ppa, PERIM_OUTER);
531             error = -1;
532             break;
533
534 #ifdef NO_DLPI
535         case PPPIO_BIND:
536             /* Attach to a given SAP. */
537             if (iop->ioc_count != sizeof(int) || us->ppa == 0)
538                 break;
539             n = *(int *)mp->b_cont->b_rptr;
540             /* n must be a valid PPP network protocol number. */
541             if (n < 0x21 || n > 0x3fff || (n & 0x101) != 1)
542                 break;
543             /* check that no other stream is bound to this sap already. */
544             for (os = us->ppa; os != 0; os = os->next)
545                 if (os->sap == n)
546                     break;
547             if (os != 0)
548                 break;
549             us->sap = n;
550             iop->ioc_count = 0;
551             error = 0;
552             break;
553 #endif /* NO_DLPI */
554
555         case PPPIO_MRU:
556             if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
557                 break;
558             n = *(int *)mp->b_cont->b_rptr;
559             if (n <= 0 || n > PPP_MAXMTU)
560                 break;
561             if (n < PPP_MRU)
562                 n = PPP_MRU;
563             us->mru = n;
564             if (us->lowerq)
565                 putctl4(us->lowerq, M_CTL, PPPCTL_MRU, n);
566             error = 0;
567             iop->ioc_count = 0;
568             break;
569
570         case PPPIO_MTU:
571             if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
572                 break;
573             n = *(int *)mp->b_cont->b_rptr;
574             if (n <= 0 || n > PPP_MAXMTU)
575                 break;
576             if (n < PPP_MRU)
577                 n = PPP_MRU;
578             us->mtu = n;
579 #ifdef LACHTCP
580             us->ifstats.ifs_mtu = n;
581 #endif
582             if (us->lowerq)
583                 putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n);
584             error = 0;
585             iop->ioc_count = 0;
586             break;
587
588         case PPPIO_LASTMOD:
589             us->flags |= US_LASTMOD;
590             error = 0;
591             break;
592
593         case PPPIO_DEBUG:
594             if (iop->ioc_count != sizeof(int))
595                 break;
596             n = *(int *)mp->b_cont->b_rptr;
597             if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
598                 qwriter(q, NULL, debug_dump, PERIM_OUTER);
599                 iop->ioc_count = 0;
600                 error = 0;
601             } else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
602                 DPRINT1("ppp/%d: debug log enabled\n", us->mn);
603                 us->flags |= US_DBGLOG;
604                 iop->ioc_count = 0;
605                 error = 0;
606             } else {
607                 if (us->ppa == 0 || us->ppa->lowerq == 0)
608                     break;
609                 putnext(us->ppa->lowerq, mp);
610                 error = -1;
611             }
612             break;
613
614         case PPPIO_NPMODE:
615             if (iop->ioc_count != 2 * sizeof(int))
616                 break;
617             if ((us->flags & US_CONTROL) == 0)
618                 break;
619             sap = ((int *)mp->b_cont->b_rptr)[0];
620             for (nps = us->next; nps != 0; nps = nps->next)
621                 if (nps->sap == sap)
622                     break;
623             if (nps == 0)
624                 break;
625             nps->npmode = (enum NPmode) ((int *)mp->b_cont->b_rptr)[1];
626             if (nps->npmode == NPMODE_DROP || nps->npmode == NPMODE_ERROR)
627                 flushq(WR(nps->q), FLUSHDATA);
628             else if (nps->npmode == NPMODE_PASS && qsize(WR(nps->q)) > 0
629                      && (nps->flags & US_BLOCKED) == 0)
630                 qenable(WR(nps->q));
631             iop->ioc_count = 0;
632             error = 0;
633             break;
634
635         case PPPIO_GIDLE:
636             if ((ppa = us->ppa) == 0)
637                 break;
638             mq = allocb(sizeof(struct ppp_idle), BPRI_HI);
639             if (mq == 0) {
640                 error = ENOSR;
641                 break;
642             }
643             if (mp->b_cont != 0)
644                 freemsg(mp->b_cont);
645             mp->b_cont = mq;
646             mq->b_cont = 0;
647             pip = (struct ppp_idle *) mq->b_wptr;
648             pip->xmit_idle = time - ppa->last_sent;
649             pip->recv_idle = time - ppa->last_recv;
650             mq->b_wptr += sizeof(struct ppp_idle);
651             iop->ioc_count = sizeof(struct ppp_idle);
652             error = 0;
653             break;
654
655 #ifdef LACHTCP
656         case SIOCSIFNAME:
657             printf("SIOCSIFNAME\n");
658             /* Sent from IP down to us.  Attach the ifstats structure.  */
659             if (iop->ioc_count != sizeof(struct ifreq) || us->ppa == 0)
660                 break;
661             ifr = (struct ifreq *)mp->b_cont->b_rptr;
662             /* Find the unit number in the interface name.  */
663             for (i = 0; i < IFNAMSIZ; i++) {
664                 if (ifr->ifr_name[i] == 0 ||
665                     (ifr->ifr_name[i] >= '0' &&
666                      ifr->ifr_name[i] <= '9'))
667                     break;
668                 else
669                     us->ifname[i] = ifr->ifr_name[i];
670             }
671             us->ifname[i] = 0;
672
673             /* Convert the unit number to binary.  */
674             for (n = 0; i < IFNAMSIZ; i++) {
675                 if (ifr->ifr_name[i] == 0) {
676                     break;
677                 }
678                 else {
679                     n = n * 10 + ifr->ifr_name[i] - '0';
680                 }
681             }
682
683             /* Verify the ppa.  */
684             if (us->ppa->ppa_id != n)
685                 break;
686             ppa = us->ppa;
687
688             /* Set up the netstat block.  */
689             strncpy (ppa->ifname, us->ifname, IFNAMSIZ);
690
691             ppa->ifstats.ifs_name = ppa->ifname;
692             ppa->ifstats.ifs_unit = n;
693             ppa->ifstats.ifs_active = us->state != DL_UNBOUND;
694             ppa->ifstats.ifs_mtu = ppa->mtu;
695
696             /* Link in statistics used by netstat.  */
697             ppa->ifstats.ifs_next = ifstats;
698             ifstats = &ppa->ifstats;
699
700             iop->ioc_count = 0;
701             error = 0;
702             break;
703
704         case SIOCGIFFLAGS:
705             printf("SIOCGIFFLAGS\n");
706             if (!(us->flags & US_CONTROL)) {
707                 if (us->ppa)
708                     us = us->ppa;
709                 else
710                     break;
711             }
712             ((struct iocblk_in *)iop)->ioc_ifflags = us->ifflags;
713             error = 0;
714             break;
715
716         case SIOCSIFFLAGS:
717             printf("SIOCSIFFLAGS\n");
718             if (!(us->flags & US_CONTROL)) {
719                 if (us->ppa)
720                     us = us->ppa;
721                 else
722                     break;
723             }
724             us->ifflags = ((struct iocblk_in *)iop)->ioc_ifflags;
725             error = 0;
726             break;
727
728         case SIOCSIFADDR:
729             printf("SIOCSIFADDR\n");
730             if (!(us->flags & US_CONTROL)) {
731                 if (us->ppa)
732                     us = us->ppa;
733                 else
734                     break;
735             }
736             us->ifflags |= IFF_RUNNING;
737             ((struct iocblk_in *)iop)->ioc_ifflags |= IFF_RUNNING;
738             error = 0;
739             break;
740
741         case SIOCGIFNETMASK:
742         case SIOCSIFNETMASK:
743         case SIOCGIFADDR:
744         case SIOCGIFDSTADDR:
745         case SIOCSIFDSTADDR:
746         case SIOCGIFMETRIC:
747             error = 0;
748             break;
749 #endif /* LACHTCP */
750
751         default:
752             if (us->ppa == 0 || us->ppa->lowerq == 0)
753                 break;
754             us->ioc_id = iop->ioc_id;
755             error = -1;
756             switch (iop->ioc_cmd) {
757             case PPPIO_GETSTAT:
758             case PPPIO_GETCSTAT:
759                 if (us->flags & US_LASTMOD) {
760                     error = EINVAL;
761                     break;
762                 }
763                 putnext(us->ppa->lowerq, mp);
764                 break;
765             default:
766                 if (us->flags & US_PRIV)
767                     putnext(us->ppa->lowerq, mp);
768                 else {
769                     DPRINT1("ppp ioctl %x rejected\n", iop->ioc_cmd);
770                     error = EPERM;
771                 }
772                 break;
773             }
774             break;
775         }
776
777         if (error > 0) {
778             iop->ioc_error = error;
779             mp->b_datap->db_type = M_IOCNAK;
780             qreply(q, mp);
781         } else if (error == 0) {
782             mp->b_datap->db_type = M_IOCACK;
783             qreply(q, mp);
784         }
785         break;
786
787     case M_FLUSH:
788         if (us->flags & US_DBGLOG)
789             DPRINT2("ppp/%d: flush %x\n", us->mn, *mp->b_rptr);
790         if (*mp->b_rptr & FLUSHW)
791             flushq(q, FLUSHDATA);
792         if (*mp->b_rptr & FLUSHR) {
793             *mp->b_rptr &= ~FLUSHW;
794             qreply(q, mp);
795         } else
796             freemsg(mp);
797         break;
798
799     default:
800         freemsg(mp);
801         break;
802     }
803     return 0;
804 }
805
806 #ifndef NO_DLPI
807 static void
808 dlpi_request(q, mp, us)
809     queue_t *q;
810     mblk_t *mp;
811     upperstr_t *us;
812 {
813     union DL_primitives *d = (union DL_primitives *) mp->b_rptr;
814     int size = mp->b_wptr - mp->b_rptr;
815     mblk_t *reply, *np;
816     upperstr_t *ppa, *os;
817     int sap, *ip, len;
818     dl_info_ack_t *info;
819     dl_bind_ack_t *ackp;
820
821     if (us->flags & US_DBGLOG)
822         cmn_err(CE_CONT, "ppp/%d: dlpi prim %x len=%d\n", us->mn,
823                 d->dl_primitive, size);
824     switch (d->dl_primitive) {
825     case DL_INFO_REQ:
826         if (size < sizeof(dl_info_req_t))
827             goto badprim;
828         if ((reply = allocb(sizeof(dl_info_ack_t), BPRI_HI)) == 0)
829             break;              /* should do bufcall */
830         reply->b_datap->db_type = M_PCPROTO;
831         info = (dl_info_ack_t *) reply->b_wptr;
832         reply->b_wptr += sizeof(dl_info_ack_t);
833         bzero((caddr_t) info, sizeof(dl_info_ack_t));
834         info->dl_primitive = DL_INFO_ACK;
835         info->dl_max_sdu = PPP_MAXMTU;
836         info->dl_min_sdu = 1;
837         info->dl_addr_length = sizeof(ulong);
838 #ifdef DL_OTHER
839         info->dl_mac_type = DL_OTHER;
840 #else
841         info->dl_mac_type = DL_HDLC;    /* a lie */
842 #endif
843         info->dl_current_state = us->state;
844         info->dl_service_mode = DL_CLDLS;
845         info->dl_provider_style = DL_STYLE2;
846 #if DL_CURRENT_VERSION >= 2
847         info->dl_sap_length = sizeof(ulong);
848         info->dl_version = DL_CURRENT_VERSION;
849 #endif
850         qreply(q, reply);
851         break;
852
853     case DL_ATTACH_REQ:
854         if (size < sizeof(dl_attach_req_t))
855             goto badprim;
856         if (us->state != DL_UNATTACHED || us->ppa != 0) {
857             dlpi_error(q, DL_ATTACH_REQ, DL_OUTSTATE, 0);
858             break;
859         }
860         for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
861             if (ppa->ppa_id == d->attach_req.dl_ppa)
862                 break;
863         if (ppa == 0) {
864             dlpi_error(q, DL_ATTACH_REQ, DL_BADPPA, 0);
865             break;
866         }
867         us->ppa = ppa;
868         qwriter(q, mp, attach_ppa, PERIM_OUTER);
869         break;
870
871     case DL_DETACH_REQ:
872         if (size < sizeof(dl_detach_req_t))
873             goto badprim;
874         if (us->state != DL_UNBOUND || us->ppa == 0) {
875             dlpi_error(q, DL_DETACH_REQ, DL_OUTSTATE, 0);
876             break;
877         }
878         qwriter(q, mp, detach_ppa, PERIM_OUTER);
879         break;
880
881     case DL_BIND_REQ:
882         if (size < sizeof(dl_bind_req_t))
883             goto badprim;
884         if (us->state != DL_UNBOUND || us->ppa == 0) {
885             dlpi_error(q, DL_BIND_REQ, DL_OUTSTATE, 0);
886             break;
887         }
888         if (d->bind_req.dl_service_mode != DL_CLDLS) {
889             dlpi_error(q, DL_BIND_REQ, DL_UNSUPPORTED, 0);
890             break;
891         }
892
893         /* saps must be valid PPP network protocol numbers,
894            except that we accept ETHERTYPE_IP in place of PPP_IP. */
895         sap = d->bind_req.dl_sap;
896         us->req_sap = sap;
897         DPRINT1("ppp bind %x\n", sap);
898         if (sap == ETHERTYPE_IP)
899             sap = PPP_IP;
900         if (sap < 0x21 || sap > 0x3fff || (sap & 0x101) != 1) {
901             dlpi_error(q, DL_BIND_REQ, DL_BADADDR, 0);
902             break;
903         }
904
905         /* check that no other stream is bound to this sap already. */
906         for (os = us->ppa; os != 0; os = os->next)
907             if (os->sap == sap)
908                 break;
909         if (os != 0) {
910             dlpi_error(q, DL_BIND_REQ, DL_NOADDR, 0);
911             break;
912         }
913
914         us->sap = sap;
915         us->state = DL_IDLE;
916
917         if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(ulong),
918                             BPRI_HI)) == 0)
919             break;              /* should do bufcall */
920         ackp = (dl_bind_ack_t *) reply->b_wptr;
921         reply->b_wptr += sizeof(dl_bind_ack_t) + sizeof(ulong);
922         reply->b_datap->db_type = M_PCPROTO;
923         bzero((caddr_t) ackp, sizeof(dl_bind_ack_t));
924         ackp->dl_primitive = DL_BIND_ACK;
925         ackp->dl_sap = sap;
926         ackp->dl_addr_length = sizeof(ulong);
927         ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
928         *(ulong *)(ackp+1) = sap;
929         qreply(q, reply);
930         break;
931
932     case DL_UNBIND_REQ:
933         if (size < sizeof(dl_unbind_req_t))
934             goto badprim;
935         if (us->state != DL_IDLE) {
936             dlpi_error(q, DL_UNBIND_REQ, DL_OUTSTATE, 0);
937             break;
938         }
939         us->sap = -1;
940         us->state = DL_UNBOUND;
941 #ifdef LACHTCP
942         us->ppa->ifstats.ifs_active = 0;
943 #endif
944         dlpi_ok(q, DL_UNBIND_REQ);
945         break;
946
947     case DL_UNITDATA_REQ:
948         if (size < sizeof(dl_unitdata_req_t))
949             goto badprim;
950         if (us->state != DL_IDLE) {
951             dlpi_error(q, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
952             break;
953         }
954         if ((ppa = us->ppa) == 0) {
955             cmn_err(CE_CONT, "ppp: in state dl_idle but ppa == 0?\n");
956             break;
957         }
958         len = mp->b_cont == 0? 0: msgdsize(mp->b_cont);
959         if (len > ppa->mtu) {
960             DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->mtu);
961             break;
962         }
963         ppa->last_sent = time;
964         /* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */
965         if (mp->b_datap->db_ref > 1) {
966             np = allocb(PPP_HDRLEN, BPRI_HI);
967             if (np == 0)
968                 break;          /* gak! */
969             np->b_cont = mp->b_cont;
970             mp->b_cont = 0;
971             freeb(mp);
972             mp = np;
973         } else
974             mp->b_datap->db_type = M_DATA;
975         /* XXX should use dl_dest_addr_offset/length here,
976            but we would have to translate ETHERTYPE_IP -> PPP_IP */
977         mp->b_wptr = mp->b_rptr + PPP_HDRLEN;
978         mp->b_rptr[0] = PPP_ALLSTATIONS;
979         mp->b_rptr[1] = PPP_UI;
980         mp->b_rptr[2] = us->sap >> 8;
981         mp->b_rptr[3] = us->sap;
982         if (!send_data(mp, us))
983             putq(q, mp);
984         return;
985
986 #if DL_CURRENT_VERSION >= 2
987     case DL_SUBS_BIND_REQ:
988     case DL_SUBS_UNBIND_REQ:
989     case DL_ENABMULTI_REQ:
990     case DL_DISABMULTI_REQ:
991     case DL_PROMISCON_REQ:
992     case DL_PROMISCOFF_REQ:
993     case DL_PHYS_ADDR_REQ:
994     case DL_SET_PHYS_ADDR_REQ:
995     case DL_XID_REQ:
996     case DL_TEST_REQ:
997     case DL_REPLY_UPDATE_REQ:
998     case DL_REPLY_REQ:
999     case DL_DATA_ACK_REQ:
1000 #endif
1001     case DL_CONNECT_REQ:
1002     case DL_TOKEN_REQ:
1003         dlpi_error(q, d->dl_primitive, DL_NOTSUPPORTED, 0);
1004         break;
1005
1006     case DL_CONNECT_RES:
1007     case DL_DISCONNECT_REQ:
1008     case DL_RESET_REQ:
1009     case DL_RESET_RES:
1010         dlpi_error(q, d->dl_primitive, DL_OUTSTATE, 0);
1011         break;
1012
1013     case DL_UDQOS_REQ:
1014         dlpi_error(q, d->dl_primitive, DL_BADQOSTYPE, 0);
1015         break;
1016
1017 #if DL_CURRENT_VERSION >= 2
1018     case DL_TEST_RES:
1019     case DL_XID_RES:
1020         break;
1021 #endif
1022
1023     default:
1024         cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
1025         /* fall through */
1026     badprim:
1027         dlpi_error(q, d->dl_primitive, DL_BADPRIM, 0);
1028         break;
1029     }
1030     freemsg(mp);
1031 }
1032
1033 static void
1034 dlpi_error(q, prim, err, uerr)
1035     queue_t *q;
1036     int prim, err, uerr;
1037 {
1038     mblk_t *reply;
1039     dl_error_ack_t *errp;
1040
1041     reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
1042     if (reply == 0)
1043         return;                 /* XXX should do bufcall */
1044     reply->b_datap->db_type = M_PCPROTO;
1045     errp = (dl_error_ack_t *) reply->b_wptr;
1046     reply->b_wptr += sizeof(dl_error_ack_t);
1047     errp->dl_primitive = DL_ERROR_ACK;
1048     errp->dl_error_primitive = prim;
1049     errp->dl_errno = err;
1050     errp->dl_unix_errno = uerr;
1051     qreply(q, reply);
1052 }
1053
1054 static void
1055 dlpi_ok(q, prim)
1056     queue_t *q;
1057     int prim;
1058 {
1059     mblk_t *reply;
1060     dl_ok_ack_t *okp;
1061
1062     reply = allocb(sizeof(dl_ok_ack_t), BPRI_HI);
1063     if (reply == 0)
1064         return;                 /* XXX should do bufcall */
1065     reply->b_datap->db_type = M_PCPROTO;
1066     okp = (dl_ok_ack_t *) reply->b_wptr;
1067     reply->b_wptr += sizeof(dl_ok_ack_t);
1068     okp->dl_primitive = DL_OK_ACK;
1069     okp->dl_correct_primitive = prim;
1070     qreply(q, reply);
1071 }
1072 #endif /* NO_DLPI */
1073
1074 static int
1075 send_data(mp, us)
1076     mblk_t *mp;
1077     upperstr_t *us;
1078 {
1079     queue_t *q;
1080     upperstr_t *ppa;
1081
1082     if (us->flags & US_BLOCKED || us->npmode == NPMODE_QUEUE)
1083         return 0;
1084     ppa = us->ppa;
1085     if (ppa == 0 || us->npmode == NPMODE_DROP || us->npmode == NPMODE_ERROR) {
1086         freemsg(mp);
1087         return 1;
1088     }
1089     if ((q = ppa->lowerq) == 0) {
1090         /* try to send it up the control stream */
1091         if (canputnext(ppa->q)) {
1092             putnext(ppa->q, mp);
1093             return 1;
1094         }
1095     } else {
1096         if (canputnext(ppa->lowerq)) {
1097             /*
1098              * The lower write queue's put procedure just updates counters
1099              * and does a putnext.  We call it so that on SMP systems, we
1100              * enter the lower queues' perimeter so that the counter
1101              * updates are serialized.
1102              */
1103             put(ppa->lowerq, mp);
1104             return 1;
1105         }
1106     }
1107     us->flags |= US_BLOCKED;
1108     return 0;
1109 }
1110
1111 /*
1112  * Allocate a new PPA id and link this stream into the list of PPAs.
1113  * This procedure is called with an exclusive lock on all queues in
1114  * this driver.
1115  */
1116 static void
1117 new_ppa(q, mp)
1118     queue_t *q;
1119     mblk_t *mp;
1120 {
1121     upperstr_t *us, **usp;
1122     int ppa_id;
1123
1124     usp = &ppas;
1125     ppa_id = 0;
1126     while ((us = *usp) != 0 && ppa_id == us->ppa_id) {
1127         ++ppa_id;
1128         usp = &us->nextppa;
1129     }
1130     us = (upperstr_t *) q->q_ptr;
1131     us->ppa_id = ppa_id;
1132     us->ppa = us;
1133     us->next = 0;
1134     us->nextppa = *usp;
1135     *usp = us;
1136     us->flags |= US_CONTROL;
1137     us->npmode = NPMODE_PASS;
1138
1139     us->mtu = PPP_MRU;
1140     us->mru = PPP_MRU;
1141
1142 #ifdef SOL2
1143     /*
1144      * Create a kstats record for our statistics, so netstat -i works.
1145      */
1146     if (us->kstats == 0) {
1147         char unit[32];
1148
1149         sprintf(unit, "ppp%d", us->ppa->ppa_id);
1150         us->kstats = kstat_create("ppp", us->ppa->ppa_id, unit,
1151                                   "net", KSTAT_TYPE_NAMED, 4, 0);
1152         if (us->kstats != 0) {
1153             kstat_named_t *kn = KSTAT_NAMED_PTR(us->kstats);
1154
1155             strcpy(kn[0].name, "ipackets");
1156             kn[0].data_type = KSTAT_DATA_ULONG;
1157             strcpy(kn[1].name, "ierrors");
1158             kn[1].data_type = KSTAT_DATA_ULONG;
1159             strcpy(kn[2].name, "opackets");
1160             kn[2].data_type = KSTAT_DATA_ULONG;
1161             strcpy(kn[3].name, "oerrors");
1162             kn[3].data_type = KSTAT_DATA_ULONG;
1163             kstat_install(us->kstats);
1164         }
1165     }
1166 #endif /* SOL2 */
1167
1168     *(int *)mp->b_cont->b_rptr = ppa_id;
1169     mp->b_datap->db_type = M_IOCACK;
1170     qreply(q, mp);
1171 }
1172
1173 static void
1174 attach_ppa(q, mp)
1175     queue_t *q;
1176     mblk_t *mp;
1177 {
1178     upperstr_t *us, *t;
1179
1180     us = (upperstr_t *) q->q_ptr;
1181 #ifndef NO_DLPI
1182     us->state = DL_UNBOUND;
1183 #endif
1184     for (t = us->ppa; t->next != 0; t = t->next)
1185         ;
1186     t->next = us;
1187     us->next = 0;
1188     if (mp->b_datap->db_type == M_IOCTL) {
1189         mp->b_datap->db_type = M_IOCACK;
1190         qreply(q, mp);
1191     } else {
1192 #ifndef NO_DLPI
1193         dlpi_ok(q, DL_ATTACH_REQ);
1194 #endif
1195     }
1196 }
1197
1198 static void
1199 detach_ppa(q, mp)
1200     queue_t *q;
1201     mblk_t *mp;
1202 {
1203     upperstr_t *us, *t;
1204
1205     us = (upperstr_t *) q->q_ptr;
1206     for (t = us->ppa; t->next != 0; t = t->next)
1207         if (t->next == us) {
1208             t->next = us->next;
1209             break;
1210         }
1211     us->next = 0;
1212     us->ppa = 0;
1213 #ifndef NO_DLPI
1214     us->state = DL_UNATTACHED;
1215     dlpi_ok(q, DL_DETACH_REQ);
1216 #endif
1217 }
1218
1219 static int
1220 pppuwsrv(q)
1221     queue_t *q;
1222 {
1223     upperstr_t *us;
1224     struct lowerstr *ls;
1225     queue_t *lwq;
1226     mblk_t *mp;
1227
1228     us = (upperstr_t *) q->q_ptr;
1229     us->flags &= ~US_BLOCKED;
1230     while ((mp = getq(q)) != 0) {
1231         if (!send_data(mp, us)) {
1232             putbq(q, mp);
1233             break;
1234         }
1235     }
1236     return 0;
1237 }
1238
1239 static int
1240 ppplwput(q, mp)
1241     queue_t *q;
1242     mblk_t *mp;
1243 {
1244     upperstr_t *ppa;
1245
1246     ppa = (upperstr_t *) q->q_ptr;
1247     if (ppa != 0) {             /* why wouldn't it? */
1248         ppa->stats.ppp_opackets++;
1249         ppa->stats.ppp_obytes += msgdsize(mp);
1250 #ifdef INCR_OPACKETS
1251         INCR_OPACKETS(ppa);
1252 #endif
1253     }
1254     putnext(q, mp);
1255     return 0;
1256 }
1257
1258 static int
1259 ppplwsrv(q)
1260     queue_t *q;
1261 {
1262     upperstr_t *us;
1263
1264     /*
1265      * Flow control has back-enabled this stream:
1266      * enable the write service procedures of all upper
1267      * streams feeding this lower stream.
1268      */
1269     for (us = (upperstr_t *) q->q_ptr; us != NULL; us = us->next)
1270         if (us->flags & US_BLOCKED)
1271             qenable(WR(us->q));
1272     return 0;
1273 }
1274
1275 static int
1276 pppursrv(q)
1277     queue_t *q;
1278 {
1279     upperstr_t *us, *as;
1280     mblk_t *mp, *hdr;
1281 #ifndef NO_DLPI
1282     dl_unitdata_ind_t *ud;
1283 #endif
1284     int proto;
1285
1286     us = (upperstr_t *) q->q_ptr;
1287     if (us->flags & US_CONTROL) {
1288         /*
1289          * A control stream.
1290          * If there is no lower queue attached, run the write service
1291          * routines of other upper streams attached to this PPA.
1292          */
1293         if (us->lowerq == 0) {
1294             as = us;
1295             do {
1296                 if (as->flags & US_BLOCKED)
1297                     qenable(WR(as->q));
1298                 as = as->next;
1299             } while (as != 0);
1300         }
1301     } else {
1302         /*
1303          * A network protocol stream.  Put a DLPI header on each
1304          * packet and send it on.
1305          * (Actually, it seems that the IP module will happily
1306          * accept M_DATA messages without the DL_UNITDATA_IND header.)
1307          */
1308         while ((mp = getq(q)) != 0) {
1309             if (!canputnext(q)) {
1310                 putbq(q, mp);
1311                 break;
1312             }
1313 #ifndef NO_DLPI
1314             proto = PPP_PROTOCOL(mp->b_rptr);
1315             mp->b_rptr += PPP_HDRLEN;
1316             hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong),
1317                          BPRI_MED);
1318             if (hdr == 0) {
1319                 /* XXX should put it back and use bufcall */
1320                 freemsg(mp);
1321                 continue;
1322             }
1323             hdr->b_datap->db_type = M_PROTO;
1324             ud = (dl_unitdata_ind_t *) hdr->b_wptr;
1325             hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong);
1326             hdr->b_cont = mp;
1327             ud->dl_primitive = DL_UNITDATA_IND;
1328             ud->dl_dest_addr_length = sizeof(ulong);
1329             ud->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
1330             ud->dl_src_addr_length = sizeof(ulong);
1331             ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(ulong);
1332 #if DL_CURRENT_VERSION >= 2
1333             ud->dl_group_address = 0;
1334 #endif
1335             /* Send the DLPI client the data with the SAP they requested,
1336                (e.g. ETHERTYPE_IP) rather than the PPP protocol number
1337                (e.g. PPP_IP) */
1338             ((ulong *)(ud + 1))[0] = us->req_sap;       /* dest SAP */
1339             ((ulong *)(ud + 1))[1] = us->req_sap;       /* src SAP */
1340             putnext(q, hdr);
1341 #else /* NO_DLPI */
1342             putnext(q, mp);
1343 #endif /* NO_DLPI */
1344         }
1345     }
1346
1347     /*
1348      * If this stream is attached to a PPA with a lower queue pair,
1349      * enable the read queue's service routine if it has data queued.
1350      * XXX there is a possibility that packets could get out of order
1351      * if ppplrput now runs before ppplrsrv.
1352      */
1353     if (us->ppa != 0 && us->ppa->lowerq != 0)
1354         qenable(RD(us->ppa->lowerq));
1355
1356     return 0;
1357 }
1358
1359 static upperstr_t *
1360 find_dest(ppa, proto)
1361     upperstr_t *ppa;
1362     int proto;
1363 {
1364     upperstr_t *us;
1365
1366     for (us = ppa->next; us != 0; us = us->next)
1367         if (proto == us->sap)
1368             break;
1369     return us;
1370 }
1371
1372 static int
1373 ppplrput(q, mp)
1374     queue_t *q;
1375     mblk_t *mp;
1376 {
1377     upperstr_t *ppa, *us;
1378     queue_t *uq;
1379     int proto, len;
1380     mblk_t *np;
1381     struct iocblk *iop;
1382
1383     ppa = (upperstr_t *) q->q_ptr;
1384     if (ppa == 0) {
1385         DPRINT1("ppplrput: q = %x, ppa = 0??\n", q);
1386         freemsg(mp);
1387         return 0;
1388     }
1389     switch (mp->b_datap->db_type) {
1390     case M_FLUSH:
1391         if (*mp->b_rptr & FLUSHW) {
1392             *mp->b_rptr &= ~FLUSHR;
1393             qreply(q, mp);
1394         } else
1395             freemsg(mp);
1396         break;
1397
1398     case M_CTL:
1399         switch (*mp->b_rptr) {
1400         case PPPCTL_IERROR:
1401 #ifdef INCR_IERRORS
1402             INCR_IERRORS(ppa);
1403 #endif
1404             ppa->stats.ppp_ierrors++;
1405             break;
1406         case PPPCTL_OERROR:
1407 #ifdef INCR_OERRORS
1408             INCR_OERRORS(ppa);
1409 #endif
1410             ppa->stats.ppp_oerrors++;
1411             break;
1412         }
1413         freemsg(mp);
1414         break;
1415
1416     case M_IOCACK:
1417     case M_IOCNAK:
1418         /*
1419          * Attempt to match up the response with the stream
1420          * that the request came from.
1421          */
1422         iop = (struct iocblk *) mp->b_rptr;
1423         for (us = ppa; us != 0; us = us->next)
1424             if (us->ioc_id == iop->ioc_id)
1425                 break;
1426         if (us == 0)
1427             freemsg(mp);
1428         else
1429             putnext(us->q, mp);
1430         break;
1431
1432     default:
1433         if (mp->b_datap->db_type == M_DATA) {
1434             len = msgdsize(mp);
1435             if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
1436                 PULLUP(mp, PPP_HDRLEN);
1437                 if (mp == 0) {
1438                     DPRINT1("ppp_lrput: msgpullup failed (len=%d)\n", len);
1439                     break;
1440                 }
1441             }
1442             ppa->stats.ppp_ipackets++;
1443             ppa->stats.ppp_ibytes += len;
1444 #ifdef INCR_IPACKETS
1445             INCR_IPACKETS(ppa);
1446 #endif
1447             proto = PPP_PROTOCOL(mp->b_rptr);
1448             if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
1449                 /*
1450                  * A data packet for some network protocol.
1451                  * Queue it on the upper stream for that protocol.
1452                  */
1453                 if (canput(us->q))
1454                     putq(us->q, mp);
1455                 else
1456                     putq(q, mp);
1457                 ppa->last_recv = time;
1458                 break;
1459             }
1460         }
1461         /*
1462          * A control frame, a frame for an unknown protocol,
1463          * or some other message type.
1464          * Send it up to pppd via the control stream.
1465          */
1466         if (queclass(mp) == QPCTL || canputnext(ppa->q))
1467             putnext(ppa->q, mp);
1468         else
1469             putq(q, mp);
1470         break;
1471     }
1472
1473     return 0;
1474 }
1475
1476 static int
1477 ppplrsrv(q)
1478     queue_t *q;
1479 {
1480     mblk_t *mp;
1481     upperstr_t *ppa, *us;
1482     int proto;
1483
1484     /*
1485      * Packets only get queued here for flow control reasons.
1486      */
1487     ppa = (upperstr_t *) q->q_ptr;
1488     while ((mp = getq(q)) != 0) {
1489         if (mp->b_datap->db_type == M_DATA
1490             && (proto = PPP_PROTOCOL(mp->b_rptr)) < 0x8000
1491             && (us = find_dest(ppa, proto)) != 0) {
1492             if (canput(us->q))
1493                 putq(us->q, mp);
1494             else {
1495                 putbq(q, mp);
1496                 break;
1497             }
1498         } else {
1499             if (canputnext(ppa->q))
1500                 putnext(ppa->q, mp);
1501             else {
1502                 putbq(q, mp);
1503                 break;
1504             }
1505         }
1506     }
1507     return 0;
1508 }
1509
1510 static int
1511 putctl2(q, type, code, val)
1512     queue_t *q;
1513     int type, code, val;
1514 {
1515     mblk_t *mp;
1516
1517     mp = allocb(2, BPRI_HI);
1518     if (mp == 0)
1519         return 0;
1520     mp->b_datap->db_type = type;
1521     mp->b_wptr[0] = code;
1522     mp->b_wptr[1] = val;
1523     mp->b_wptr += 2;
1524     putnext(q, mp);
1525     return 1;
1526 }
1527
1528 static int
1529 putctl4(q, type, code, val)
1530     queue_t *q;
1531     int type, code, val;
1532 {
1533     mblk_t *mp;
1534
1535     mp = allocb(4, BPRI_HI);
1536     if (mp == 0)
1537         return 0;
1538     mp->b_datap->db_type = type;
1539     mp->b_wptr[0] = code;
1540     ((short *)mp->b_wptr)[1] = val;
1541     mp->b_wptr += 4;
1542     putnext(q, mp);
1543     return 1;
1544 }
1545
1546 static void
1547 debug_dump(q, mp)
1548     queue_t *q;                 /* not used */
1549     mblk_t *mp;                 /* not used either */
1550 {
1551     upperstr_t *us;
1552     queue_t *uq, *lq;
1553
1554     DPRINT("ppp upper streams:\n");
1555     for (us = minor_devs; us != 0; us = us->nextmn) {
1556         uq = us->q;
1557         DPRINT3(" %d: q=%x rlev=%d",
1558                 us->mn, uq, (uq? qsize(uq): 0));
1559         DPRINT3(" wlev=%d flags=0x%b", (uq? qsize(WR(uq)): 0),
1560                 us->flags, "\020\1priv\2control\3blocked\4last");
1561         DPRINT3(" state=%x sap=%x req_sap=%x", us->state, us->sap,
1562                 us->req_sap);
1563         if (us->ppa == 0)
1564             DPRINT(" ppa=?\n");
1565         else
1566             DPRINT1(" ppa=%d\n", us->ppa->ppa_id);
1567         if (us->flags & US_CONTROL) {
1568             lq = us->lowerq;
1569             DPRINT3("    control for %d lq=%x rlev=%d",
1570                     us->ppa_id, lq, (lq? qsize(RD(lq)): 0));
1571             DPRINT3(" wlev=%d mru=%d mtu=%d\n",
1572                     (lq? qsize(lq): 0), us->mru, us->mtu);
1573         }
1574     }
1575 }