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