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