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