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