Note that the inbound and outbound qualifiers can be used with
[mpls-ppp.git] / aix4 / ppp_if.c
blob23b8446167d6c2fd2fe571ba7bb1490397bc3e91
1 /*
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
9 */
11 #define VJC 1
12 #include <sys/types.h>
14 #ifndef PPP_VD
15 #include "ppp.h"
16 #endif
18 #if NUM_PPP > 0
20 #define STREAMS 1
22 #define PPP_STATS 1 /* keep statistics */
23 #define DEBUGS 1
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>
33 #include <sys/user.h>
36 #include <sys/systm.h>
38 #include <sys/mbuf.h>
39 #include <sys/socket.h>
40 #include <sys/errno.h>
41 #include <sys/ioctl.h>
42 #include <sys/file.h>
43 #include <sys/uio.h>
44 #include <net/if.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>
56 #ifdef VJC
57 #undef SPECIAL_I
58 #include <net/vjcompress.h>
59 #endif
61 #ifdef PPP_STATS
62 #define INCR(comp) ++p->pii_stats.comp
63 #else
64 #define INCR(comp)
65 #endif
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.
75 #define NP_IP 0
76 #define NUM_NP 1 /* # protocols supported */
79 * Structure used within the ppp_if streams module.
81 struct ppp_if_info {
82 int pii_flags;
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;
88 #ifdef VJC
89 struct vjcompress pii_sc_comp; /* vjc control buffer */
90 #endif
91 #ifdef PPP_STATS
92 struct pppstat pii_stats;
93 struct ppp_comp_stats pii_cstats;
94 #endif
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 */
107 #ifdef DEBUGS
108 #include <sys/syslog.h>
109 #define DLOG(s,a) if (p->pii_flags&PII_FLAGS_DEBUG) bsdlog(LOG_INFO, s, a)
110 #else
111 #define DLOG(s) {}
112 #endif
114 #ifdef PPP_SNIT
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};
120 #endif
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;
141 PII *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)
152 int rc = 0;
154 switch (cmd) {
155 case CFG_INIT:
156 rc = str_install(STR_LOAD_MOD, &pppconf);
157 break;
158 case CFG_TERM:
159 rc = str_install(STR_UNLOAD_MOD, &pppconf);
160 break;
161 default:
162 rc = EINVAL;
163 break;
165 if ((rc == 0) && !(pii = xmalloc(sizeof(PII) * NUM_PPP, 0, pinned_heap)))
166 rc = ENOMEM;
167 else
168 bzero(pii, sizeof(PII) * NUM_PPP);
170 return(rc);
174 ppp_attach(unit)
175 int unit;
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;
183 ifp->if_unit = unit;
184 ifp->if_ioctl = ppp_ioctl;
185 ifp->if_output = ppp_output;
186 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
187 if_attach(ifp);
188 if_nostat(ifp);
189 pii[unit].pii_flags |= PII_FLAGS_ATTACHED;
194 ppp_unattach(unit)
195 int unit;
197 struct ifnet *ifp = &pii[unit].pii_ifnet;
198 struct ifnet **p;
199 int s;
201 if (!(pii[unit].pii_flags & PII_FLAGS_ATTACHED))
202 return 0;
204 /* remove interface from interface list */
205 for (p = &ifp; *p; p = &((*p)->if_next)) {
206 if (*p == ifp) {
207 *p = (*p)->if_next;
209 /* mark it down and flush it's que */
210 if_down(ifp);
212 /* free any addresses hanging off the intf */
213 if_release_addrs(ifp);
215 pii[unit].pii_flags &= ~PII_FLAGS_ATTACHED;
217 return 0;
221 return -1;
225 static void
226 if_release_addrs(ifp)
227 register struct ifnet *ifp;
229 register struct in_ifaddr **addr;
230 register struct ifaddr *ifa, *ifanxt;
231 register int s;
233 if_delete_route(ifp);
235 for (addr = &in_ifaddr; *addr; ) {
236 if ((*addr)->ia_ifp == ifp)
237 *addr = (*addr)->ia_next;
238 else
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;
247 m_free(dtom(ifa));
249 ifp->if_addrlist = 0;
253 * Delete routes to the specified interface.
254 * Hacked from rtrequest().
256 static void
257 if_delete_route(ifp)
258 struct ifnet *ifp;
260 extern int rttrash; /* routes not in table but not freed */
261 register struct mbuf **mprev, *m;
262 register struct rtentry *route;
263 register int i;
265 /* search host rt tbl */
267 for (i = 0; i < RTHASHSIZ; i++) {
268 mprev = &rthost[i];
269 while (m = *mprev) {
270 route = mtod(m, struct rtentry *);
271 if (route->rt_ifp == ifp) {
272 *mprev = m->m_next;
273 if (route->rt_refcnt > 0) {
274 route->rt_flags &= ~RTF_UP;
275 rttrash++;
276 m->m_next = 0;
277 } else {
278 m_free(m);
280 } else
281 mprev = &m->m_next;
286 /* search net rt tbl */
288 for (i = 0; i < RTHASHSIZ; i++) {
289 mprev = &rtnet[i];
290 while (m = *mprev) {
291 route = mtod(m, struct rtentry *);
292 if (route->rt_ifp == ifp) {
293 *mprev = m->m_next;
294 if (route->rt_refcnt > 0) {
295 route->rt_flags &= ~RTF_UP;
296 rttrash++;
297 m->m_next = 0;
298 } else {
299 m_free(m);
301 } else
302 mprev = &m->m_next;
309 ppp_busy()
311 int x;
313 for (x = 0; x < NUM_PPP; x++) {
314 if (pii[x].pii_flags & PII_FLAGS_INUSE)
315 return 1;
317 return 0;
320 static PII *
321 ppp_if_alloc()
323 int s, x;
324 PII *p;
326 for (x = 0; x < NUM_PPP; x++)
327 if (!(pii[x].pii_flags & PII_FLAGS_INUSE))
328 break;
329 if (x == NUM_PPP) { /* all buffers in use */
330 return NULL;
332 p = &pii[x];
333 p->pii_flags |= PII_FLAGS_INUSE;
334 return p;
337 static void
338 ppp_if_init(q, p)
339 queue_t *q;
340 PII *p;
342 int s, n;
345 #ifdef VJC
346 vj_compress_init(&p->pii_sc_comp, -1);
347 #endif
348 #ifdef PPP_STATS
349 bzero(&p->pii_stats, sizeof(p->pii_stats));
350 #endif
351 if (!(p->pii_flags & PII_FLAGS_ATTACHED))
352 ppp_attach(p - pii); /* attach it */
353 else
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 */
363 p->pii_npq = NULL;
364 p->pii_npq_tail = &p->pii_npq;
366 DLOG("ppp_if%d: init\n", p - pii);
369 static int
370 ppp_if_open(q, dev, flag, sflag)
371 queue_t *q;
372 dev_t dev;
373 int flag, sflag;
376 if (!suser()) {
377 return(EPERM);
380 return (0);
383 static int
384 ppp_if_close(q)
385 queue_t *q; /* queue info */
387 PII *p = (PII *) q->q_ptr;
388 int s, n;
389 mblk_t *mp, *mq;
391 if (p != NULL) {
392 if_down(&p->pii_ifnet);
393 p->pii_ifnet.if_flags &= ~IFF_RUNNING;
394 p->pii_flags &= ~PII_FLAGS_INUSE;
395 q->q_ptr = NULL;
396 for (mp = p->pii_npq; mp != NULL; mp = mq) {
397 mq = mp->b_next;
398 freemsg(mp);
400 p->pii_npq = NULL;
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 */
409 static int
410 ppp_if_wput(q, mp)
411 queue_t *q;
412 register mblk_t *mp;
414 register struct iocblk *i;
415 register PII *p;
416 int bits, flags, error, unit, s;
417 queue_t *oq;
418 int npix;
419 struct npioctl *npi;
420 mblk_t *mq, **mqnext;
421 struct ppp_stats *psp;
423 switch (mp->b_datap->db_type) {
425 case M_FLUSH:
426 if (*mp->b_rptr & FLUSHW)
427 flushq(q, FLUSHDATA);
428 putnext(q, mp); /* send it along too */
429 break;
431 case M_DATA:
432 putq(q, mp); /* queue it for my service routine */
433 break;
435 case M_IOCTL:
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 */
441 #ifdef VJC
442 if (i->ioc_count == TRANSPARENT) {
443 bits = *(u_int *) mp->b_cont->b_rptr;
444 DLOG("ppp_if: SIFVJCOMP %d\n", bits);
445 if (bits & 1)
446 p->pii_flags |= PII_FLAGS_VJC_ON;
447 else
448 p->pii_flags &= ~PII_FLAGS_VJC_ON;
449 if (bits & 2)
450 p->pii_flags |= PII_FLAGS_VJC_NOCCID;
451 else
452 p->pii_flags &= ~PII_FLAGS_VJC_NOCCID;
453 if (bits & 4)
454 p->pii_flags |= PII_FLAGS_VJC_REJ;
455 else
456 p->pii_flags &= ~PII_FLAGS_VJC_REJ;
457 bits >>= 4; /* now max conn id. */
458 if (bits)
459 vj_compress_init(&p->pii_sc_comp, bits);
460 mp->b_datap->db_type = M_IOCACK;
461 i->ioc_count = 0;
462 qreply(q, mp);
463 break;
465 #endif
466 putnext(q, mp);
467 break;
469 case SIOCGETU: /* get unit number */
471 * Allocate a unit if we don't already have one.
473 error = 0;
474 if (p == (PII *) 0) {
475 p = ppp_if_alloc();
476 if (p == NULL)
477 error = ENOBUFS;
478 else
479 ppp_if_init(RD(q), p);
481 if (error == 0
482 && (mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL)
483 error = ENOSR;
484 if (error == 0) {
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;
488 } else {
489 i->ioc_error = error;
490 i->ioc_count = 0;
491 mp->b_datap->db_type = M_IOCNAK;
493 qreply(q,mp);
494 break;
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;
503 i->ioc_count = 0;
504 error = EINVAL;
505 } else {
506 p = &pii[unit];
507 if (p->pii_flags & PII_FLAGS_INUSE) {
508 oq = p->pii_writeq;
509 oq->q_ptr = RD(oq)->q_ptr = NULL;
510 q->q_ptr = RD(q)->q_ptr = (caddr_t) p;
511 p->pii_writeq = q;
512 } else {
513 ppp_if_init(RD(q), p);
515 mp->b_datap->db_type = M_IOCACK;
517 qreply(q, mp);
518 break;
520 putnext(q, mp);
521 break;
523 case SIOCSIFDEBUG :
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;
527 if (flags & 1)
528 p->pii_flags |= PII_FLAGS_DEBUG;
529 else
530 p->pii_flags &= ~PII_FLAGS_DEBUG;
532 putnext(q, mp);
533 break;
535 case SIOCGETNPMODE:
536 case SIOCSETNPMODE:
537 if (i->ioc_count == TRANSPARENT && p != NULL) {
538 npi = *((struct npioctl **) mp->b_cont->b_rptr);
539 switch (npi->protocol) {
540 case PPP_IP:
541 npix = NP_IP;
542 break;
543 default:
544 npix = -1;
546 if (npix < 0) {
547 i->ioc_error = EAFNOSUPPORT;
548 i->ioc_count = 0;
549 mp->b_datap->db_type = M_IOCNAK;
550 qreply(q, mp);
551 break;
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;
559 continue;
561 *mqnext = mq->b_next;
562 if (npi->mode == NPMODE_PASS) {
563 putq(q, mq); /* q it for service routine */
564 } else {
565 freemsg(mq);
568 p->pii_npq_tail = mqnext;
570 p->pii_npmode[npix] = npi->mode;
571 i->ioc_count = 0;
572 } else
573 npi->mode = p->pii_npmode[npix];
574 mp->b_datap->db_type = M_IOCACK;
575 qreply(q, mp);
576 break;
578 putnext(q, mp);
579 break;
581 default: /* unknown IOCTL call */
582 putnext(q, mp); /* pass it along */
584 break;
586 default:
587 putnext(q, mp); /* don't know what to do with this, so send it along*/
591 static int
592 ppp_if_wsrv(q)
593 queue_t *q;
595 register mblk_t *mp;
596 register PII *p;
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)) {
606 putbq(q, mp);
607 return;
610 /* increment count of outgoing packets */
611 if (p != NULL)
612 INCR(ppp_opackets);
614 /* just pass it along, nothing to do in this direction */
615 putnext(q, mp);
616 } /* end while */
620 static int
621 ppp_if_rput(q, mp)
622 queue_t *q;
623 register mblk_t *mp;
625 register PII *p;
627 switch (mp->b_datap->db_type) {
629 case M_FLUSH:
630 if (*mp->b_rptr & FLUSHR)
631 flushq(q, FLUSHDATA);
632 putnext(q, mp); /* send it along too */
633 break;
635 case M_DATA:
636 putq(q, mp); /* queue it for my service routine */
637 break;
639 case M_CTL:
640 p = (PII *) q->q_ptr;
641 if (p != NULL) {
642 switch (*(u_char *) mp->b_rptr) {
643 case IF_INPUT_ERROR :
644 p->pii_ifnet.if_ierrors++;
645 INCR(ppp_ierrors);
646 DLOG("ppp_if: input error inc to %d\n",
647 p->pii_ifnet.if_ierrors);
648 break;
649 case IF_OUTPUT_ERROR :
650 p->pii_ifnet.if_oerrors++;
651 INCR(ppp_oerrors);
652 DLOG("ppp_if: output error inc to %d\n",
653 p->pii_ifnet.if_oerrors);
654 break;
655 case IF_CSTATS:
656 bcopy(mp->b_rptr + sizeof(u_long), &p->pii_cstats,
657 sizeof(struct ppp_comp_stats));
658 freemsg(mp);
659 break;
660 default:
661 putnext(q, mp); /* send it up to pppd */
662 break;
665 break;
667 default:
668 putnext(q, mp); /* send along other message types */
672 static int
673 ppp_if_rsrv(q)
674 queue_t *q;
676 register mblk_t *mp,*m0;
677 #ifdef VJC
678 register mblk_t *mvjc;
679 unsigned char *cp, *iphdr;
680 u_int hlen;
681 #endif
682 register PII *p;
683 struct mbuf *mb1, *mb2, *mbtail;
684 struct ifnet *ifp;
685 int len, xlen, count, s, pklen;
686 u_char *rptr;
687 int address, control;
688 int dlen;
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
698 if (p == NULL) {
699 if (!canput(q->q_next)) {
700 putbq(q, mp);
701 return;
703 putnext(q, mp);
704 continue;
707 len = msgdsize(mp);
708 dlen = len - PPP_HDRLEN;
709 #ifdef PPP_STATS
710 p->pii_stats.ppp_ibytes += len;
711 #endif
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);
717 freemsg(mp);
718 p->pii_ifnet.if_ierrors++;
719 continue;
721 m0 = mp; /* remember first message block */
723 #ifdef VJC
724 switch (PPP_PROTOCOL(mp->b_rptr)) {
725 case PPP_VJC_COMP :
726 if ((p->pii_flags & PII_FLAGS_VJC_REJ)
727 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
728 DLOG("VJC rejected\n", 0);
729 freemsg(mp);
730 continue;
732 address = PPP_ADDRESS(mp->b_rptr);
733 control = PPP_CONTROL(mp->b_rptr);
734 mp->b_rptr += PPP_HDRLEN;
735 len -= 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);
743 freemsg(mp);
744 continue;
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);
753 if (xlen < 0) {
754 DLOG("ppp: vj_uncompress failed on type Compressed\n", 0);
755 freemsg(mp);
756 continue;
758 if (!(mvjc = allocb(hlen + PPP_HDRLEN, BPRI_MED))) {
759 DLOG("allocb mvjc failed (%d)\n", hlen + PPP_HDRLEN);
760 freemsg(mp);
761 continue;
763 dlen = len - xlen + hlen;
764 cp = mvjc->b_rptr;
765 cp[0] = address;
766 cp[1] = control;
767 cp[2] = 0;
768 cp[3] = PPP_IP;
769 bcopy(iphdr, cp + PPP_HDRLEN, hlen);
770 mvjc->b_wptr = cp + PPP_HDRLEN + hlen;
771 mvjc->b_cont = mp;
772 mp->b_rptr += xlen;
773 m0 = mp = mvjc;
774 break;
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);
780 freemsg(mp);
781 continue;
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);
790 freemsg(mp);
791 continue;
795 * "Uncompress" it. Basically this just copies information
796 * into p->pii_sc_comp and restores the protocol field of
797 * the IP header.
799 if (!vj_uncompress_uncomp(mp->b_rptr + PPP_HDRLEN,
800 &p->pii_sc_comp)) {
801 DLOG("ppp: vj_uncompress failed on type Uncompresed\n", 0);
802 freemsg(mp);
803 continue;
805 mp->b_rptr[3] = PPP_IP;
806 break;
808 #endif
810 switch (PPP_PROTOCOL(mp->b_rptr)) {
811 default:
812 if (!canput(q->q_next)) {
813 putbq(q, mp);
814 return;
816 INCR(ppp_ipackets);
817 p->pii_ifnet.if_ipackets++;
818 putnext(q, mp);
819 continue;
821 case PPP_IP:
823 * Don't let packets through until IPCP is up.
825 INCR(ppp_ipackets);
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);
831 freemsg(mp);
832 continue;
836 * Get the first mbuf and put the struct ifnet * in.
838 MGETHDR(mb1, M_DONTWAIT, MT_DATA);
839 mb1->m_len = 0;
840 if (mb1 == NULL) {
841 p->pii_ifnet.if_ierrors++;
842 freemsg(m0);
843 continue;
845 len = MHLEN;
846 mb1->m_pkthdr.rcvif = &(p->pii_ifnet);
847 mb1->m_pkthdr.len = dlen;
848 mbtail = mb2 = mb1;
849 mb1->m_len = 0;
851 rptr = mp->b_rptr + PPP_HDRLEN;
852 xlen = mp->b_wptr - rptr;
853 for(;;) {
854 if (xlen == 0) { /* move to the next mblk */
855 mp = mp->b_cont;
856 if (mp == NULL)
857 break;
858 xlen = mp->b_wptr - (rptr = mp->b_rptr);
859 continue;
861 if (len == 0) {
862 MGET(mb2, M_DONTWAIT, MT_DATA);
863 if (!mb2) {
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 */
867 mb1 = NULL;
868 break;
870 len = MLEN;
871 mb2->m_len = 0;
872 mbtail->m_next = mb2;
873 mbtail = mb2;
875 count = MIN(xlen, len);
876 bcopy((char *) rptr, mtod(mb2, char *) + mb2->m_len, count);
877 rptr += count;
878 len -= count;
879 xlen -= count;
880 mb2->m_len += count;
883 freemsg(m0);
884 if (mb1 == NULL)
885 continue;
887 #ifdef PPP_SNIT
888 if (p->pii_ifnet.if_flags & IFF_PROMISC) {
889 struct mbuf *m = mb1;
891 len = 0;
892 do {
893 len += m->m_len;
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 *);
900 #endif
902 if (IF_QFULL(&ipintrq)) {
903 IF_DROP(&ipintrq);
904 p->pii_ifnet.if_ierrors++;
905 m_freem(mb1);
907 else {
909 find_input_type(0x0800, mb1, ifp, 0);
911 } /* end while */
914 /* ifp output procedure */
916 ppp_output(ifp, m0, dst)
917 struct ifnet *ifp;
918 struct mbuf *m0;
919 struct sockaddr *dst;
921 register PII *p = &pii[ifp->if_unit];
922 struct mbuf *m1;
923 int error, s, len;
924 u_short protocol;
925 #ifdef VJC
926 int type;
927 u_char *vjhdr;
928 #endif
929 mblk_t *mp;
930 enum NPmode npmode;
932 error = 0;
933 if (!(ifp->if_flags & IFF_UP)) {
934 error = ENETDOWN;
935 goto getout;
938 switch (dst->sa_family) {
939 #ifdef INET
940 case AF_INET:
941 #ifdef PPP_SNIT
942 if (ifp->if_flags & IFF_PROMISC) {
943 struct mbuf *m = m0;
945 len = 0;
946 do {
947 len += m->m_len;
948 } while (m = m->m_next);
949 nif.nif_bodylen = len;
950 snit_intr(ifp, m0, &nif);
952 #endif
953 protocol = PPP_IP;
954 npmode = p->pii_npmode[NP_IP];
955 break;
956 #endif
958 default:
959 DLOG("ppp: af%d not supported\n", dst->sa_family);
960 error = EAFNOSUPPORT;
961 goto getout;
964 if (!p->pii_writeq) {
965 DLOG("ppp_if%d: no queue\n", p - pii);
966 error = EHOSTUNREACH;
967 goto getout;
970 switch (npmode) {
971 case NPMODE_DROP:
972 goto getout;
973 case NPMODE_ERROR:
974 error = ENETDOWN;
975 goto getout;
978 #ifdef VJC
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),
985 &vjhdr);
986 switch (type) {
987 case TYPE_UNCOMPRESSED_TCP :
988 protocol = PPP_VJC_UNCOMP;
989 break;
990 case TYPE_COMPRESSED_TCP :
991 protocol = PPP_VJC_COMP;
992 len = vjhdr - (u_char *) ip;
993 m0->m_data += len;
994 m0->m_len -= len;
995 break;
999 #endif
1001 len = PPP_HDRLEN;
1002 for (m1 = m0; m1; m1 = m1->m_next)
1003 len += m1->m_len;
1005 if (!(mp = allocb(len, BPRI_MED))) {
1006 DLOG("ppp_if%d: allocb failed\n", p - pii);
1007 error = ENOBUFS;
1008 goto getout;
1011 #ifdef PPP_STATS
1012 p->pii_stats.ppp_obytes += len;
1013 #endif
1015 *mp->b_wptr++ = PPP_ALLSTATIONS;
1016 *mp->b_wptr++ = PPP_UI;
1017 *mp->b_wptr++ = 0;
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);
1028 } else {
1029 mp->b_next = NULL;
1030 *p->pii_npq_tail = mp;
1031 p->pii_npq_tail = &mp;
1034 getout:
1035 m_freem(m0);
1036 if (error) {
1037 INCR(ppp_oerrors);
1038 p->pii_ifnet.if_oerrors++;
1040 return (error);
1044 * if_ ioctl requests
1046 ppp_ioctl(ifp, cmd, data)
1047 register struct ifnet *ifp;
1048 unsigned int cmd;
1049 caddr_t data;
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;
1055 PII *p;
1056 queue_t *q;
1057 int error = 0;
1059 switch (cmd) {
1060 case SIOCSIFFLAGS :
1061 /* This happens every time IFF_PROMISC has been changed. */
1062 if (!ifr)
1063 break;
1064 if (!suser()) {
1065 error = EPERM;
1066 break;
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);
1073 break;
1075 case SIOCGIFFLAGS :
1076 ifr->ifr_flags = ifp->if_flags;
1077 break;
1079 case SIOCSIFADDR :
1080 if( ifa->ifa_addr->sa_family != AF_INET)
1081 error = EAFNOSUPPORT;
1082 break;
1084 case SIOCSIFDSTADDR :
1085 if (ifa->ifa_addr->sa_family != AF_INET)
1086 error = EAFNOSUPPORT;
1087 break;
1089 case SIOCSIFMTU :
1090 if (!suser()) {
1091 error = EPERM;
1092 break;
1094 if (ifr->ifr_mtu > MAX_PKTSIZE - PPP_FRAMING) {
1095 error = EINVAL;
1096 break;
1098 ifp->if_mtu = ifr->ifr_mtu;
1099 break;
1101 case SIOCGIFMTU :
1102 ifr->ifr_mtu = ifp->if_mtu;
1103 break;
1105 case SIOCGPPPSTATS:
1106 p = &pii[ifp->if_unit];
1107 psp = (struct ppp_stats *) &((struct ifpppstatsreq *)data)->stats;
1108 bzero(psp, sizeof(struct ppp_stats));
1109 #ifdef PPP_STATS
1110 psp->p = p->pii_stats;
1111 #endif
1112 #if defined(VJC) && !defined(VJ_NO_STATS)
1113 psp->vj = p->pii_sc_comp.stats;
1114 #endif
1115 break;
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 */
1122 q = p->pii_writeq;
1123 if (q != NULL) {
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));
1134 break;
1136 default:
1137 error = EINVAL;
1138 break;
1141 return(error);
1144 #endif