]> git.ozlabs.org Git - ppp.git/blob - modules/ppp.c
571d95bd3358daf138e97fc24b7586d8e3464ba3
[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.5 1996/05/28 00:56:18 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     int len;
419
420     us = (upperstr_t *) q->q_ptr;
421     switch (mp->b_datap->db_type) {
422 #ifndef NO_DLPI
423     case M_PCPROTO:
424     case M_PROTO:
425         dlpi_request(q, mp, us);
426         break;
427 #endif /* NO_DLPI */
428
429     case M_DATA:
430         if (us->flags & US_DBGLOG)
431             DPRINT3("ppp/%d: uwput M_DATA len=%d flags=%x\n",
432                     us->mn, msgdsize(mp), us->flags);
433         if (us->ppa == 0 || msgdsize(mp) > us->ppa->mtu + PPP_HDRLEN
434 #ifndef NO_DLPI
435             || (us->flags & US_CONTROL) == 0
436 #endif /* NO_DLPI */
437             ) {
438             DPRINT1("pppuwput: junk data len=%d\n", msgdsize(mp));
439             freemsg(mp);
440             break;
441         }
442 #ifdef NO_DLPI
443         if (!pass_packet(us->ppa, mp, 1)) {
444             freemsg(mp);
445             break;
446         }
447 #endif
448         if (!send_data(mp, us))
449             putq(q, mp);
450         break;
451
452     case M_IOCTL:
453         iop = (struct iocblk *) mp->b_rptr;
454         error = EINVAL;
455         if (us->flags & US_DBGLOG)
456             DPRINT3("ppp/%d: ioctl %x count=%d\n",
457                     us->mn, iop->ioc_cmd, iop->ioc_count);
458         switch (iop->ioc_cmd) {
459         case I_LINK:
460             if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
461                 break;
462             lb = (struct linkblk *) mp->b_cont->b_rptr;
463             us->lowerq = lq = lb->l_qbot;
464             lq->q_ptr = (caddr_t) us;
465             RD(lq)->q_ptr = (caddr_t) us;
466             noenable(RD(lq));
467             flushq(RD(lq), FLUSHALL);
468             iop->ioc_count = 0;
469             error = 0;
470             us->flags &= ~US_LASTMOD;
471             /* Unblock upper streams which now feed this lower stream. */
472             qenable(lq);
473             /* Send useful information down to the modules which
474                are now linked below us. */
475             putctl2(lq, M_CTL, PPPCTL_UNIT, us->ppa_id);
476             putctl4(lq, M_CTL, PPPCTL_MRU, us->mru);
477             putctl4(lq, M_CTL, PPPCTL_MTU, us->mtu);
478             break;
479
480         case I_UNLINK:
481             lb = (struct linkblk *) mp->b_cont->b_rptr;
482 #if DEBUG
483             if (us->lowerq != lb->l_qbot)
484                 DPRINT2("ppp unlink: lowerq=%x qbot=%x\n",
485                         us->lowerq, lb->l_qbot);
486 #endif
487             us->lowerq = 0;
488             iop->ioc_count = 0;
489             error = 0;
490             /* Unblock streams which now feed back up the control stream. */
491             qenable(us->q);
492             break;
493
494         case PPPIO_NEWPPA:
495             if (us->flags & US_CONTROL)
496                 break;
497             if ((us->flags & US_PRIV) == 0) {
498                 error = EPERM;
499                 break;
500             }
501             /* Arrange to return an int */
502             if ((mq = mp->b_cont) == 0
503                 || mq->b_datap->db_lim - mq->b_rptr < sizeof(int)) {
504                 mq = allocb(sizeof(int), BPRI_HI);
505                 if (mq == 0) {
506                     error = ENOSR;
507                     break;
508                 }
509                 if (mp->b_cont != 0)
510                     freemsg(mp->b_cont);
511                 mp->b_cont = mq;
512                 mq->b_cont = 0;
513             }
514             iop->ioc_count = sizeof(int);
515             mq->b_wptr = mq->b_rptr + sizeof(int);
516             qwriter(q, mp, new_ppa, PERIM_OUTER);
517             error = -1;
518             break;
519
520         case PPPIO_ATTACH:
521             /* like dlpi_attach, for programs which can't write to
522                the stream (like pppstats) */
523             if (iop->ioc_count != sizeof(int) || us->ppa != 0)
524                 break;
525             n = *(int *)mp->b_cont->b_rptr;
526             for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
527                 if (ppa->ppa_id == n)
528                     break;
529             if (ppa == 0)
530                 break;
531             us->ppa = ppa;
532             iop->ioc_count = 0;
533             qwriter(q, mp, attach_ppa, PERIM_OUTER);
534             error = -1;
535             break;
536
537 #ifdef NO_DLPI
538         case PPPIO_BIND:
539             /* Attach to a given SAP. */
540             if (iop->ioc_count != sizeof(int) || us->ppa == 0)
541                 break;
542             n = *(int *)mp->b_cont->b_rptr;
543             /* n must be a valid PPP network protocol number. */
544             if (n < 0x21 || n > 0x3fff || (n & 0x101) != 1)
545                 break;
546             /* check that no other stream is bound to this sap already. */
547             for (os = us->ppa; os != 0; os = os->next)
548                 if (os->sap == n)
549                     break;
550             if (os != 0)
551                 break;
552             us->sap = n;
553             iop->ioc_count = 0;
554             error = 0;
555             break;
556 #endif /* NO_DLPI */
557
558         case PPPIO_MRU:
559             if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
560                 break;
561             n = *(int *)mp->b_cont->b_rptr;
562             if (n <= 0 || n > PPP_MAXMTU)
563                 break;
564             if (n < PPP_MRU)
565                 n = PPP_MRU;
566             us->mru = n;
567             if (us->lowerq)
568                 putctl4(us->lowerq, M_CTL, PPPCTL_MRU, n);
569             error = 0;
570             iop->ioc_count = 0;
571             break;
572
573         case PPPIO_MTU:
574             if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
575                 break;
576             n = *(int *)mp->b_cont->b_rptr;
577             if (n <= 0 || n > PPP_MAXMTU)
578                 break;
579             if (n < PPP_MRU)
580                 n = PPP_MRU;
581             us->mtu = n;
582 #ifdef LACHTCP
583             us->ifstats.ifs_mtu = n;
584 #endif
585             if (us->lowerq)
586                 putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n);
587             error = 0;
588             iop->ioc_count = 0;
589             break;
590
591         case PPPIO_LASTMOD:
592             us->flags |= US_LASTMOD;
593             error = 0;
594             break;
595
596         case PPPIO_DEBUG:
597             if (iop->ioc_count != sizeof(int))
598                 break;
599             n = *(int *)mp->b_cont->b_rptr;
600             if (n == PPPDBG_DUMP + PPPDBG_DRIVER) {
601                 qwriter(q, NULL, debug_dump, PERIM_OUTER);
602                 iop->ioc_count = 0;
603                 error = 0;
604             } else if (n == PPPDBG_LOG + PPPDBG_DRIVER) {
605                 DPRINT1("ppp/%d: debug log enabled\n", us->mn);
606                 us->flags |= US_DBGLOG;
607                 iop->ioc_count = 0;
608                 error = 0;
609             } else {
610                 if (us->ppa == 0 || us->ppa->lowerq == 0)
611                     break;
612                 putnext(us->ppa->lowerq, mp);
613                 error = -1;
614             }
615             break;
616
617         case PPPIO_NPMODE:
618             if (iop->ioc_count != 2 * sizeof(int))
619                 break;
620             if ((us->flags & US_CONTROL) == 0)
621                 break;
622             sap = ((int *)mp->b_cont->b_rptr)[0];
623             for (nps = us->next; nps != 0; nps = nps->next)
624                 if (nps->sap == sap)
625                     break;
626             if (nps == 0) {
627                 if (us->flags & US_DBGLOG)
628                     DPRINT2("ppp/%d: no stream for sap %x\n", us->mn, sap);
629                 break;
630             }
631             nps->npmode = (enum NPmode) ((int *)mp->b_cont->b_rptr)[1];
632             if (nps->npmode == NPMODE_DROP || nps->npmode == NPMODE_ERROR)
633                 flushq(WR(nps->q), FLUSHDATA);
634             else if (nps->npmode == NPMODE_PASS && qsize(WR(nps->q)) > 0
635                      && (nps->flags & US_BLOCKED) == 0)
636                 qenable(WR(nps->q));
637             iop->ioc_count = 0;
638             error = 0;
639             break;
640
641         case PPPIO_GIDLE:
642             if ((ppa = us->ppa) == 0)
643                 break;
644             mq = allocb(sizeof(struct ppp_idle), BPRI_HI);
645             if (mq == 0) {
646                 error = ENOSR;
647                 break;
648             }
649             if (mp->b_cont != 0)
650                 freemsg(mp->b_cont);
651             mp->b_cont = mq;
652             mq->b_cont = 0;
653             pip = (struct ppp_idle *) mq->b_wptr;
654             pip->xmit_idle = time - ppa->last_sent;
655             pip->recv_idle = time - ppa->last_recv;
656             mq->b_wptr += sizeof(struct ppp_idle);
657             iop->ioc_count = sizeof(struct ppp_idle);
658             error = 0;
659             break;
660
661 #ifdef LACHTCP
662         case SIOCSIFNAME:
663             printf("SIOCSIFNAME\n");
664             /* Sent from IP down to us.  Attach the ifstats structure.  */
665             if (iop->ioc_count != sizeof(struct ifreq) || us->ppa == 0)
666                 break;
667             ifr = (struct ifreq *)mp->b_cont->b_rptr;
668             /* Find the unit number in the interface name.  */
669             for (i = 0; i < IFNAMSIZ; i++) {
670                 if (ifr->ifr_name[i] == 0 ||
671                     (ifr->ifr_name[i] >= '0' &&
672                      ifr->ifr_name[i] <= '9'))
673                     break;
674                 else
675                     us->ifname[i] = ifr->ifr_name[i];
676             }
677             us->ifname[i] = 0;
678
679             /* Convert the unit number to binary.  */
680             for (n = 0; i < IFNAMSIZ; i++) {
681                 if (ifr->ifr_name[i] == 0) {
682                     break;
683                 }
684                 else {
685                     n = n * 10 + ifr->ifr_name[i] - '0';
686                 }
687             }
688
689             /* Verify the ppa.  */
690             if (us->ppa->ppa_id != n)
691                 break;
692             ppa = us->ppa;
693
694             /* Set up the netstat block.  */
695             strncpy (ppa->ifname, us->ifname, IFNAMSIZ);
696
697             ppa->ifstats.ifs_name = ppa->ifname;
698             ppa->ifstats.ifs_unit = n;
699             ppa->ifstats.ifs_active = us->state != DL_UNBOUND;
700             ppa->ifstats.ifs_mtu = ppa->mtu;
701
702             /* Link in statistics used by netstat.  */
703             ppa->ifstats.ifs_next = ifstats;
704             ifstats = &ppa->ifstats;
705
706             iop->ioc_count = 0;
707             error = 0;
708             break;
709
710         case SIOCGIFFLAGS:
711             printf("SIOCGIFFLAGS\n");
712             if (!(us->flags & US_CONTROL)) {
713                 if (us->ppa)
714                     us = us->ppa;
715                 else
716                     break;
717             }
718             ((struct iocblk_in *)iop)->ioc_ifflags = us->ifflags;
719             error = 0;
720             break;
721
722         case SIOCSIFFLAGS:
723             printf("SIOCSIFFLAGS\n");
724             if (!(us->flags & US_CONTROL)) {
725                 if (us->ppa)
726                     us = us->ppa;
727                 else
728                     break;
729             }
730             us->ifflags = ((struct iocblk_in *)iop)->ioc_ifflags;
731             error = 0;
732             break;
733
734         case SIOCSIFADDR:
735             printf("SIOCSIFADDR\n");
736             if (!(us->flags & US_CONTROL)) {
737                 if (us->ppa)
738                     us = us->ppa;
739                 else
740                     break;
741             }
742             us->ifflags |= IFF_RUNNING;
743             ((struct iocblk_in *)iop)->ioc_ifflags |= IFF_RUNNING;
744             error = 0;
745             break;
746
747         case SIOCGIFNETMASK:
748         case SIOCSIFNETMASK:
749         case SIOCGIFADDR:
750         case SIOCGIFDSTADDR:
751         case SIOCSIFDSTADDR:
752         case SIOCGIFMETRIC:
753             error = 0;
754             break;
755 #endif /* LACHTCP */
756
757         default:
758             if (us->ppa == 0 || us->ppa->lowerq == 0)
759                 break;
760             us->ioc_id = iop->ioc_id;
761             error = -1;
762             switch (iop->ioc_cmd) {
763             case PPPIO_GETSTAT:
764             case PPPIO_GETCSTAT:
765                 if (us->flags & US_LASTMOD) {
766                     error = EINVAL;
767                     break;
768                 }
769                 putnext(us->ppa->lowerq, mp);
770                 break;
771             default:
772                 if (us->flags & US_PRIV)
773                     putnext(us->ppa->lowerq, mp);
774                 else {
775                     DPRINT1("ppp ioctl %x rejected\n", iop->ioc_cmd);
776                     error = EPERM;
777                 }
778                 break;
779             }
780             break;
781         }
782
783         if (error > 0) {
784             iop->ioc_error = error;
785             mp->b_datap->db_type = M_IOCNAK;
786             qreply(q, mp);
787         } else if (error == 0) {
788             mp->b_datap->db_type = M_IOCACK;
789             qreply(q, mp);
790         }
791         break;
792
793     case M_FLUSH:
794         if (us->flags & US_DBGLOG)
795             DPRINT2("ppp/%d: flush %x\n", us->mn, *mp->b_rptr);
796         if (*mp->b_rptr & FLUSHW)
797             flushq(q, FLUSHDATA);
798         if (*mp->b_rptr & FLUSHR) {
799             *mp->b_rptr &= ~FLUSHW;
800             qreply(q, mp);
801         } else
802             freemsg(mp);
803         break;
804
805     default:
806         freemsg(mp);
807         break;
808     }
809     return 0;
810 }
811
812 #ifndef NO_DLPI
813 static void
814 dlpi_request(q, mp, us)
815     queue_t *q;
816     mblk_t *mp;
817     upperstr_t *us;
818 {
819     union DL_primitives *d = (union DL_primitives *) mp->b_rptr;
820     int size = mp->b_wptr - mp->b_rptr;
821     mblk_t *reply, *np;
822     upperstr_t *ppa, *os;
823     int sap, *ip, len;
824     dl_info_ack_t *info;
825     dl_bind_ack_t *ackp;
826
827     if (us->flags & US_DBGLOG)
828         DPRINT3("ppp/%d: dlpi prim %x len=%d\n", us->mn,
829                 d->dl_primitive, size);
830     switch (d->dl_primitive) {
831     case DL_INFO_REQ:
832         if (size < sizeof(dl_info_req_t))
833             goto badprim;
834         if ((reply = allocb(sizeof(dl_info_ack_t), BPRI_HI)) == 0)
835             break;              /* should do bufcall */
836         reply->b_datap->db_type = M_PCPROTO;
837         info = (dl_info_ack_t *) reply->b_wptr;
838         reply->b_wptr += sizeof(dl_info_ack_t);
839         bzero((caddr_t) info, sizeof(dl_info_ack_t));
840         info->dl_primitive = DL_INFO_ACK;
841         info->dl_max_sdu = PPP_MAXMTU;
842         info->dl_min_sdu = 1;
843         info->dl_addr_length = sizeof(ulong);
844 #ifdef DL_OTHER
845         info->dl_mac_type = DL_OTHER;
846 #else
847         info->dl_mac_type = DL_HDLC;    /* a lie */
848 #endif
849         info->dl_current_state = us->state;
850         info->dl_service_mode = DL_CLDLS;
851         info->dl_provider_style = DL_STYLE2;
852 #if DL_CURRENT_VERSION >= 2
853         info->dl_sap_length = sizeof(ulong);
854         info->dl_version = DL_CURRENT_VERSION;
855 #endif
856         qreply(q, reply);
857         break;
858
859     case DL_ATTACH_REQ:
860         if (size < sizeof(dl_attach_req_t))
861             goto badprim;
862         if (us->state != DL_UNATTACHED || us->ppa != 0) {
863             dlpi_error(q, DL_ATTACH_REQ, DL_OUTSTATE, 0);
864             break;
865         }
866         for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
867             if (ppa->ppa_id == d->attach_req.dl_ppa)
868                 break;
869         if (ppa == 0) {
870             dlpi_error(q, DL_ATTACH_REQ, DL_BADPPA, 0);
871             break;
872         }
873         us->ppa = ppa;
874         qwriter(q, mp, attach_ppa, PERIM_OUTER);
875         break;
876
877     case DL_DETACH_REQ:
878         if (size < sizeof(dl_detach_req_t))
879             goto badprim;
880         if (us->state != DL_UNBOUND || us->ppa == 0) {
881             dlpi_error(q, DL_DETACH_REQ, DL_OUTSTATE, 0);
882             break;
883         }
884         qwriter(q, mp, detach_ppa, PERIM_OUTER);
885         break;
886
887     case DL_BIND_REQ:
888         if (size < sizeof(dl_bind_req_t))
889             goto badprim;
890         if (us->state != DL_UNBOUND || us->ppa == 0) {
891             dlpi_error(q, DL_BIND_REQ, DL_OUTSTATE, 0);
892             break;
893         }
894         if (d->bind_req.dl_service_mode != DL_CLDLS) {
895             dlpi_error(q, DL_BIND_REQ, DL_UNSUPPORTED, 0);
896             break;
897         }
898
899         /* saps must be valid PPP network protocol numbers,
900            except that we accept ETHERTYPE_IP in place of PPP_IP. */
901         sap = d->bind_req.dl_sap;
902         us->req_sap = sap;
903         DPRINT1("ppp bind %x\n", sap);
904         if (sap == ETHERTYPE_IP)
905             sap = PPP_IP;
906         if (sap < 0x21 || sap > 0x3fff || (sap & 0x101) != 1) {
907             dlpi_error(q, DL_BIND_REQ, DL_BADADDR, 0);
908             break;
909         }
910
911         /* check that no other stream is bound to this sap already. */
912         for (os = us->ppa; os != 0; os = os->next)
913             if (os->sap == sap)
914                 break;
915         if (os != 0) {
916             dlpi_error(q, DL_BIND_REQ, DL_NOADDR, 0);
917             break;
918         }
919
920         us->sap = sap;
921         us->state = DL_IDLE;
922
923         if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(ulong),
924                             BPRI_HI)) == 0)
925             break;              /* should do bufcall */
926         ackp = (dl_bind_ack_t *) reply->b_wptr;
927         reply->b_wptr += sizeof(dl_bind_ack_t) + sizeof(ulong);
928         reply->b_datap->db_type = M_PCPROTO;
929         bzero((caddr_t) ackp, sizeof(dl_bind_ack_t));
930         ackp->dl_primitive = DL_BIND_ACK;
931         ackp->dl_sap = sap;
932         ackp->dl_addr_length = sizeof(ulong);
933         ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
934         *(ulong *)(ackp+1) = sap;
935         qreply(q, reply);
936         break;
937
938     case DL_UNBIND_REQ:
939         if (size < sizeof(dl_unbind_req_t))
940             goto badprim;
941         if (us->state != DL_IDLE) {
942             dlpi_error(q, DL_UNBIND_REQ, DL_OUTSTATE, 0);
943             break;
944         }
945         us->sap = -1;
946         us->state = DL_UNBOUND;
947 #ifdef LACHTCP
948         us->ppa->ifstats.ifs_active = 0;
949 #endif
950         dlpi_ok(q, DL_UNBIND_REQ);
951         break;
952
953     case DL_UNITDATA_REQ:
954         if (size < sizeof(dl_unitdata_req_t))
955             goto badprim;
956         if (us->state != DL_IDLE) {
957             dlpi_error(q, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
958             break;
959         }
960         if ((ppa = us->ppa) == 0) {
961             cmn_err(CE_CONT, "ppp: in state dl_idle but ppa == 0?\n");
962             break;
963         }
964         len = mp->b_cont == 0? 0: msgdsize(mp->b_cont);
965         if (len > ppa->mtu) {
966             DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->mtu);
967             break;
968         }
969         /* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */
970         if (mp->b_datap->db_ref > 1) {
971             np = allocb(PPP_HDRLEN, BPRI_HI);
972             if (np == 0)
973                 break;          /* gak! */
974             np->b_cont = mp->b_cont;
975             mp->b_cont = 0;
976             freeb(mp);
977             mp = np;
978         } else
979             mp->b_datap->db_type = M_DATA;
980         /* XXX should use dl_dest_addr_offset/length here,
981            but we would have to translate ETHERTYPE_IP -> PPP_IP */
982         mp->b_wptr = mp->b_rptr + PPP_HDRLEN;
983         mp->b_rptr[0] = PPP_ALLSTATIONS;
984         mp->b_rptr[1] = PPP_UI;
985         mp->b_rptr[2] = us->sap >> 8;
986         mp->b_rptr[3] = us->sap;
987         if (!pass_packet(ppa, mp, 1)) {
988             freemsg(mp);
989         } else {
990             if (!send_data(mp, us))
991                 putq(q, mp);
992         }
993         return;
994
995 #if DL_CURRENT_VERSION >= 2
996     case DL_SUBS_BIND_REQ:
997     case DL_SUBS_UNBIND_REQ:
998     case DL_ENABMULTI_REQ:
999     case DL_DISABMULTI_REQ:
1000     case DL_PROMISCON_REQ:
1001     case DL_PROMISCOFF_REQ:
1002     case DL_PHYS_ADDR_REQ:
1003     case DL_SET_PHYS_ADDR_REQ:
1004     case DL_XID_REQ:
1005     case DL_TEST_REQ:
1006     case DL_REPLY_UPDATE_REQ:
1007     case DL_REPLY_REQ:
1008     case DL_DATA_ACK_REQ:
1009 #endif
1010     case DL_CONNECT_REQ:
1011     case DL_TOKEN_REQ:
1012         dlpi_error(q, d->dl_primitive, DL_NOTSUPPORTED, 0);
1013         break;
1014
1015     case DL_CONNECT_RES:
1016     case DL_DISCONNECT_REQ:
1017     case DL_RESET_REQ:
1018     case DL_RESET_RES:
1019         dlpi_error(q, d->dl_primitive, DL_OUTSTATE, 0);
1020         break;
1021
1022     case DL_UDQOS_REQ:
1023         dlpi_error(q, d->dl_primitive, DL_BADQOSTYPE, 0);
1024         break;
1025
1026 #if DL_CURRENT_VERSION >= 2
1027     case DL_TEST_RES:
1028     case DL_XID_RES:
1029         break;
1030 #endif
1031
1032     default:
1033         cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
1034         /* fall through */
1035     badprim:
1036         dlpi_error(q, d->dl_primitive, DL_BADPRIM, 0);
1037         break;
1038     }
1039     freemsg(mp);
1040 }
1041
1042 static void
1043 dlpi_error(q, prim, err, uerr)
1044     queue_t *q;
1045     int prim, err, uerr;
1046 {
1047     mblk_t *reply;
1048     dl_error_ack_t *errp;
1049
1050     reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
1051     if (reply == 0)
1052         return;                 /* XXX should do bufcall */
1053     reply->b_datap->db_type = M_PCPROTO;
1054     errp = (dl_error_ack_t *) reply->b_wptr;
1055     reply->b_wptr += sizeof(dl_error_ack_t);
1056     errp->dl_primitive = DL_ERROR_ACK;
1057     errp->dl_error_primitive = prim;
1058     errp->dl_errno = err;
1059     errp->dl_unix_errno = uerr;
1060     qreply(q, reply);
1061 }
1062
1063 static void
1064 dlpi_ok(q, prim)
1065     queue_t *q;
1066     int prim;
1067 {
1068     mblk_t *reply;
1069     dl_ok_ack_t *okp;
1070
1071     reply = allocb(sizeof(dl_ok_ack_t), BPRI_HI);
1072     if (reply == 0)
1073         return;                 /* XXX should do bufcall */
1074     reply->b_datap->db_type = M_PCPROTO;
1075     okp = (dl_ok_ack_t *) reply->b_wptr;
1076     reply->b_wptr += sizeof(dl_ok_ack_t);
1077     okp->dl_primitive = DL_OK_ACK;
1078     okp->dl_correct_primitive = prim;
1079     qreply(q, reply);
1080 }
1081 #endif /* NO_DLPI */
1082
1083 static int
1084 pass_packet(ppa, mp, outbound)
1085     upperstr_t *ppa;
1086     mblk_t *mp;
1087     int outbound;
1088 {
1089     /*
1090      * Here is where we might, in future, decide whether to pass
1091      * or drop the packet, and whether it counts as link activity.
1092      */
1093     if (outbound)
1094         ppa->last_sent = time;
1095     else
1096         ppa->last_recv = time;
1097     return 1;
1098 }
1099
1100 static int
1101 send_data(mp, us)
1102     mblk_t *mp;
1103     upperstr_t *us;
1104 {
1105     queue_t *q;
1106     upperstr_t *ppa;
1107
1108     if ((us->flags & US_BLOCKED) || us->npmode == NPMODE_QUEUE)
1109         return 0;
1110     ppa = us->ppa;
1111     if (ppa == 0 || us->npmode == NPMODE_DROP || us->npmode == NPMODE_ERROR) {
1112         if (us->flags & US_DBGLOG)
1113             DPRINT2("ppp/%d: dropping pkt (npmode=%d)\n", us->mn, us->npmode);
1114         freemsg(mp);
1115         return 1;
1116     }
1117     if ((q = ppa->lowerq) == 0) {
1118         /* try to send it up the control stream */
1119         if (canputnext(ppa->q)) {
1120             putnext(ppa->q, mp);
1121             return 1;
1122         }
1123     } else {
1124         if (canputnext(ppa->lowerq)) {
1125             /*
1126              * The lower write queue's put procedure just updates counters
1127              * and does a putnext.  We call it so that on SMP systems, we
1128              * enter the lower queues' perimeter so that the counter
1129              * updates are serialized.
1130              */
1131             put(ppa->lowerq, mp);
1132             return 1;
1133         }
1134     }
1135     us->flags |= US_BLOCKED;
1136     return 0;
1137 }
1138
1139 /*
1140  * Allocate a new PPA id and link this stream into the list of PPAs.
1141  * This procedure is called with an exclusive lock on all queues in
1142  * this driver.
1143  */
1144 static void
1145 new_ppa(q, mp)
1146     queue_t *q;
1147     mblk_t *mp;
1148 {
1149     upperstr_t *us, **usp;
1150     int ppa_id;
1151
1152     usp = &ppas;
1153     ppa_id = 0;
1154     while ((us = *usp) != 0 && ppa_id == us->ppa_id) {
1155         ++ppa_id;
1156         usp = &us->nextppa;
1157     }
1158     us = (upperstr_t *) q->q_ptr;
1159     us->ppa_id = ppa_id;
1160     us->ppa = us;
1161     us->next = 0;
1162     us->nextppa = *usp;
1163     *usp = us;
1164     us->flags |= US_CONTROL;
1165     us->npmode = NPMODE_PASS;
1166
1167     us->mtu = PPP_MRU;
1168     us->mru = PPP_MRU;
1169
1170 #ifdef SOL2
1171     /*
1172      * Create a kstats record for our statistics, so netstat -i works.
1173      */
1174     if (us->kstats == 0) {
1175         char unit[32];
1176
1177         sprintf(unit, "ppp%d", us->ppa->ppa_id);
1178         us->kstats = kstat_create("ppp", us->ppa->ppa_id, unit,
1179                                   "net", KSTAT_TYPE_NAMED, 4, 0);
1180         if (us->kstats != 0) {
1181             kstat_named_t *kn = KSTAT_NAMED_PTR(us->kstats);
1182
1183             strcpy(kn[0].name, "ipackets");
1184             kn[0].data_type = KSTAT_DATA_ULONG;
1185             strcpy(kn[1].name, "ierrors");
1186             kn[1].data_type = KSTAT_DATA_ULONG;
1187             strcpy(kn[2].name, "opackets");
1188             kn[2].data_type = KSTAT_DATA_ULONG;
1189             strcpy(kn[3].name, "oerrors");
1190             kn[3].data_type = KSTAT_DATA_ULONG;
1191             kstat_install(us->kstats);
1192         }
1193     }
1194 #endif /* SOL2 */
1195
1196     *(int *)mp->b_cont->b_rptr = ppa_id;
1197     mp->b_datap->db_type = M_IOCACK;
1198     qreply(q, mp);
1199 }
1200
1201 static void
1202 attach_ppa(q, mp)
1203     queue_t *q;
1204     mblk_t *mp;
1205 {
1206     upperstr_t *us, *t;
1207
1208     us = (upperstr_t *) q->q_ptr;
1209 #ifndef NO_DLPI
1210     us->state = DL_UNBOUND;
1211 #endif
1212     for (t = us->ppa; t->next != 0; t = t->next)
1213         ;
1214     t->next = us;
1215     us->next = 0;
1216     if (mp->b_datap->db_type == M_IOCTL) {
1217         mp->b_datap->db_type = M_IOCACK;
1218         qreply(q, mp);
1219     } else {
1220 #ifndef NO_DLPI
1221         dlpi_ok(q, DL_ATTACH_REQ);
1222 #endif
1223     }
1224 }
1225
1226 static void
1227 detach_ppa(q, mp)
1228     queue_t *q;
1229     mblk_t *mp;
1230 {
1231     upperstr_t *us, *t;
1232
1233     us = (upperstr_t *) q->q_ptr;
1234     for (t = us->ppa; t->next != 0; t = t->next)
1235         if (t->next == us) {
1236             t->next = us->next;
1237             break;
1238         }
1239     us->next = 0;
1240     us->ppa = 0;
1241 #ifndef NO_DLPI
1242     us->state = DL_UNATTACHED;
1243     dlpi_ok(q, DL_DETACH_REQ);
1244 #endif
1245 }
1246
1247 static int
1248 pppuwsrv(q)
1249     queue_t *q;
1250 {
1251     upperstr_t *us;
1252     struct lowerstr *ls;
1253     queue_t *lwq;
1254     mblk_t *mp;
1255
1256     us = (upperstr_t *) q->q_ptr;
1257     us->flags &= ~US_BLOCKED;
1258     while ((mp = getq(q)) != 0) {
1259         if (!send_data(mp, us)) {
1260             putbq(q, mp);
1261             break;
1262         }
1263     }
1264     return 0;
1265 }
1266
1267 static int
1268 ppplwput(q, mp)
1269     queue_t *q;
1270     mblk_t *mp;
1271 {
1272     upperstr_t *ppa;
1273
1274     ppa = (upperstr_t *) q->q_ptr;
1275     if (ppa != 0) {             /* why wouldn't it? */
1276         ppa->stats.ppp_opackets++;
1277         ppa->stats.ppp_obytes += msgdsize(mp);
1278 #ifdef INCR_OPACKETS
1279         INCR_OPACKETS(ppa);
1280 #endif
1281     }
1282     putnext(q, mp);
1283     return 0;
1284 }
1285
1286 static int
1287 ppplwsrv(q)
1288     queue_t *q;
1289 {
1290     upperstr_t *us;
1291
1292     /*
1293      * Flow control has back-enabled this stream:
1294      * enable the write service procedures of all upper
1295      * streams feeding this lower stream.
1296      */
1297     for (us = (upperstr_t *) q->q_ptr; us != NULL; us = us->next)
1298         if (us->flags & US_BLOCKED)
1299             qenable(WR(us->q));
1300     return 0;
1301 }
1302
1303 static int
1304 pppursrv(q)
1305     queue_t *q;
1306 {
1307     upperstr_t *us, *as;
1308     mblk_t *mp, *hdr;
1309 #ifndef NO_DLPI
1310     dl_unitdata_ind_t *ud;
1311 #endif
1312     int proto;
1313
1314     us = (upperstr_t *) q->q_ptr;
1315     if (us->flags & US_CONTROL) {
1316         /*
1317          * A control stream.
1318          * If there is no lower queue attached, run the write service
1319          * routines of other upper streams attached to this PPA.
1320          */
1321         if (us->lowerq == 0) {
1322             as = us;
1323             do {
1324                 if (as->flags & US_BLOCKED)
1325                     qenable(WR(as->q));
1326                 as = as->next;
1327             } while (as != 0);
1328         }
1329     } else {
1330         /*
1331          * A network protocol stream.  Put a DLPI header on each
1332          * packet and send it on.
1333          * (Actually, it seems that the IP module will happily
1334          * accept M_DATA messages without the DL_UNITDATA_IND header.)
1335          */
1336         while ((mp = getq(q)) != 0) {
1337             if (!canputnext(q)) {
1338                 putbq(q, mp);
1339                 break;
1340             }
1341 #ifndef NO_DLPI
1342             proto = PPP_PROTOCOL(mp->b_rptr);
1343             mp->b_rptr += PPP_HDRLEN;
1344             hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong),
1345                          BPRI_MED);
1346             if (hdr == 0) {
1347                 /* XXX should put it back and use bufcall */
1348                 freemsg(mp);
1349                 continue;
1350             }
1351             hdr->b_datap->db_type = M_PROTO;
1352             ud = (dl_unitdata_ind_t *) hdr->b_wptr;
1353             hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong);
1354             hdr->b_cont = mp;
1355             ud->dl_primitive = DL_UNITDATA_IND;
1356             ud->dl_dest_addr_length = sizeof(ulong);
1357             ud->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
1358             ud->dl_src_addr_length = sizeof(ulong);
1359             ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(ulong);
1360 #if DL_CURRENT_VERSION >= 2
1361             ud->dl_group_address = 0;
1362 #endif
1363             /* Send the DLPI client the data with the SAP they requested,
1364                (e.g. ETHERTYPE_IP) rather than the PPP protocol number
1365                (e.g. PPP_IP) */
1366             ((ulong *)(ud + 1))[0] = us->req_sap;       /* dest SAP */
1367             ((ulong *)(ud + 1))[1] = us->req_sap;       /* src SAP */
1368             putnext(q, hdr);
1369 #else /* NO_DLPI */
1370             putnext(q, mp);
1371 #endif /* NO_DLPI */
1372         }
1373     }
1374
1375     /*
1376      * If this stream is attached to a PPA with a lower queue pair,
1377      * enable the read queue's service routine if it has data queued.
1378      * XXX there is a possibility that packets could get out of order
1379      * if ppplrput now runs before ppplrsrv.
1380      */
1381     if (us->ppa != 0 && us->ppa->lowerq != 0)
1382         qenable(RD(us->ppa->lowerq));
1383
1384     return 0;
1385 }
1386
1387 static upperstr_t *
1388 find_dest(ppa, proto)
1389     upperstr_t *ppa;
1390     int proto;
1391 {
1392     upperstr_t *us;
1393
1394     for (us = ppa->next; us != 0; us = us->next)
1395         if (proto == us->sap)
1396             break;
1397     return us;
1398 }
1399
1400 static int
1401 ppplrput(q, mp)
1402     queue_t *q;
1403     mblk_t *mp;
1404 {
1405     upperstr_t *ppa, *us;
1406     queue_t *uq;
1407     int proto, len;
1408     mblk_t *np;
1409     struct iocblk *iop;
1410
1411     ppa = (upperstr_t *) q->q_ptr;
1412     if (ppa == 0) {
1413         DPRINT1("ppplrput: q = %x, ppa = 0??\n", q);
1414         freemsg(mp);
1415         return 0;
1416     }
1417     switch (mp->b_datap->db_type) {
1418     case M_FLUSH:
1419         if (*mp->b_rptr & FLUSHW) {
1420             *mp->b_rptr &= ~FLUSHR;
1421             qreply(q, mp);
1422         } else
1423             freemsg(mp);
1424         break;
1425
1426     case M_CTL:
1427         switch (*mp->b_rptr) {
1428         case PPPCTL_IERROR:
1429 #ifdef INCR_IERRORS
1430             INCR_IERRORS(ppa);
1431 #endif
1432             ppa->stats.ppp_ierrors++;
1433             break;
1434         case PPPCTL_OERROR:
1435 #ifdef INCR_OERRORS
1436             INCR_OERRORS(ppa);
1437 #endif
1438             ppa->stats.ppp_oerrors++;
1439             break;
1440         }
1441         freemsg(mp);
1442         break;
1443
1444     case M_IOCACK:
1445     case M_IOCNAK:
1446         /*
1447          * Attempt to match up the response with the stream
1448          * that the request came from.
1449          */
1450         iop = (struct iocblk *) mp->b_rptr;
1451         for (us = ppa; us != 0; us = us->next)
1452             if (us->ioc_id == iop->ioc_id)
1453                 break;
1454         if (us == 0)
1455             freemsg(mp);
1456         else
1457             putnext(us->q, mp);
1458         break;
1459
1460     default:
1461         if (mp->b_datap->db_type == M_DATA) {
1462             len = msgdsize(mp);
1463             if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
1464                 PULLUP(mp, PPP_HDRLEN);
1465                 if (mp == 0) {
1466                     DPRINT1("ppp_lrput: msgpullup failed (len=%d)\n", len);
1467                     break;
1468                 }
1469             }
1470             ppa->stats.ppp_ipackets++;
1471             ppa->stats.ppp_ibytes += len;
1472 #ifdef INCR_IPACKETS
1473             INCR_IPACKETS(ppa);
1474 #endif
1475             if (!pass_packet(ppa, mp, 0)) {
1476                 freemsg(mp);
1477                 break;
1478             }
1479             proto = PPP_PROTOCOL(mp->b_rptr);
1480             if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
1481                 /*
1482                  * A data packet for some network protocol.
1483                  * Queue it on the upper stream for that protocol.
1484                  */
1485                 if (canput(us->q))
1486                     putq(us->q, mp);
1487                 else
1488                     putq(q, mp);
1489                 break;
1490             }
1491         }
1492         /*
1493          * A control frame, a frame for an unknown protocol,
1494          * or some other message type.
1495          * Send it up to pppd via the control stream.
1496          */
1497         if (queclass(mp) == QPCTL || canputnext(ppa->q))
1498             putnext(ppa->q, mp);
1499         else
1500             putq(q, mp);
1501         break;
1502     }
1503
1504     return 0;
1505 }
1506
1507 static int
1508 ppplrsrv(q)
1509     queue_t *q;
1510 {
1511     mblk_t *mp;
1512     upperstr_t *ppa, *us;
1513     int proto;
1514
1515     /*
1516      * Packets only get queued here for flow control reasons.
1517      */
1518     ppa = (upperstr_t *) q->q_ptr;
1519     while ((mp = getq(q)) != 0) {
1520         if (mp->b_datap->db_type == M_DATA
1521             && (proto = PPP_PROTOCOL(mp->b_rptr)) < 0x8000
1522             && (us = find_dest(ppa, proto)) != 0) {
1523             if (canput(us->q))
1524                 putq(us->q, mp);
1525             else {
1526                 putbq(q, mp);
1527                 break;
1528             }
1529         } else {
1530             if (canputnext(ppa->q))
1531                 putnext(ppa->q, mp);
1532             else {
1533                 putbq(q, mp);
1534                 break;
1535             }
1536         }
1537     }
1538     return 0;
1539 }
1540
1541 static int
1542 putctl2(q, type, code, val)
1543     queue_t *q;
1544     int type, code, val;
1545 {
1546     mblk_t *mp;
1547
1548     mp = allocb(2, BPRI_HI);
1549     if (mp == 0)
1550         return 0;
1551     mp->b_datap->db_type = type;
1552     mp->b_wptr[0] = code;
1553     mp->b_wptr[1] = val;
1554     mp->b_wptr += 2;
1555     putnext(q, mp);
1556     return 1;
1557 }
1558
1559 static int
1560 putctl4(q, type, code, val)
1561     queue_t *q;
1562     int type, code, val;
1563 {
1564     mblk_t *mp;
1565
1566     mp = allocb(4, BPRI_HI);
1567     if (mp == 0)
1568         return 0;
1569     mp->b_datap->db_type = type;
1570     mp->b_wptr[0] = code;
1571     ((short *)mp->b_wptr)[1] = val;
1572     mp->b_wptr += 4;
1573     putnext(q, mp);
1574     return 1;
1575 }
1576
1577 static void
1578 debug_dump(q, mp)
1579     queue_t *q;                 /* not used */
1580     mblk_t *mp;                 /* not used either */
1581 {
1582     upperstr_t *us;
1583     queue_t *uq, *lq;
1584
1585     DPRINT("ppp upper streams:\n");
1586     for (us = minor_devs; us != 0; us = us->nextmn) {
1587         uq = us->q;
1588         DPRINT3(" %d: q=%x rlev=%d",
1589                 us->mn, uq, (uq? qsize(uq): 0));
1590         DPRINT3(" wlev=%d flags=0x%b", (uq? qsize(WR(uq)): 0),
1591                 us->flags, "\020\1priv\2control\3blocked\4last");
1592         DPRINT3(" state=%x sap=%x req_sap=%x", us->state, us->sap,
1593                 us->req_sap);
1594         if (us->ppa == 0)
1595             DPRINT(" ppa=?\n");
1596         else
1597             DPRINT1(" ppa=%d\n", us->ppa->ppa_id);
1598         if (us->flags & US_CONTROL) {
1599             lq = us->lowerq;
1600             DPRINT3("    control for %d lq=%x rlev=%d",
1601                     us->ppa_id, lq, (lq? qsize(RD(lq)): 0));
1602             DPRINT3(" wlev=%d mru=%d mtu=%d\n",
1603                     (lq? qsize(lq): 0), us->mru, us->mtu);
1604         }
1605     }
1606 }