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