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