2 ppp_if.c - Streams PPP interface module
4 top level module handles if_ and packetizing PPP packets.
6 Copyright (C) 1990 Brad K. Clements, All Rights Reserved
7 See copyright notice in NOTES
12 #include <sys/types.h>
22 #define PPP_STATS 1 /* keep statistics */
25 #include <net/net_globals.h>
26 #include <sys/param.h>
27 #include <sys/stream.h>
28 #include <sys/stropts.h>
29 #include <sys/strconf.h>
31 #include <sys/device.h>
36 #include <sys/systm.h>
39 #include <sys/socket.h>
40 #include <sys/errno.h>
41 #include <sys/ioctl.h>
45 #include <net/route.h>
46 #include <net/netisr.h>
47 #include <netinet/in.h>
48 #include <netinet/in_var.h>
49 #define _NETINET_IN_SYSTM_H_
50 typedef u_long n_long;
51 #include <netinet/ip.h>
53 #include <net/ppp_defs.h>
54 #include <net/ppp_str.h>
58 #include <net/vjcompress.h>
62 #define INCR(comp) ++p->pii_stats.comp
67 #define MAX_PKTSIZE 4096 /* max packet size including framing */
68 #define PPP_FRAMING 6 /* 4-byte header + 2-byte FCS */
69 #define MAX_IPHDR 128 /* max TCP/IP header size */
70 #define MAX_VJHDR 20 /* max VJ compressed header size (?) */
73 * Network protocols we support.
76 #define NUM_NP 1 /* # protocols supported */
79 * Structure used within the ppp_if streams module.
83 struct ifnet pii_ifnet;
84 queue_t *pii_writeq; /* used by ppp_output */
85 enum NPmode pii_npmode[NUM_NP];
86 mblk_t *pii_npq; /* list of packets queued up */
87 mblk_t **pii_npq_tail;
89 struct vjcompress pii_sc_comp; /* vjc control buffer */
92 struct pppstat pii_stats;
93 struct ppp_comp_stats pii_cstats;
98 * Values for pii_flags.
100 #define PII_FLAGS_INUSE 0x1 /* in use by a stream */
101 #define PII_FLAGS_ATTACHED 0x8 /* already if_attached */
102 #define PII_FLAGS_VJC_ON 0x10 /* VJ TCP header compression enabled */
103 #define PII_FLAGS_VJC_NOCCID 0x20 /* VJ: don't compress conn. id */
104 #define PII_FLAGS_VJC_REJ 0x40 /* receive: reject VJ comp */
105 #define PII_FLAGS_DEBUG 0x80 /* enable debug printout */
108 #include <sys/syslog.h>
109 #define DLOG(s,a) if (p->pii_flags&PII_FLAGS_DEBUG) bsdlog(LOG_INFO, s, a)
115 #include <net/nit_if.h>
116 #include <netinet/if_ether.h>
117 /* Use a fake link level header to make etherfind and tcpdump happy. */
118 static struct ether_header header = {{1}, {2}, ETHERTYPE_IP};
119 static struct nit_if nif = {(caddr_t)&header, sizeof(header), 0, 0};
122 static int ppp_if_open(), ppp_if_close(), ppp_if_rput(), ppp_if_wput(),
123 ppp_if_wsrv(), ppp_if_rsrv();
125 static struct module_info minfo ={
126 0xbad,"ppp_if",0, INFPSZ, 16384, 4096
129 static struct qinit r_init = {
130 ppp_if_rput, ppp_if_rsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL
132 static struct qinit w_init = {
133 ppp_if_wput, ppp_if_wsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL
135 struct streamtab ppp_ifinfo = {
136 &r_init, &w_init, NULL, NULL
139 typedef struct ppp_if_info PII;
143 int ppp_output(), ppp_ioctl();
144 static void if_release_addrs(), if_delete_route();
146 strconf_t pppconf = {
147 "pppif", &ppp_ifinfo, STR_NEW_OPEN, 0, SQLVL_DEFAULT, (void *) 0
150 int ppp_load(int cmd, struct uio *uiop)
156 rc = str_install(STR_LOAD_MOD, &pppconf);
159 rc = str_install(STR_UNLOAD_MOD, &pppconf);
165 if ((rc == 0) && !(pii = xmalloc(sizeof(PII) * NUM_PPP, 0, pinned_heap)))
168 bzero(pii, sizeof(PII) * NUM_PPP);
177 register struct ifnet *ifp = &pii[unit].pii_ifnet;
179 ifp->if_name = "ppp";
180 ifp->if_type = IFT_PTPSERIAL;
181 ifp->if_mtu = PPP_MTU;
182 ifp->if_flags = IFF_POINTOPOINT;
184 ifp->if_ioctl = ppp_ioctl;
185 ifp->if_output = ppp_output;
186 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
189 pii[unit].pii_flags |= PII_FLAGS_ATTACHED;
197 struct ifnet *ifp = &pii[unit].pii_ifnet;
201 if (!(pii[unit].pii_flags & PII_FLAGS_ATTACHED))
204 /* remove interface from interface list */
205 for (p = &ifp; *p; p = &((*p)->if_next)) {
209 /* mark it down and flush it's que */
212 /* free any addresses hanging off the intf */
213 if_release_addrs(ifp);
215 pii[unit].pii_flags &= ~PII_FLAGS_ATTACHED;
226 if_release_addrs(ifp)
227 register struct ifnet *ifp;
229 register struct in_ifaddr **addr;
230 register struct ifaddr *ifa, *ifanxt;
233 if_delete_route(ifp);
235 for (addr = &in_ifaddr; *addr; ) {
236 if ((*addr)->ia_ifp == ifp)
237 *addr = (*addr)->ia_next;
239 addr = &((*addr)->ia_next);
243 * Free all mbufs holding down this interface's address(es).
245 for (ifa = ifp->if_addrlist; ifa; ifa = ifanxt) {
246 ifanxt = ifa->ifa_next;
249 ifp->if_addrlist = 0;
253 * Delete routes to the specified interface.
254 * Hacked from rtrequest().
260 extern int rttrash; /* routes not in table but not freed */
261 register struct mbuf **mprev, *m;
262 register struct rtentry *route;
265 /* search host rt tbl */
267 for (i = 0; i < RTHASHSIZ; i++) {
270 route = mtod(m, struct rtentry *);
271 if (route->rt_ifp == ifp) {
273 if (route->rt_refcnt > 0) {
274 route->rt_flags &= ~RTF_UP;
286 /* search net rt tbl */
288 for (i = 0; i < RTHASHSIZ; i++) {
291 route = mtod(m, struct rtentry *);
292 if (route->rt_ifp == ifp) {
294 if (route->rt_refcnt > 0) {
295 route->rt_flags &= ~RTF_UP;
313 for (x = 0; x < NUM_PPP; x++) {
314 if (pii[x].pii_flags & PII_FLAGS_INUSE)
326 for (x = 0; x < NUM_PPP; x++)
327 if (!(pii[x].pii_flags & PII_FLAGS_INUSE))
329 if (x == NUM_PPP) { /* all buffers in use */
333 p->pii_flags |= PII_FLAGS_INUSE;
346 vj_compress_init(&p->pii_sc_comp, -1);
349 bzero(&p->pii_stats, sizeof(p->pii_stats));
351 if (!(p->pii_flags & PII_FLAGS_ATTACHED))
352 ppp_attach(p - pii); /* attach it */
354 p->pii_ifnet.if_mtu = PPP_MTU;
355 p->pii_writeq = WR(q);
356 /* set write Q and read Q to point here */
357 WR(q)->q_ptr = q->q_ptr = (caddr_t) p;
358 p->pii_ifnet.if_flags |= IFF_RUNNING;
359 p->pii_flags &= PII_FLAGS_INUSE | PII_FLAGS_ATTACHED | PII_FLAGS_DEBUG;
360 for (n = 0; n < NUM_NP; ++n)
361 p->pii_npmode[n] = NPMODE_ERROR;
362 p->pii_npmode[NP_IP] = NPMODE_PASS; /* for backwards compatibility */
364 p->pii_npq_tail = &p->pii_npq;
366 DLOG("ppp_if%d: init\n", p - pii);
370 ppp_if_open(q, dev, flag, sflag)
385 queue_t *q; /* queue info */
387 PII *p = (PII *) q->q_ptr;
392 if_down(&p->pii_ifnet);
393 p->pii_ifnet.if_flags &= ~IFF_RUNNING;
394 p->pii_flags &= ~PII_FLAGS_INUSE;
396 for (mp = p->pii_npq; mp != NULL; mp = mq) {
401 p->pii_npq_tail = &p->pii_npq;
402 p->pii_writeq = NULL;
403 DLOG("ppp_if%d: closed\n", p - pii);
405 return(0); /* no work to be done */
414 register struct iocblk *i;
416 int bits, flags, error, unit, s;
420 mblk_t *mq, **mqnext;
421 struct ppp_stats *psp;
423 switch (mp->b_datap->db_type) {
426 if (*mp->b_rptr & FLUSHW)
427 flushq(q, FLUSHDATA);
428 putnext(q, mp); /* send it along too */
432 putq(q, mp); /* queue it for my service routine */
436 i = (struct iocblk *) mp->b_rptr;
437 p = (PII *) q->q_ptr;
438 switch ((unsigned int)i->ioc_cmd) {
440 case SIOCSIFVJCOMP: /* enable or disable VJ compression */
442 if (i->ioc_count == TRANSPARENT) {
443 bits = *(u_int *) mp->b_cont->b_rptr;
444 DLOG("ppp_if: SIFVJCOMP %d\n", bits);
446 p->pii_flags |= PII_FLAGS_VJC_ON;
448 p->pii_flags &= ~PII_FLAGS_VJC_ON;
450 p->pii_flags |= PII_FLAGS_VJC_NOCCID;
452 p->pii_flags &= ~PII_FLAGS_VJC_NOCCID;
454 p->pii_flags |= PII_FLAGS_VJC_REJ;
456 p->pii_flags &= ~PII_FLAGS_VJC_REJ;
457 bits >>= 4; /* now max conn id. */
459 vj_compress_init(&p->pii_sc_comp, bits);
460 mp->b_datap->db_type = M_IOCACK;
469 case SIOCGETU: /* get unit number */
471 * Allocate a unit if we don't already have one.
474 if (p == (PII *) 0) {
479 ppp_if_init(RD(q), p);
482 && (mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL)
485 *(int *) mp->b_cont->b_wptr = p->pii_ifnet.if_unit;
486 mp->b_cont->b_wptr += i->ioc_count = sizeof(int);
487 mp->b_datap->db_type = M_IOCACK;
489 i->ioc_error = error;
491 mp->b_datap->db_type = M_IOCNAK;
496 case SIOCSETU: /* set unit number */
497 if ((i->ioc_count == sizeof(int)) ||
498 (i->ioc_count == TRANSPARENT)) {
499 unit = *(int *)mp->b_cont->b_rptr;
500 if (p != NULL || (unsigned) unit > NUM_PPP) {
501 mp->b_datap->db_type = M_IOCNAK;
502 i->ioc_error = EINVAL;
507 if (p->pii_flags & PII_FLAGS_INUSE) {
509 oq->q_ptr = RD(oq)->q_ptr = NULL;
510 q->q_ptr = RD(q)->q_ptr = (caddr_t) p;
513 ppp_if_init(RD(q), p);
515 mp->b_datap->db_type = M_IOCACK;
524 /* catch it on the way past to set our debug flag as well */
525 if (i->ioc_count == TRANSPARENT) {
526 flags = *(int *)mp->b_cont->b_rptr;
528 p->pii_flags |= PII_FLAGS_DEBUG;
530 p->pii_flags &= ~PII_FLAGS_DEBUG;
537 if (i->ioc_count == TRANSPARENT && p != NULL) {
538 npi = *((struct npioctl **) mp->b_cont->b_rptr);
539 switch (npi->protocol) {
547 i->ioc_error = EAFNOSUPPORT;
549 mp->b_datap->db_type = M_IOCNAK;
553 if (i->ioc_cmd == SIOCSETNPMODE) {
554 if (p->pii_npmode[npix] == NPMODE_QUEUE
555 && npi->mode != NPMODE_QUEUE) {
556 for (mqnext = &p->pii_npq; (mq = *mqnext) != NULL; ) {
557 if (PPP_PROTOCOL(mq->b_rptr) != npi->protocol){
558 mqnext = &mq->b_next;
561 *mqnext = mq->b_next;
562 if (npi->mode == NPMODE_PASS) {
563 putq(q, mq); /* q it for service routine */
568 p->pii_npq_tail = mqnext;
570 p->pii_npmode[npix] = npi->mode;
573 npi->mode = p->pii_npmode[npix];
574 mp->b_datap->db_type = M_IOCACK;
581 default: /* unknown IOCTL call */
582 putnext(q, mp); /* pass it along */
587 putnext(q, mp); /* don't know what to do with this, so send it along*/
598 p = (PII *) q->q_ptr;
600 while ((mp = getq(q)) != NULL) {
602 * we can only get M_DATA types into our Queue,
603 * due to our Put function
605 if (!canput(q->q_next)) {
610 /* increment count of outgoing packets */
614 /* just pass it along, nothing to do in this direction */
627 switch (mp->b_datap->db_type) {
630 if (*mp->b_rptr & FLUSHR)
631 flushq(q, FLUSHDATA);
632 putnext(q, mp); /* send it along too */
636 putq(q, mp); /* queue it for my service routine */
640 p = (PII *) q->q_ptr;
642 switch (*(u_char *) mp->b_rptr) {
643 case IF_INPUT_ERROR :
644 p->pii_ifnet.if_ierrors++;
646 DLOG("ppp_if: input error inc to %d\n",
647 p->pii_ifnet.if_ierrors);
649 case IF_OUTPUT_ERROR :
650 p->pii_ifnet.if_oerrors++;
652 DLOG("ppp_if: output error inc to %d\n",
653 p->pii_ifnet.if_oerrors);
656 bcopy(mp->b_rptr + sizeof(u_long), &p->pii_cstats,
657 sizeof(struct ppp_comp_stats));
661 putnext(q, mp); /* send it up to pppd */
668 putnext(q, mp); /* send along other message types */
676 register mblk_t *mp,*m0;
678 register mblk_t *mvjc;
679 unsigned char *cp, *iphdr;
683 struct mbuf *mb1, *mb2, *mbtail;
685 int len, xlen, count, s, pklen;
687 int address, control;
690 p = (PII *) q->q_ptr;
692 while ((mp = getq(q)) != NULL) {
694 * we can only get M_DATA types into our Queue,
695 * due to our Put function
699 if (!canput(q->q_next)) {
708 dlen = len - PPP_HDRLEN;
710 p->pii_stats.ppp_ibytes += len;
713 /* make sure ppp_header is completely in first block */
714 if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
715 && !pullupmsg(mp, PPP_HDRLEN)) {
716 DLOG("pullupmsg failed!\n", 0);
718 p->pii_ifnet.if_ierrors++;
721 m0 = mp; /* remember first message block */
724 switch (PPP_PROTOCOL(mp->b_rptr)) {
726 if ((p->pii_flags & PII_FLAGS_VJC_REJ)
727 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
728 DLOG("VJC rejected\n", 0);
732 address = PPP_ADDRESS(mp->b_rptr);
733 control = PPP_CONTROL(mp->b_rptr);
734 mp->b_rptr += PPP_HDRLEN;
738 * Make sure the VJ header is in one message block.
740 xlen = MIN(len, MAX_VJHDR);
741 if (mp->b_rptr + xlen > mp->b_wptr && !pullupmsg(mp, xlen)) {
742 DLOG("pullupmsg vjc %d failed\n", xlen);
748 * Decompress it, then get a buffer and put the
749 * decompressed header in it.
751 xlen = vj_uncompress_tcp(mp->b_rptr, mp->b_wptr - mp->b_rptr,
752 len, &p->pii_sc_comp, &iphdr, &hlen);
754 DLOG("ppp: vj_uncompress failed on type Compressed\n", 0);
758 if (!(mvjc = allocb(hlen + PPP_HDRLEN, BPRI_MED))) {
759 DLOG("allocb mvjc failed (%d)\n", hlen + PPP_HDRLEN);
763 dlen = len - xlen + hlen;
769 bcopy(iphdr, cp + PPP_HDRLEN, hlen);
770 mvjc->b_wptr = cp + PPP_HDRLEN + hlen;
776 case PPP_VJC_UNCOMP :
777 if ((p->pii_flags & PII_FLAGS_VJC_REJ)
778 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
779 DLOG("VJU rejected\n", 0);
785 * Make sure the IP header is in one message block.
787 xlen = MIN(len, MAX_IPHDR + PPP_HDRLEN);
788 if (mp->b_rptr + xlen > mp->b_wptr && !pullupmsg(mp, xlen)) {
789 DLOG("pullupmsg vju %d failed\n", xlen);
795 * "Uncompress" it. Basically this just copies information
796 * into p->pii_sc_comp and restores the protocol field of
799 if (!vj_uncompress_uncomp(mp->b_rptr + PPP_HDRLEN,
801 DLOG("ppp: vj_uncompress failed on type Uncompresed\n", 0);
805 mp->b_rptr[3] = PPP_IP;
810 switch (PPP_PROTOCOL(mp->b_rptr)) {
812 if (!canput(q->q_next)) {
817 p->pii_ifnet.if_ipackets++;
823 * Don't let packets through until IPCP is up.
826 p->pii_ifnet.if_ipackets++;
828 if (!(p->pii_ifnet.if_flags & IFF_UP)
829 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
830 DLOG("pkt ignored - IP down\n", 0);
836 * Get the first mbuf and put the struct ifnet * in.
838 MGETHDR(mb1, M_DONTWAIT, MT_DATA);
841 p->pii_ifnet.if_ierrors++;
846 mb1->m_pkthdr.rcvif = &(p->pii_ifnet);
847 mb1->m_pkthdr.len = dlen;
851 rptr = mp->b_rptr + PPP_HDRLEN;
852 xlen = mp->b_wptr - rptr;
854 if (xlen == 0) { /* move to the next mblk */
858 xlen = mp->b_wptr - (rptr = mp->b_rptr);
862 MGET(mb2, M_DONTWAIT, MT_DATA);
864 /* if we couldn't get a buffer, drop the packet */
865 p->pii_ifnet.if_ierrors++;
866 m_freem(mb1); /* discard what we've used already */
872 mbtail->m_next = mb2;
875 count = MIN(xlen, len);
876 bcopy((char *) rptr, mtod(mb2, char *) + mb2->m_len, count);
888 if (p->pii_ifnet.if_flags & IFF_PROMISC) {
889 struct mbuf *m = mb1;
894 } while (m = m->m_next);
895 nif.nif_bodylen = len - sizeof(struct ifnet *);
896 mb1->m_off += sizeof(struct ifnet *);
897 snit_intr(&p->pii_ifnet, mb1, &nif);
898 mb1->m_off -= sizeof(struct ifnet *);
902 if (IF_QFULL(&ipintrq)) {
904 p->pii_ifnet.if_ierrors++;
909 find_input_type(0x0800, mb1, ifp, 0);
914 /* ifp output procedure */
916 ppp_output(ifp, m0, dst)
919 struct sockaddr *dst;
921 register PII *p = &pii[ifp->if_unit];
933 if (!(ifp->if_flags & IFF_UP)) {
938 switch (dst->sa_family) {
942 if (ifp->if_flags & IFF_PROMISC) {
948 } while (m = m->m_next);
949 nif.nif_bodylen = len;
950 snit_intr(ifp, m0, &nif);
954 npmode = p->pii_npmode[NP_IP];
959 DLOG("ppp: af%d not supported\n", dst->sa_family);
960 error = EAFNOSUPPORT;
964 if (!p->pii_writeq) {
965 DLOG("ppp_if%d: no queue\n", p - pii);
966 error = EHOSTUNREACH;
979 if ((protocol == PPP_IP) && (p->pii_flags & PII_FLAGS_VJC_ON)) {
980 register struct ip *ip;
981 ip = mtod(m0, struct ip *);
982 if (ip->ip_p == IPPROTO_TCP) {
983 type = vj_compress_tcp(ip, m0->m_len, &p->pii_sc_comp,
984 !(p->pii_flags & PII_FLAGS_VJC_NOCCID),
987 case TYPE_UNCOMPRESSED_TCP :
988 protocol = PPP_VJC_UNCOMP;
990 case TYPE_COMPRESSED_TCP :
991 protocol = PPP_VJC_COMP;
992 len = vjhdr - (u_char *) ip;
1002 for (m1 = m0; m1; m1 = m1->m_next)
1005 if (!(mp = allocb(len, BPRI_MED))) {
1006 DLOG("ppp_if%d: allocb failed\n", p - pii);
1012 p->pii_stats.ppp_obytes += len;
1015 *mp->b_wptr++ = PPP_ALLSTATIONS;
1016 *mp->b_wptr++ = PPP_UI;
1018 *mp->b_wptr++ = protocol;
1019 for (m1 = m0; m1; m1 = m1->m_next) { /* copy all data */
1020 bcopy(mtod(m1, char *), (char *) mp->b_wptr, m1->m_len);
1021 mp->b_wptr += m1->m_len;
1024 p->pii_ifnet.if_opackets++;
1025 DLOG("ppp_output npmode is %d\n",npmode);
1026 if (npmode == NPMODE_PASS) {
1027 putq(p->pii_writeq, mp);
1030 *p->pii_npq_tail = mp;
1031 p->pii_npq_tail = ∓
1038 p->pii_ifnet.if_oerrors++;
1044 * if_ ioctl requests
1046 ppp_ioctl(ifp, cmd, data)
1047 register struct ifnet *ifp;
1051 register struct ifaddr *ifa = (struct ifaddr *) data;
1052 register struct ifreq *ifr = (struct ifreq *) data;
1053 struct ppp_stats *psp;
1054 struct ppp_comp_stats *pcp;
1061 /* This happens every time IFF_PROMISC has been changed. */
1069 /* clear the flags that can be cleared */
1070 ifp->if_flags &= (IFF_CANTCHANGE);
1071 /* or in the flags that can be changed */
1072 ifp->if_flags |= (ifr->ifr_flags & ~IFF_CANTCHANGE);
1076 ifr->ifr_flags = ifp->if_flags;
1080 if( ifa->ifa_addr->sa_family != AF_INET)
1081 error = EAFNOSUPPORT;
1084 case SIOCSIFDSTADDR :
1085 if (ifa->ifa_addr->sa_family != AF_INET)
1086 error = EAFNOSUPPORT;
1094 if (ifr->ifr_mtu > MAX_PKTSIZE - PPP_FRAMING) {
1098 ifp->if_mtu = ifr->ifr_mtu;
1102 ifr->ifr_mtu = ifp->if_mtu;
1106 p = &pii[ifp->if_unit];
1107 psp = (struct ppp_stats *) &((struct ifpppstatsreq *)data)->stats;
1108 bzero(psp, sizeof(struct ppp_stats));
1110 psp->p = p->pii_stats;
1112 #if defined(VJC) && !defined(VJ_NO_STATS)
1113 psp->vj = p->pii_sc_comp.stats;
1117 case SIOCGPPPCSTATS:
1118 p = &pii[ifp->if_unit];
1119 bzero(&p->pii_cstats, sizeof(struct ppp_comp_stats));
1121 /* Make a message to send on the interface's write stream */
1124 putctl1(q, M_CTL, IF_GET_CSTATS);
1126 * We assume the message gets passed along immediately, so
1127 * by the time the putctl1 returns, the request has been
1128 * processed, the values returned and p->pii_cstats has
1129 * been updated. If not, we just get zeroes.
1132 pcp = (struct ppp_comp_stats *)&((struct ifpppcstatsreq *)data)->stats;
1133 bcopy(&p->pii_cstats, pcp, sizeof(struct ppp_comp_stats));