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