2 * ppp.c - STREAMS multiplexing pseudo-device driver for PPP.
4 * Copyright (c) 1994 The Australian National University.
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
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
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,
27 * $Id: ppp.c,v 1.2 1995/05/19 02:17:42 paulus Exp $
31 * This file is used under Solaris 2.
34 #include <sys/types.h>
35 #include <sys/param.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>
44 #include <sys/sunddi.h>
46 #include <sys/ioccom.h>
47 #include <net/ppp_defs.h>
48 #include <net/pppio.h>
57 * The IP module uses this SAP value for IP packets.
60 #define ETHERTYPE_IP 0x800
64 #define PPP_MAXMTU 65535
68 * Private information; one per upper stream.
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 */
80 * There is exactly one control stream for each PPA.
81 * The following fields are only used for control streams.
84 queue_t *lowerq; /* write queue attached below this PPA */
85 struct upperstr *nextppa; /* next control stream */
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 */
95 static void *upper_states;
96 static struct upperstr *ppas;
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));
119 static struct module_info ppp_info = {
120 0xb1a6, "ppp", 0, 512, 512, 128
123 static struct qinit pppurint = {
124 NULL, pppursrv, pppopen, pppclose, NULL, &ppp_info, NULL
127 static struct qinit pppuwint = {
128 pppuwput, pppuwsrv, NULL, NULL, NULL, &ppp_info, NULL
131 static struct qinit ppplrint = {
132 ppplrput, ppplrsrv, NULL, NULL, NULL, &ppp_info, NULL
135 static struct qinit ppplwint = {
136 NULL, ppplwsrv, NULL, NULL, NULL, &ppp_info, NULL
139 static struct streamtab pppinfo = {
140 &pppurint, &pppuwint,
144 static dev_info_t *ppp_dip;
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 */
155 static struct dev_ops ppp_ops = {
156 DEVO_REV, /* devo_rev */
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 */
169 * Module linkage information
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 */
178 static struct modlinkage modlinkage = {
189 error = ddi_soft_state_init(&upper_states, sizeof(struct upperstr), 4);
191 error = mod_install(&modlinkage);
194 ddi_soft_state_fini(&upper_states);
204 error = mod_remove(&modlinkage);
207 ddi_soft_state_fini(&upper_states);
215 return mod_info(&modlinkage, mip);
222 return strcmp(ddi_get_name(dip), "ppp") == 0? DDI_IDENTIFIED:
229 ddi_attach_cmd_t cmd;
232 if (cmd != DDI_ATTACH)
234 if (ddi_create_minor_node(dip, "ppp", S_IFCHR, 0, DDI_PSEUDO, CLONE_DEV)
236 ddi_remove_minor_node(dip, NULL);
245 ddi_detach_cmd_t cmd;
247 ddi_remove_minor_node(dip, NULL);
252 ppp_devinfo(dip, cmd, arg, result)
262 case DDI_INFO_DEVT2DEVINFO:
266 *result = (void *) ppp_dip;
268 case DDI_INFO_DEVT2INSTANCE:
278 pppopen(q, devp, oflag, sflag, credp)
288 return 0; /* device is already open */
290 if (sflag == CLONEOPEN) {
291 for (mn = 0; ddi_get_soft_state(upper_states, mn) != NULL; ++mn)
294 mn = getminor(*devp);
298 * Construct a new minor node.
300 if (ddi_soft_state_zalloc(upper_states, mn) != DDI_SUCCESS)
302 up = ddi_get_soft_state(upper_states, mn);
303 *devp = makedevice(getmajor(*devp), mn);
307 if (drv_priv(credp) == 0)
308 up->flags |= US_PRIV;
309 up->state = DL_UNATTACHED;
323 pppclose(q, flag, credp)
328 struct upperstr *up, **upp;
329 struct upperstr *as, *asnext;
334 up = (struct upperstr *) q->q_ptr;
335 if (up->flags & US_CONTROL) {
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.
342 for (as = up->next; as != 0; as = asnext) {
346 if (as->flags & US_BLOCKED) {
347 as->flags &= ~US_BLOCKED;
348 flushq(WR(as->q), FLUSHDATA);
351 for (upp = &ppas; *upp != 0; upp = &(*upp)->nextppa)
359 * If this stream is attached to a PPA,
360 * remove it from the PPA's list.
362 if ((as = up->ppa) != 0) {
363 for (; as->next != 0; as = as->next)
364 if (as->next == up) {
373 ddi_soft_state_free(upper_states, up->mn);
379 * A message from on high. We do one of three things:
381 * - put the message on the lower write stream
382 * - queue it for our service routine
389 struct upperstr *us, *usnext;
396 us = (struct upperstr *) q->q_ptr;
397 switch (mp->b_datap->db_type) {
400 dlpi_request(q, mp, us);
404 if ((us->flags & US_CONTROL) == 0
405 || msgdsize(mp) > us->mtu + PPP_HDRLEN) {
407 cmn_err(CE_CONT, "pppuwput: junk data len=%d\n", msgdsize(mp));
412 if (!send_data(mp, us))
417 iop = (struct iocblk *) mp->b_rptr;
419 switch (iop->ioc_cmd) {
421 if ((us->flags & US_CONTROL) == 0 || us->lowerq != 0)
423 lb = (struct linkblk *) mp->b_cont->b_rptr;
424 us->lowerq = lq = lb->l_qbot;
429 /* Unblock upper streams which now feed this lower stream. */
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);
439 lb = (struct linkblk *) mp->b_cont->b_rptr;
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);
448 /* Unblock streams which now feed back up the control stream. */
453 if (us->flags & US_CONTROL)
455 if ((us->flags & US_PRIV) == 0) {
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);
472 iop->ioc_count = sizeof(int);
473 mq->b_wptr = mq->b_rptr + sizeof(int);
474 qwriter(q, mp, new_ppa, PERIM_OUTER);
479 if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
481 n = *(int *)mp->b_cont->b_rptr;
482 if (n <= 0 || n > PPP_MAXMTU)
488 putctl4(us->lowerq, M_CTL, PPPCTL_MRU, n);
494 if (iop->ioc_count != sizeof(int) || (us->flags & US_CONTROL) == 0)
496 n = *(int *)mp->b_cont->b_rptr;
497 if (n <= 0 || n > PPP_MAXMTU)
503 putctl4(us->lowerq, M_CTL, PPPCTL_MTU, n);
509 if (us->ppa == 0 || us->ppa->lowerq == 0)
512 switch (iop->ioc_cmd) {
515 putnext(us->ppa->lowerq, mp);
518 if (us->flags & US_PRIV)
519 putnext(us->ppa->lowerq, mp);
521 cmn_err(CE_CONT, "ppp ioctl %x rejected\n", iop->ioc_cmd);
530 iop->ioc_error = error;
531 mp->b_datap->db_type = M_IOCNAK;
533 } else if (error == 0) {
534 mp->b_datap->db_type = M_IOCACK;
540 if (*mp->b_rptr & FLUSHW)
541 flushq(q, FLUSHDATA);
542 if (*mp->b_rptr & FLUSHR) {
543 *mp->b_rptr &= ~FLUSHW;
557 dlpi_request(q, mp, us)
562 union DL_primitives *d = (union DL_primitives *) mp->b_rptr;
563 int size = mp->b_wptr - mp->b_rptr;
565 struct upperstr *t, *ppa;
569 dl_phys_addr_ack_t *adrp;
570 dl_get_statistics_ack_t *statsp;
572 switch (d->dl_primitive) {
574 if (size < sizeof(dl_info_req_t))
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;
596 if (size < sizeof(dl_attach_req_t))
598 if (us->state != DL_UNATTACHED || us->ppa != 0) {
599 dlpi_error(q, DL_ATTACH_REQ, DL_OUTSTATE, 0);
602 for (ppa = ppas; ppa != 0; ppa = ppa->nextppa)
603 if (ppa->ppa_id == d->attach_req.dl_ppa)
606 dlpi_error(q, DL_ATTACH_REQ, DL_BADPPA, 0);
610 us->state = DL_UNBOUND;
611 for (t = ppa; t->next != 0; t = t->next)
615 dlpi_ok(q, DL_ATTACH_REQ);
619 if (size < sizeof(dl_detach_req_t))
621 if (us->state != DL_UNBOUND || us->ppa == 0) {
622 dlpi_error(q, DL_DETACH_REQ, DL_OUTSTATE, 0);
625 for (t = us->ppa; t->next != 0; t = t->next)
632 us->state = DL_UNATTACHED;
633 dlpi_ok(q, DL_DETACH_REQ);
637 if (size < sizeof(dl_bind_req_t))
639 if (us->state != DL_UNBOUND) {
640 dlpi_error(q, DL_BIND_REQ, DL_OUTSTATE, 0);
643 if (d->bind_req.dl_service_mode != DL_CLDLS) {
644 dlpi_error(q, DL_BIND_REQ, DL_UNSUPPORTED, 0);
647 /* saps must be valid PPP network protocol numbers */
648 sap = d->bind_req.dl_sap;
651 cmn_err(CE_CONT, "ppp bind %x\n", sap);
653 if (sap == ETHERTYPE_IP)
655 if (sap < 0x21 || sap > 0x3fff
656 || (sap & 1) == 0 || (sap & 0x100) != 0) {
657 dlpi_error(q, DL_BIND_REQ, DL_BADADDR, 0);
662 if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(ulong),
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;
671 ackp->dl_addr_length = sizeof(ulong);
672 ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
673 *(ulong *)(ackp+1) = sap;
678 if (size < sizeof(dl_unbind_req_t))
680 if (us->state != DL_IDLE) {
681 dlpi_error(q, DL_UNBIND_REQ, DL_OUTSTATE, 0);
685 us->state = DL_UNBOUND;
686 dlpi_ok(q, DL_UNBIND_REQ);
689 case DL_UNITDATA_REQ:
690 if (size < sizeof(dl_unitdata_req_t))
692 if (us->state != DL_IDLE) {
693 dlpi_error(q, DL_UNITDATA_REQ, DL_OUTSTATE, 0);
696 if (mp->b_cont != 0 && us->ppa != 0
697 && msgdsize(mp->b_cont) > us->ppa->mtu) {
699 cmn_err(CE_CONT, "dlpi data too large (%d > %d)\n",
700 msgdsize(mp->b_cont), us->mtu);
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);
709 np->b_cont = mp->b_cont;
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))
727 case DL_GET_STATISTICS_REQ:
728 if (size < sizeof(dl_get_statistics_req_t))
730 if ((reply = allocb(sizeof(dl_get_statistics_ack_t) + 5 * sizeof(int),
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);
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:
761 case DL_REPLY_UPDATE_REQ:
763 case DL_DATA_ACK_REQ:
764 dlpi_error(q, d->dl_primitive, DL_NOTSUPPORTED, 0);
768 case DL_DISCONNECT_REQ:
771 dlpi_error(q, d->dl_primitive, DL_OUTSTATE, 0);
775 dlpi_error(q, d->dl_primitive, DL_BADQOSTYPE, 0);
783 cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive);
786 dlpi_error(q, d->dl_primitive, DL_BADPRIM, 0);
793 dlpi_error(q, prim, err, uerr)
798 dl_error_ack_t *errp;
800 reply = allocb(sizeof(dl_error_ack_t), BPRI_HI);
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;
821 reply = allocb(sizeof(dl_ok_ack_t), BPRI_HI);
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;
838 struct upperstr *ppa;
840 if (us->flags & US_BLOCKED)
847 if ((q = ppa->lowerq) == 0) {
848 /* try to send it up the control stream */
855 us->flags |= US_BLOCKED;
864 struct upperstr *us, **usp;
868 * Allocate a new PPA id and link this stream into
873 while ((us = *usp) != 0 && ppa_id == us->ppa_id) {
877 us = (struct upperstr *) q->q_ptr;
883 us->flags |= US_CONTROL;
888 *(int *)mp->b_cont->b_rptr = ppa_id;
889 mp->b_datap->db_type = M_IOCACK;
902 us = (struct upperstr *) q->q_ptr;
903 while ((mp = getq(q)) != 0) {
904 if (!send_data(mp, us)) {
910 us->flags &= ~US_BLOCKED;
921 * Flow control has back-enabled this stream:
922 * enable the write service procedures of all upper
923 * streams feeding this lower stream.
925 for (us = (struct upperstr *) q->q_ptr; us != NULL; us = us->next)
926 if (us->flags & US_BLOCKED)
935 struct upperstr *us, *as;
937 dl_unitdata_ind_t *ud;
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.
944 us = (struct upperstr *) q->q_ptr;
945 if (us->flags & US_CONTROL) {
948 * If there is no lower queue attached, run the write service
949 * routines of other upper streams attached to this PPA.
951 if (us->lowerq == 0) {
954 if (as->flags & US_BLOCKED)
961 * A network protocol stream. Put a DLPI header on each
962 * packet and send it on.
964 while ((mp = getq(q)) != 0) {
965 if (!canputnext(q)) {
969 proto = PPP_PROTOCOL(mp->b_rptr);
970 mp->b_rptr += PPP_HDRLEN;
971 hdr = allocb(sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong),
974 /* XXX should put it back and use bufcall */
978 ud = (dl_unitdata_ind_t *) hdr->b_wptr;
979 hdr->b_wptr += sizeof(dl_unitdata_ind_t) + 2 * sizeof(ulong);
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
990 ((ulong *)(ud + 1))[0] = us->req_sap; /* dest SAP */
991 ((ulong *)(ud + 1))[1] = us->req_sap; /* src SAP */
998 static struct upperstr *
999 find_dest(ppa, proto)
1000 struct upperstr *ppa;
1003 struct upperstr *us;
1005 for (us = ppa->next; us != 0; us = us->next)
1006 if (proto == us->sap)
1016 struct upperstr *ppa, *us;
1020 ppa = (struct upperstr *) q->q_ptr;
1023 cmn_err(CE_CONT, "ppplrput: q = %x, ppa = 0??\n", q);
1028 switch (mp->b_datap->db_type) {
1030 if (*mp->b_rptr & FLUSHW) {
1031 *mp->b_rptr &= ~FLUSHR;
1042 if (mp->b_datap->db_type == M_DATA) {
1043 if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
1044 && !pullupmsg(mp, PPP_HDRLEN)) {
1046 cmn_err(CE_CONT, "ppp_lrput: pullupmsg failed\n");
1051 proto = PPP_PROTOCOL(mp->b_rptr);
1052 if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) {
1054 * A data packet for some network protocol.
1055 * Queue it on the upper stream for that protocol.
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.
1069 if (mp->b_datap->db_type >= QPCTL || canputnext(ppa->q))
1070 putnext(ppa->q, mp);
1084 struct upperstr *ppa, *us;
1088 * Packets only get queued here for flow control reasons.
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) {
1102 if (canputnext(ppa->q))
1103 putnext(ppa->q, mp);
1114 putctl2(q, type, code, val)
1116 int type, code, val;
1120 mp = allocb(2, BPRI_HI);
1123 mp->b_datap->db_type = type;
1124 mp->b_wptr[0] = code;
1125 mp->b_wptr[1] = val;
1132 putctl4(q, type, code, val)
1134 int type, code, val;
1138 mp = allocb(4, BPRI_HI);
1141 mp->b_datap->db_type = type;
1142 mp->b_wptr[0] = code;
1143 ((short *)mp->b_wptr)[1] = val;