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