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