]> git.ozlabs.org Git - ppp.git/blob - svr4/ppp.c
.
[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.6 1995/06/30 00:54:51 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_PHYS_ADDR_REQ:
826     case DL_SET_PHYS_ADDR_REQ:
827     case DL_XID_REQ:
828     case DL_TEST_REQ:
829     case DL_REPLY_UPDATE_REQ:
830     case DL_REPLY_REQ:
831     case DL_DATA_ACK_REQ:
832 #endif
833     case DL_CONNECT_REQ:
834     case DL_TOKEN_REQ:
835         dlpi_error(q, d->dl_primitive, DL_NOTSUPPORTED, 0);
836         break;
837
838     case DL_CONNECT_RES:
839     case DL_DISCONNECT_REQ:
840     case DL_RESET_REQ:
841     case DL_RESET_RES:
842         dlpi_error(q, d->dl_primitive, DL_OUTSTATE, 0);
843         break;
844
845     case DL_UDQOS_REQ:
846         dlpi_error(q, d->dl_primitive, DL_BADQOSTYPE, 0);
847         break;
848
849 #if DL_CURRENT_VERSION >= 2
850     case DL_TEST_RES:
851     case DL_XID_RES:
852         break;
853 #endif
854
855     default:
856         cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
857         /* fall through */
858     badprim:
859         dlpi_error(q, d->dl_primitive, DL_BADPRIM, 0);
860         break;
861     }
862     freemsg(mp);
863 }
864
865 static void
866 dlpi_error(q, prim, err, uerr)
867     queue_t *q;
868     int prim, err, uerr;
869 {
870     mblk_t *reply;
871     dl_error_ack_t *errp;
872
873     reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
874     if (reply == 0)
875         return;                 /* XXX should do bufcall */
876     reply->b_datap->db_type = M_PCPROTO;
877     errp = (dl_error_ack_t *) reply->b_wptr;
878     reply->b_wptr += sizeof(dl_error_ack_t);
879     errp->dl_primitive = DL_ERROR_ACK;
880     errp->dl_error_primitive = prim;
881     errp->dl_errno = err;
882     errp->dl_unix_errno = uerr;
883     qreply(q, reply);
884 }
885
886 static void
887 dlpi_ok(q, prim)
888     queue_t *q;
889     int prim;
890 {
891     mblk_t *reply;
892     dl_ok_ack_t *okp;
893
894     reply = allocb(sizeof(dl_ok_ack_t), BPRI_HI);
895     if (reply == 0)
896         return;                 /* XXX should do bufcall */
897     reply->b_datap->db_type = M_PCPROTO;
898     okp = (dl_ok_ack_t *) reply->b_wptr;
899     reply->b_wptr += sizeof(dl_ok_ack_t);
900     okp->dl_primitive = DL_OK_ACK;
901     okp->dl_correct_primitive = prim;
902     qreply(q, reply);
903 }
904
905 static int
906 send_data(mp, us)
907     mblk_t *mp;
908     upperstr_t *us;
909 {
910     queue_t *q;
911     upperstr_t *ppa;
912
913     if (us->flags & US_BLOCKED)
914         return 0;
915     ppa = us->ppa;
916     if (ppa == 0) {
917         freemsg(mp);
918         return 1;
919     }
920     if ((q = ppa->lowerq) == 0) {
921         /* try to send it up the control stream */
922         if (canputnext(ppa->q)) {
923             putnext(ppa->q, mp);
924             return 1;
925         }
926     } else {
927         if (canputnext(ppa->lowerq)) {
928             /*
929              * The lower write queue's put procedure just updates counters
930              * and does a putnext.  We call it in order to enter the lower
931              * queues' perimeter so that the counter updates are serialized.
932              */
933             put(ppa->lowerq, mp);
934             return 1;
935         }
936     }
937     us->flags |= US_BLOCKED;
938     return 0;
939 }
940
941 /*
942  * Allocate a new PPA id and link this stream into the list of PPAs.
943  * This procedure is called with an exclusive lock on all queues in
944  * this driver.
945  */
946 static void
947 new_ppa(q, mp)
948     queue_t *q;
949     mblk_t *mp;
950 {
951     upperstr_t *us, **usp;
952     int ppa_id;
953
954     usp = &ppas;
955     ppa_id = 0;
956     while ((us = *usp) != 0 && ppa_id == us->ppa_id) {
957         ++ppa_id;
958         usp = &us->nextppa;
959     }
960     us = (upperstr_t *) q->q_ptr;
961     us->ppa_id = ppa_id;
962     us->ppa = us;
963     us->next = 0;
964     us->nextppa = *usp;
965     *usp = us;
966     us->flags |= US_CONTROL;
967
968     us->mtu = PPP_MRU;
969     us->mru = PPP_MRU;
970
971 #ifdef sun
972     if (us->kstats == 0) {
973         char unit[32];
974
975         sprintf(unit, "ppp%d", us->ppa->ppa_id);
976         us->kstats = kstat_create("ppp", us->ppa->ppa_id, unit,
977                                   "net", KSTAT_TYPE_NAMED, 4, 0);
978         if (us->kstats != 0) {
979             kstat_named_t *kn = KSTAT_NAMED_PTR(us->kstats);
980
981             strcpy(kn[0].name, "ipackets");
982             kn[0].data_type = KSTAT_DATA_ULONG;
983             strcpy(kn[1].name, "ierrors");
984             kn[1].data_type = KSTAT_DATA_ULONG;
985             strcpy(kn[2].name, "opackets");
986             kn[2].data_type = KSTAT_DATA_ULONG;
987             strcpy(kn[3].name, "oerrors");
988             kn[3].data_type = KSTAT_DATA_ULONG;
989             kstat_install(us->kstats);
990         }
991     }
992 #endif
993
994     *(int *)mp->b_cont->b_rptr = ppa_id;
995     mp->b_datap->db_type = M_IOCACK;
996     qreply(q, mp);
997 }
998
999 static void
1000 attach_ppa(q, mp)
1001     queue_t *q;
1002     mblk_t *mp;
1003 {
1004     upperstr_t *us, *t;
1005
1006     us = (upperstr_t *) q->q_ptr;
1007     us->state = DL_UNBOUND;
1008     for (t = us->ppa; t->next != 0; t = t->next)
1009         ;
1010     t->next = us;
1011     us->next = 0;
1012     if (mp->b_datap->db_type == M_IOCTL) {
1013         mp->b_datap->db_type = M_IOCACK;
1014         qreply(q, mp);
1015     } else {
1016         dlpi_ok(q, DL_ATTACH_REQ);
1017     }
1018 }
1019
1020 static void
1021 detach_ppa(q, mp)
1022     queue_t *q;
1023     mblk_t *mp;
1024 {
1025     upperstr_t *us, *t;
1026
1027     us = (upperstr_t *) q->q_ptr;
1028     for (t = us->ppa; t->next != 0; t = t->next)
1029         if (t->next == us) {
1030             t->next = us->next;
1031             break;
1032         }
1033     us->next = 0;
1034     us->ppa = 0;
1035     us->state = DL_UNATTACHED;
1036     dlpi_ok(q, DL_DETACH_REQ);
1037 }
1038
1039 static int
1040 pppuwsrv(q)
1041     queue_t *q;
1042 {
1043     upperstr_t *us;
1044     struct lowerstr *ls;
1045     queue_t *lwq;
1046     mblk_t *mp;
1047
1048     us = (upperstr_t *) q->q_ptr;
1049     us->flags &= ~US_BLOCKED;
1050     while ((mp = getq(q)) != 0) {
1051         if (!send_data(mp, us)) {
1052             putbq(q, mp);
1053             break;
1054         }
1055     }
1056     return 0;
1057 }
1058
1059 static int
1060 ppplwput(q, mp)
1061     queue_t *q;
1062     mblk_t *mp;
1063 {
1064     upperstr_t *ppa;
1065
1066     ppa = q->q_ptr;
1067     if (ppa != 0) {             /* why wouldn't it? */
1068         ppa->stats.ppp_opackets++;
1069         ppa->stats.ppp_obytes += msgdsize(mp);
1070 #ifdef sun
1071         if (ppa->kstats != 0)
1072             KSTAT_NAMED_PTR(ppa->kstats)[2].value.ul++;
1073 #endif
1074     }
1075     putnext(q, mp);
1076     return 0;
1077 }
1078
1079 static int
1080 ppplwsrv(q)
1081     queue_t *q;
1082 {
1083     upperstr_t *us;
1084
1085     /*
1086      * Flow control has back-enabled this stream:
1087      * enable the write service procedures of all upper
1088      * streams feeding this lower stream.
1089      */
1090     for (us = (upperstr_t *) q->q_ptr; us != NULL; us = us->next)
1091         if (us->flags & US_BLOCKED)
1092             qenable(WR(us->q));
1093     return 0;
1094 }
1095
1096 static int
1097 pppursrv(q)
1098     queue_t *q;
1099 {
1100     upperstr_t *us, *as;
1101     mblk_t *mp, *hdr;
1102     dl_unitdata_ind_t *ud;
1103     int proto;
1104
1105     us = (upperstr_t *) q->q_ptr;
1106     if (us->flags & US_CONTROL) {
1107         /*
1108          * A control stream.
1109          * If there is no lower queue attached, run the write service
1110          * routines of other upper streams attached to this PPA.
1111          */
1112         if (us->lowerq == 0) {
1113             as = us;
1114             do {
1115                 if (as->flags & US_BLOCKED)
1116                     qenable(WR(as->q));
1117                 as = as->next;
1118             } while (as != 0);
1119         }
1120     } else {
1121         /*
1122          * A network protocol stream.  Put a DLPI header on each
1123          * packet and send it on.
1124          * (Actually, it seems that the IP module will happily
1125          * accept M_DATA messages without the DL_UNITDATA_IND header.)
1126          */
1127         while ((mp = getq(q)) != 0) {
1128             if (!canputnext(q)) {
1129                 putbq(q, mp);
1130                 break;
1131             }
1132             proto = PPP_PROTOCOL(mp->b_rptr);
1133             mp->b_rptr += PPP_HDRLEN;
1134             hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong),
1135                          BPRI_MED);
1136             if (hdr == 0) {
1137                 /* XXX should put it back and use bufcall */
1138                 freemsg(mp);
1139                 continue;
1140             }
1141             hdr->b_datap->db_type = M_PROTO;
1142             ud = (dl_unitdata_ind_t *) hdr->b_wptr;
1143             hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong);
1144             hdr->b_cont = mp;
1145             ud->dl_primitive = DL_UNITDATA_IND;
1146             ud->dl_dest_addr_length = sizeof(ulong);
1147             ud->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
1148             ud->dl_src_addr_length = sizeof(ulong);
1149             ud->dl_src_addr_offset = ud->dl_dest_addr_offset + sizeof(ulong);
1150 #if DL_CURRENT_VERSION >= 2
1151             ud->dl_group_address = 0;
1152 #endif
1153             /* Send the DLPI client the data with the SAP they requested,
1154                (e.g. ETHERTYPE_IP) rather than the PPP protocol number
1155                (e.g. PPP_IP) */
1156             ((ulong *)(ud + 1))[0] = us->req_sap;       /* dest SAP */
1157             ((ulong *)(ud + 1))[1] = us->req_sap;       /* src SAP */
1158             putnext(q, hdr);
1159         }
1160     }
1161
1162     /*
1163      * If this stream is attached to a PPA with a lower queue pair,
1164      * enable the read queue's service routine if it has data queued.
1165      * XXX there is a possibility that packets could get out of order
1166      * if ppplrput now runs before ppplrsrv.
1167      */
1168     if (us->ppa != 0 && us->ppa->lowerq != 0)
1169         qenable(RD(us->ppa->lowerq));
1170
1171     return 0;
1172 }
1173
1174 static upperstr_t *
1175 find_dest(ppa, proto)
1176     upperstr_t *ppa;
1177     int proto;
1178 {
1179     upperstr_t *us;
1180
1181     for (us = ppa->next; us != 0; us = us->next)
1182         if (proto == us->sap)
1183             break;
1184     return us;
1185 }
1186
1187 static int
1188 ppplrput(q, mp)
1189     queue_t *q;
1190     mblk_t *mp;
1191 {
1192     upperstr_t *ppa, *us;
1193     queue_t *uq;
1194     int proto, len;
1195     mblk_t *np;
1196     struct iocblk *iop;
1197
1198     ppa = (upperstr_t *) q->q_ptr;
1199     if (ppa == 0) {
1200 #if DEBUG
1201         cmn_err(CE_CONT, "ppplrput: q = %x, ppa = 0??\n", q);
1202 #endif
1203         freemsg(mp);
1204         return 0;
1205     }
1206     switch (mp->b_datap->db_type) {
1207     case M_FLUSH:
1208         if (*mp->b_rptr & FLUSHW) {
1209             *mp->b_rptr &= ~FLUSHR;
1210             qreply(q, mp);
1211         } else
1212             freemsg(mp);
1213         break;
1214
1215     case M_CTL:
1216         switch (*mp->b_rptr) {
1217         case PPPCTL_IERROR:
1218 #ifdef sun
1219             if (ppa->kstats != 0) {
1220                 KSTAT_NAMED_PTR(ppa->kstats)[1].value.ul++;
1221             }
1222 #endif
1223             ppa->stats.ppp_ierrors++;
1224             break;
1225         case PPPCTL_OERROR:
1226 #ifdef sun
1227             if (ppa->kstats != 0) {
1228                 KSTAT_NAMED_PTR(ppa->kstats)[3].value.ul++;
1229             }
1230 #endif
1231             ppa->stats.ppp_oerrors++;
1232             break;
1233         }
1234         freemsg(mp);
1235         break;
1236
1237     case M_IOCACK:
1238     case M_IOCNAK:
1239         /*
1240          * Attempt to match up the response with the stream
1241          * that the request came from.
1242          */
1243         iop = (struct iocblk *) mp->b_rptr;
1244         for (us = ppa; us != 0; us = us->next)
1245             if (us->ioc_id == iop->ioc_id)
1246                 break;
1247         if (us == 0)
1248             freemsg(mp);
1249         else
1250             putnext(us->q, mp);
1251         break;
1252
1253     default:
1254         if (mp->b_datap->db_type == M_DATA) {
1255             len = msgdsize(mp);
1256             if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) {
1257                 np = msgpullup(mp, PPP_HDRLEN);
1258                 freemsg(mp);
1259                 if (np == 0) {
1260 #if DEBUG
1261                     cmn_err(CE_CONT, "ppp_lrput: msgpullup failed (len=%d)\n",
1262                             len);
1263 #endif
1264                     break;
1265                 }
1266                 mp = np;
1267             }
1268             ppa->stats.ppp_ipackets++;
1269             ppa->stats.ppp_ibytes += len;
1270 #ifdef sun
1271             if (ppa->kstats != 0) {
1272                 KSTAT_NAMED_PTR(ppa->kstats)[0].value.ul++;
1273             }
1274 #endif
1275             proto = PPP_PROTOCOL(mp->b_rptr);
1276             if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
1277                 /*
1278                  * A data packet for some network protocol.
1279                  * Queue it on the upper stream for that protocol.
1280                  */
1281                 if (canput(us->q))
1282                     putq(us->q, mp);
1283                 else
1284                     putq(q, mp);
1285                 break;
1286             }
1287         }
1288         /*
1289          * A control frame, a frame for an unknown protocol,
1290          * or some other message type.
1291          * Send it up to pppd via the control stream.
1292          */
1293         if (queclass(mp) == QPCTL || canputnext(ppa->q))
1294             putnext(ppa->q, mp);
1295         else
1296             putq(q, mp);
1297         break;
1298     }
1299
1300     return 0;
1301 }
1302
1303 static int
1304 ppplrsrv(q)
1305     queue_t *q;
1306 {
1307     mblk_t *mp;
1308     upperstr_t *ppa, *us;
1309     int proto;
1310
1311     /*
1312      * Packets only get queued here for flow control reasons.
1313      */
1314     ppa = (upperstr_t *) q->q_ptr;
1315     while ((mp = getq(q)) != 0) {
1316         if (mp->b_datap->db_type == M_DATA
1317             && (proto = PPP_PROTOCOL(mp->b_rptr)) < 0x8000
1318             && (us = find_dest(ppa, proto)) != 0) {
1319             if (canput(us->q))
1320                 putq(us->q, mp);
1321             else {
1322                 putbq(q, mp);
1323                 break;
1324             }
1325         } else {
1326             if (canputnext(ppa->q))
1327                 putnext(ppa->q, mp);
1328             else {
1329                 putbq(q, mp);
1330                 break;
1331             }
1332         }
1333     }
1334     return 0;
1335 }
1336
1337 static int
1338 putctl2(q, type, code, val)
1339     queue_t *q;
1340     int type, code, val;
1341 {
1342     mblk_t *mp;
1343
1344     mp = allocb(2, BPRI_HI);
1345     if (mp == 0)
1346         return 0;
1347     mp->b_datap->db_type = type;
1348     mp->b_wptr[0] = code;
1349     mp->b_wptr[1] = val;
1350     mp->b_wptr += 2;
1351     putnext(q, mp);
1352     return 1;
1353 }
1354
1355 static int
1356 putctl4(q, type, code, val)
1357     queue_t *q;
1358     int type, code, val;
1359 {
1360     mblk_t *mp;
1361
1362     mp = allocb(4, BPRI_HI);
1363     if (mp == 0)
1364         return 0;
1365     mp->b_datap->db_type = type;
1366     mp->b_wptr[0] = code;
1367     ((short *)mp->b_wptr)[1] = val;
1368     mp->b_wptr += 4;
1369     putnext(q, mp);
1370     return 1;
1371 }
1372
1373 static void
1374 debug_dump(q, mp)
1375     queue_t *q;                 /* not used */
1376     mblk_t *mp;                 /* not used either */
1377 {
1378     upperstr_t *us;
1379     queue_t *uq, *lq;
1380
1381     cmn_err(CE_CONT, "ppp upper streams:\n");
1382     for (us = minor_devs; us != 0; us = us->nextmn) {
1383         uq = us->q;
1384         cmn_err(CE_CONT, " %d: q=%x rlev=%d wlev=%d flags=0x%b",
1385                 us->mn, uq, (uq? qsize(uq): 0), (uq? qsize(WR(uq)): 0),
1386                 us->flags, "\020\1priv\2control\3blocked\4last");
1387         cmn_err(CE_CONT, " state=%x sap=%x req_sap=%x", us->state, us->sap,
1388                 us->req_sap);
1389         if (us->ppa == 0)
1390             cmn_err(CE_CONT, " ppa=?\n");
1391         else
1392             cmn_err(CE_CONT, " ppa=%d\n", us->ppa->ppa_id);
1393         if (us->flags & US_CONTROL) {
1394             lq = us->lowerq;
1395             cmn_err(CE_CONT, "    control for %d lq=%x rlev=%d wlev=%d",
1396                     us->ppa_id, lq, (lq? qsize(RD(lq)): 0),
1397                     (lq? qsize(lq): 0));
1398             cmn_err(CE_CONT, " mru=%d mtu=%d\n", us->mru, us->mtu);
1399         }
1400     }
1401 }