Initial revision
[ppp.git] / aix4 / ppp_if.c
1 /*
2   ppp_if.c - Streams PPP interface module
3
4   top level module handles if_ and packetizing PPP packets.
5
6   Copyright (C) 1990  Brad K. Clements, All Rights Reserved
7   See copyright notice in NOTES
8
9 */
10
11 #define VJC     1
12 #include <sys/types.h>
13
14 #ifndef PPP_VD
15 #include "ppp.h"
16 #endif
17
18 #if NUM_PPP > 0
19
20 #define STREAMS 1
21
22 #define PPP_STATS       1       /* keep statistics */
23 #define DEBUGS          1
24
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>
30
31 #include <sys/device.h>
32 /*
33 #include <sys/user.h>
34 */
35 /*
36 #include <sys/systm.h>
37 */
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>
52
53 #include <net/ppp_defs.h>
54 #include <net/ppp_str.h>
55
56 #ifdef  VJC
57 #undef SPECIAL_I
58 #include <net/vjcompress.h>
59 #endif
60
61 #ifdef  PPP_STATS
62 #define INCR(comp)      ++p->pii_stats.comp
63 #else
64 #define INCR(comp)
65 #endif
66
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 (?) */
71
72 /*
73  * Network protocols we support.
74  */
75 #define NP_IP           0
76 #define NUM_NP          1       /* # protocols supported */
77
78 /*
79  * Structure used within the ppp_if streams module.
80  */
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 #endif
94 };
95
96 /*
97  * Values for pii_flags.
98  */
99 #define PII_FLAGS_INUSE         0x1     /* in use by  a stream  */
100 #define PII_FLAGS_ATTACHED      0x8     /* already if_attached  */
101 #define PII_FLAGS_VJC_ON        0x10    /* VJ TCP header compression enabled */
102 #define PII_FLAGS_VJC_NOCCID    0x20    /* VJ: don't compress conn. id */
103 #define PII_FLAGS_VJC_REJ       0x40    /* receive: reject VJ comp */
104 #define PII_FLAGS_DEBUG         0x80    /* enable debug printout */
105
106 #ifdef  DEBUGS
107 #include <sys/syslog.h>
108 #define DLOG(s,a) if (p->pii_flags&PII_FLAGS_DEBUG) bsdlog(LOG_INFO, s, a)
109 #else
110 #define DLOG(s) {}
111 #endif
112
113 #ifdef PPP_SNIT
114 #include <net/nit_if.h>
115 #include <netinet/if_ether.h>
116 /* Use a fake link level header to make etherfind and tcpdump happy. */
117 static struct ether_header header = {{1}, {2}, ETHERTYPE_IP};
118 static struct nit_if nif = {(caddr_t)&header, sizeof(header), 0, 0};
119 #endif
120
121 static  int     ppp_if_open(), ppp_if_close(), ppp_if_rput(), ppp_if_wput(),
122                 ppp_if_wsrv(), ppp_if_rsrv();
123
124 static  struct  module_info     minfo ={
125         0xbad,"ppp_if",0, INFPSZ, 16384, 4096
126 };
127
128 static  struct  qinit   r_init = {
129         ppp_if_rput, ppp_if_rsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL
130 };
131 static  struct  qinit   w_init = {
132         ppp_if_wput, ppp_if_wsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL
133 };
134 struct  streamtab       ppp_ifinfo = {
135         &r_init, &w_init, NULL, NULL
136 };
137
138 typedef struct ppp_if_info      PII;
139
140 PII     *pii;
141
142 int ppp_output(), ppp_ioctl();
143 static void if_release_addrs(), if_delete_route();
144
145 strconf_t pppconf = {
146     "pppif", &ppp_ifinfo, STR_NEW_OPEN, 0, SQLVL_DEFAULT, (void *) 0
147 };
148
149 int ppp_load(int cmd, struct uio *uiop)
150 {
151     int rc = 0;
152
153     switch (cmd) {
154         case CFG_INIT:
155             rc = str_install(STR_LOAD_MOD, &pppconf);
156             break;
157         case CFG_TERM:
158             rc = str_install(STR_UNLOAD_MOD, &pppconf);
159             break;
160         default:
161             rc = EINVAL;
162             break;
163     }
164     if ((rc == 0) && !(pii = xmalloc(sizeof(PII) * NUM_PPP, 0, pinned_heap)))
165         rc = ENOMEM;
166     else
167         bzero(pii, sizeof(PII) * NUM_PPP);
168
169     return(rc);
170 }
171
172 int
173 ppp_attach(unit)
174     int unit;
175 {
176     register struct ifnet *ifp = &pii[unit].pii_ifnet;
177
178     ifp->if_name = "ppp";
179     ifp->if_type = IFT_PTPSERIAL;
180     ifp->if_mtu  = PPP_MTU;
181     ifp->if_flags = IFF_POINTOPOINT;
182     ifp->if_unit  = unit;
183     ifp->if_ioctl = ppp_ioctl;
184     ifp->if_output = ppp_output;
185     ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
186     if_attach(ifp);
187     if_nostat(ifp);
188     pii[unit].pii_flags |= PII_FLAGS_ATTACHED;
189 }
190
191
192 int
193 ppp_unattach(unit)
194     int unit;
195 {
196     struct ifnet *ifp = &pii[unit].pii_ifnet;
197     struct ifnet **p;
198     int s;
199
200     if (!(pii[unit].pii_flags & PII_FLAGS_ATTACHED))
201         return 0;
202
203     /* remove interface from interface list */
204     for (p = &ifp; *p; p = &((*p)->if_next)) {
205         if (*p == ifp) {
206             *p = (*p)->if_next;
207
208             /* mark it down and flush it's que */
209             if_down(ifp);
210
211             /* free any addresses hanging off the intf */
212             if_release_addrs(ifp);
213
214             pii[unit].pii_flags &= ~PII_FLAGS_ATTACHED;
215
216             return 0;
217         }
218     }
219
220     return -1;
221 }
222
223
224 static void
225 if_release_addrs(ifp)
226 register struct ifnet *ifp;
227 {
228     register struct in_ifaddr **addr;
229     register struct ifaddr *ifa, *ifanxt;
230     register int s;
231  
232     if_delete_route(ifp);
233  
234     for (addr = &in_ifaddr; *addr; ) {
235         if ((*addr)->ia_ifp == ifp)
236             *addr = (*addr)->ia_next;
237         else
238             addr = &((*addr)->ia_next);
239     }
240  
241     /*
242      * Free all mbufs holding down this interface's address(es).
243      */
244     for (ifa = ifp->if_addrlist; ifa; ifa = ifanxt) {
245         ifanxt = ifa->ifa_next;
246         m_free(dtom(ifa));
247     }
248     ifp->if_addrlist = 0;
249 }
250
251 /*
252  * Delete routes to the specified interface.
253  * Hacked from rtrequest().
254  */
255 static void
256 if_delete_route(ifp)
257 struct ifnet *ifp;
258 {
259     extern int rttrash;         /* routes not in table but not freed */
260     register struct mbuf **mprev, *m;
261     register struct rtentry *route;
262     register int i;
263  
264     /* search host rt tbl */
265 /*
266     for (i = 0; i < RTHASHSIZ; i++) {
267         mprev = &rthost[i];
268         while (m = *mprev) {
269             route = mtod(m, struct rtentry *);
270             if (route->rt_ifp == ifp) {
271                 *mprev = m->m_next;
272                 if (route->rt_refcnt > 0) {
273                     route->rt_flags &= ~RTF_UP;
274                     rttrash++;
275                     m->m_next = 0;
276                 } else {
277                     m_free(m);
278                 }
279             } else
280                 mprev = &m->m_next;
281         }
282     }
283 */
284  
285     /* search net rt tbl */
286 /*
287     for (i = 0; i < RTHASHSIZ; i++) {
288         mprev = &rtnet[i];
289         while (m = *mprev) {
290             route = mtod(m, struct rtentry *);
291             if (route->rt_ifp == ifp) {
292                 *mprev = m->m_next;
293                 if (route->rt_refcnt > 0) {
294                     route->rt_flags &= ~RTF_UP;
295                     rttrash++;
296                     m->m_next = 0;
297                 } else {
298                     m_free(m);
299                 }
300             } else
301                 mprev = &m->m_next;
302         }
303     }
304 */
305
306
307 int
308 ppp_busy()
309 {
310     int x;
311
312     for (x = 0; x < NUM_PPP; x++) {
313         if (pii[x].pii_flags & PII_FLAGS_INUSE)
314             return 1;
315     }
316     return 0;
317 }
318
319 static PII *
320 ppp_if_alloc()
321 {
322     int s, x;
323     PII *p;
324
325     for (x = 0; x < NUM_PPP; x++)
326         if (!(pii[x].pii_flags & PII_FLAGS_INUSE))
327             break;
328     if (x == NUM_PPP) {         /* all buffers in use */
329         return NULL;
330     }
331     p = &pii[x];
332     p->pii_flags |= PII_FLAGS_INUSE;
333     return p;
334 }
335
336 static void
337 ppp_if_init(q, p)
338     queue_t *q;
339     PII *p;
340 {
341     int s, n;
342
343
344 #ifdef  VJC
345     vj_compress_init(&p->pii_sc_comp, -1);
346 #endif
347 #ifdef  PPP_STATS
348     bzero(&p->pii_stats, sizeof(p->pii_stats));
349 #endif
350     if (!(p->pii_flags & PII_FLAGS_ATTACHED))
351         ppp_attach(p - pii);                    /* attach it */
352     else
353         p->pii_ifnet.if_mtu = PPP_MTU;
354     p->pii_writeq = WR(q);
355     /* set write Q and read Q to point here */
356     WR(q)->q_ptr = q->q_ptr = (caddr_t) p;
357     p->pii_ifnet.if_flags |= IFF_RUNNING;
358     p->pii_flags &= PII_FLAGS_INUSE | PII_FLAGS_ATTACHED | PII_FLAGS_DEBUG;
359     for (n = 0; n < NUM_NP; ++n)
360         p->pii_npmode[n] = NPMODE_ERROR;
361     p->pii_npmode[NP_IP] = NPMODE_PASS; /* for backwards compatibility */
362     p->pii_npq = NULL;
363     p->pii_npq_tail = &p->pii_npq;
364
365     DLOG("ppp_if%d: init\n", p - pii);
366 }
367
368 static int
369 ppp_if_open(q, dev, flag, sflag)
370     queue_t     *q;
371     dev_t       dev;
372     int         flag, sflag;
373
374 {
375     if (!suser()) {
376         return(EPERM);
377     }
378
379     return (0);
380 }
381
382 static int
383 ppp_if_close(q)
384     queue_t     *q;                     /* queue info */
385 {
386     PII *p = (PII *) q->q_ptr;
387     int s, n;
388     mblk_t *mp, *mq;
389
390     if (p != NULL) {
391         if_down(&p->pii_ifnet);
392         p->pii_ifnet.if_flags &= ~IFF_RUNNING;
393         p->pii_flags &= ~PII_FLAGS_INUSE;
394         q->q_ptr = NULL;
395         for (mp = p->pii_npq; mp != NULL; mp = mq) {
396             mq = mp->b_next;
397             freemsg(mp);
398         }
399         p->pii_npq = NULL;
400         p->pii_npq_tail = &p->pii_npq;
401         DLOG("ppp_if%d: closed\n", p - pii);
402     }
403     return(0);                  /* no work to be done */
404 }
405
406
407 static int
408 ppp_if_wput(q, mp)
409     queue_t  *q;
410     register mblk_t *mp;
411 {
412     register struct iocblk *i;
413     register PII *p;
414     int bits, flags, error, unit, s;
415     queue_t *oq;
416     int npix;
417     struct npioctl *npi;
418     mblk_t *mq, **mqnext;
419     struct ppp_stats *psp;
420
421     switch (mp->b_datap->db_type) {
422
423     case M_FLUSH:
424         if (*mp->b_rptr & FLUSHW)
425             flushq(q, FLUSHDATA);
426         putnext(q, mp);         /* send it along too */
427         break;
428
429     case M_DATA:
430         putq(q, mp);    /* queue it for my service routine */
431         break;
432
433     case M_IOCTL:
434         i = (struct iocblk *) mp->b_rptr;
435         p = (PII *) q->q_ptr;
436         switch ((unsigned int)i->ioc_cmd) {
437
438         case SIOCSIFVJCOMP:     /* enable or disable VJ compression */
439 #ifdef  VJC
440             if (i->ioc_count == TRANSPARENT) {
441                 bits = *(u_int *) mp->b_cont->b_rptr;
442                 DLOG("ppp_if: SIFVJCOMP %d\n", bits);
443                 if (bits & 1) 
444                     p->pii_flags |= PII_FLAGS_VJC_ON;
445                 else
446                     p->pii_flags &= ~PII_FLAGS_VJC_ON;
447                 if (bits & 2)
448                     p->pii_flags |= PII_FLAGS_VJC_NOCCID;
449                 else
450                     p->pii_flags &= ~PII_FLAGS_VJC_NOCCID;
451                 if (bits & 4)
452                     p->pii_flags |= PII_FLAGS_VJC_REJ;
453                 else
454                     p->pii_flags &= ~PII_FLAGS_VJC_REJ;
455                 bits >>= 4;             /* now max conn id. */
456                 if (bits)
457                     vj_compress_init(&p->pii_sc_comp, bits);
458                 mp->b_datap->db_type = M_IOCACK;
459                 i->ioc_count = 0;
460                 qreply(q, mp);
461                 break;
462             }
463 #endif
464             putnext(q, mp);
465             break;
466
467         case SIOCGETU:  /* get unit number */
468             /*
469              * Allocate a unit if we don't already have one.
470              */
471             error = 0;
472             if (p == (PII *) 0) {
473                 p = ppp_if_alloc();
474                 if (p == NULL)
475                     error = ENOBUFS;
476                 else
477                     ppp_if_init(RD(q), p);
478             }
479             if (error == 0
480                 && (mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL)
481                 error = ENOSR;
482             if (error == 0) {
483                 *(int *) mp->b_cont->b_wptr = p->pii_ifnet.if_unit;
484                 mp->b_cont->b_wptr += i->ioc_count = sizeof(int);
485                 mp->b_datap->db_type = M_IOCACK;
486             } else {
487                 i->ioc_error = error;
488                 i->ioc_count = 0;
489                 mp->b_datap->db_type = M_IOCNAK;
490             }
491             qreply(q,mp);
492             break;
493
494         case SIOCSETU:  /* set unit number */
495             if ((i->ioc_count == sizeof(int)) ||
496                 (i->ioc_count == TRANSPARENT)) {
497                 unit = *(int *)mp->b_cont->b_rptr;
498                 if (p != NULL || (unsigned) unit > NUM_PPP) {
499                     mp->b_datap->db_type = M_IOCNAK;
500                     i->ioc_error = EINVAL;
501                     i->ioc_count = 0;
502                     error = EINVAL;
503                 } else {
504                     p = &pii[unit];
505                     if (p->pii_flags & PII_FLAGS_INUSE) {
506                         oq = p->pii_writeq;
507                         oq->q_ptr = RD(oq)->q_ptr = NULL;
508                         q->q_ptr = RD(q)->q_ptr = (caddr_t) p;
509                         p->pii_writeq = q;
510                     } else {
511                         ppp_if_init(RD(q), p);
512                     }
513                     mp->b_datap->db_type = M_IOCACK;
514                 }
515                 qreply(q, mp);
516                 break;
517             }
518             putnext(q, mp);
519             break;
520
521         case SIOCSIFDEBUG :
522             /* catch it on the way past to set our debug flag as well */
523             if (i->ioc_count == TRANSPARENT) {
524                 flags = *(int *)mp->b_cont->b_rptr;
525                 if (flags & 1)
526                     p->pii_flags |= PII_FLAGS_DEBUG;
527                 else
528                     p->pii_flags &= ~PII_FLAGS_DEBUG;
529             }
530             putnext(q, mp);
531             break;
532
533         case SIOCGETNPMODE:
534         case SIOCSETNPMODE:
535             if (i->ioc_count == TRANSPARENT && p != NULL) {
536                 npi = *((struct npioctl **) mp->b_cont->b_rptr);
537                 switch (npi->protocol) {
538                 case PPP_IP:
539                     npix = NP_IP;
540                     break;
541                 default:
542                     npix = -1;
543                 }
544                 if (npix < 0) {
545                     i->ioc_error = EAFNOSUPPORT;
546                     i->ioc_count = 0;
547                     mp->b_datap->db_type = M_IOCNAK;
548                     qreply(q, mp);
549                     break;
550                 }
551                 if (i->ioc_cmd == SIOCSETNPMODE) {
552                     if (p->pii_npmode[npix] == NPMODE_QUEUE
553                         && npi->mode != NPMODE_QUEUE) {
554                         for (mqnext = &p->pii_npq; (mq = *mqnext) != NULL; ) {
555                             if (PPP_PROTOCOL(mq->b_rptr) != npi->protocol){
556                                 mqnext = &mq->b_next;
557                                 continue;
558                             }
559                             *mqnext = mq->b_next;
560                             if (npi->mode == NPMODE_PASS) {
561                                 putq(q, mq); /* q it for service routine */
562                             } else {
563                                 freemsg(mq);
564                             }
565                         }
566                         p->pii_npq_tail = mqnext;
567                     }
568                     p->pii_npmode[npix] = npi->mode;
569                     i->ioc_count = 0;
570                 } else
571                     npi->mode = p->pii_npmode[npix];
572                 mp->b_datap->db_type = M_IOCACK;
573                 qreply(q, mp);
574                 break;
575             }
576             putnext(q, mp);
577             break;
578
579         default:                /* unknown IOCTL call */
580             putnext(q, mp);     /* pass it along */
581         }
582         break;
583
584     default:
585         putnext(q, mp); /* don't know what to do with this, so send it along*/
586     }
587 }
588
589 static int
590 ppp_if_wsrv(q)
591     queue_t     *q;
592 {
593     register mblk_t *mp;
594     register PII *p;
595
596     p = (PII *) q->q_ptr;
597
598     while ((mp = getq(q)) != NULL) {
599         /*
600          * we can only get M_DATA types into our Queue,
601          * due to our Put function
602          */
603         if (!canput(q->q_next)) {
604             putbq(q, mp);
605             return;
606         }
607
608         /* increment count of outgoing packets */
609         if (p != NULL)
610             INCR(ppp_opackets);
611
612         /* just pass it along, nothing to do in this direction */
613         putnext(q, mp);
614     }   /* end while */
615 }
616
617
618 static int
619 ppp_if_rput(q, mp)
620     queue_t *q;
621     register mblk_t *mp;
622 {
623     register u_char     c;
624     register PII        *p;
625
626     switch (mp->b_datap->db_type) {
627
628     case M_FLUSH:
629         if (*mp->b_rptr & FLUSHR)
630             flushq(q, FLUSHDATA);
631         putnext(q, mp);         /* send it along too */
632         break;
633
634     case M_DATA:
635         putq(q, mp);            /* queue it for my service routine */
636         break;
637
638     case M_CTL:
639         p = (PII *) q->q_ptr;
640         if (p != NULL) {
641             c = *(u_char *) mp->b_rptr;
642             switch (c) {
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             }
656         }
657         putnext(q, mp);         /* send it up to pppd */
658         break;
659
660     default:
661         putnext(q, mp);         /* send along other message types */
662     }
663 }
664
665 static int
666 ppp_if_rsrv(q)
667     queue_t     *q;
668 {
669     register mblk_t *mp,*m0;
670 #ifdef  VJC
671     register mblk_t *mvjc;
672     unsigned char *cp, *iphdr;
673     u_int hlen;
674 #endif
675     register PII *p;
676     struct mbuf *mb1, *mb2, *mbtail;
677     struct ifnet        *ifp;
678     int len, xlen, count, s, pklen;
679     u_char *rptr;
680     int address, control;
681
682     p = (PII *) q->q_ptr;
683
684     while ((mp = getq(q)) != NULL) {
685         /*
686          * we can only get M_DATA types into our Queue,
687          * due to our Put function
688          */
689
690         if (p == NULL) {
691             if (!canput(q->q_next)) {
692                 putbq(q, mp);
693                 return;
694             }
695             putnext(q, mp);
696             continue;
697         }
698
699         len = msgdsize(mp);
700 #ifdef  PPP_STATS
701         p->pii_stats.ppp_ibytes += len;
702 #endif
703
704         /* make sure ppp_header is completely in first block */
705         if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
706             && !pullupmsg(mp, PPP_HDRLEN)) {
707             DLOG("pullupmsg failed!\n", 0);
708             freemsg(mp);
709             p->pii_ifnet.if_ierrors++;
710             continue;
711         }
712         m0 = mp;        /* remember first message block */
713
714 #ifdef  VJC
715         switch (PPP_PROTOCOL(mp->b_rptr)) {
716         case PPP_VJC_COMP :
717             if ((p->pii_flags & PII_FLAGS_VJC_REJ)
718                 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
719                 DLOG("VJC rejected\n", 0);
720                 freemsg(mp);
721                 continue;                               
722             }
723             address = PPP_ADDRESS(mp->b_rptr);
724             control = PPP_CONTROL(mp->b_rptr);
725             mp->b_rptr += PPP_HDRLEN;
726             len -= PPP_HDRLEN;
727
728             /*
729              * Make sure the VJ header is in one message block.
730              */
731             xlen = MIN(len, MAX_VJHDR);
732             if (mp->b_rptr + xlen > mp->b_wptr && !pullupmsg(mp, xlen)) {
733                 DLOG("pullupmsg vjc %d failed\n", xlen);
734                 freemsg(mp);
735                 continue;
736             }
737
738             /*
739              * Decompress it, then get a buffer and put the
740              * decompressed header in it.
741              */
742             xlen = vj_uncompress_tcp(mp->b_rptr, mp->b_wptr - mp->b_rptr,
743                                      len, &p->pii_sc_comp, &iphdr, &hlen);
744             if (xlen < 0) {
745                 DLOG("ppp: vj_uncompress failed on type Compressed\n", 0);
746                 freemsg(mp);
747                 continue;
748             }
749             if (!(mvjc = allocb(hlen + PPP_HDRLEN, BPRI_MED))) {
750                 DLOG("allocb mvjc failed (%d)\n", hlen + PPP_HDRLEN);
751                 freemsg(mp);
752                 continue;
753             }
754             cp = mvjc->b_rptr;
755             cp[0] = address;
756             cp[1] = control;
757             cp[2] = 0;
758             cp[3] = PPP_IP;
759             bcopy(iphdr, cp + PPP_HDRLEN, hlen);
760             mvjc->b_wptr = cp + PPP_HDRLEN + hlen;
761             mvjc->b_cont = mp;
762             mp->b_rptr += xlen;
763             m0 = mp = mvjc;
764             len += PPP_HDRLEN + hlen;
765             break;
766
767         case PPP_VJC_UNCOMP :
768             if ((p->pii_flags & PII_FLAGS_VJC_REJ)
769                 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
770                 DLOG("VJU rejected\n", 0);
771                 freemsg(mp);
772                 continue;
773             }
774
775             /*
776              * Make sure the IP header is in one message block.
777              */
778             xlen = MIN(len, MAX_IPHDR + PPP_HDRLEN);
779             if (mp->b_rptr + xlen > mp->b_wptr && !pullupmsg(mp, xlen)) {
780                 DLOG("pullupmsg vju %d failed\n", xlen);
781                 freemsg(mp);
782                 continue;
783             }
784
785             /*
786              * "Uncompress" it.  Basically this just copies information
787              * into p->pii_sc_comp and restores the protocol field of
788              * the IP header.
789              */
790             if (!vj_uncompress_uncomp(mp->b_rptr + PPP_HDRLEN,
791                                       &p->pii_sc_comp)) {
792                 DLOG("ppp: vj_uncompress failed on type Uncompresed\n", 0);
793                 freemsg(mp);
794                 continue;
795             }
796             mp->b_rptr[3] = PPP_IP;
797             break;
798         }
799 #endif
800
801         switch (PPP_PROTOCOL(mp->b_rptr)) {
802         default:
803             if (!canput(q->q_next)) {
804                 putbq(q, mp);
805                 return;
806             }
807             INCR(ppp_ipackets);
808             p->pii_ifnet.if_ipackets++;
809             putnext(q, mp);
810             continue;
811
812         case PPP_IP:
813             /*
814              * Don't let packets through until IPCP is up.
815              */
816             INCR(ppp_ipackets);
817             p->pii_ifnet.if_ipackets++;
818
819             if (!(p->pii_ifnet.if_flags & IFF_UP)
820                 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
821                 DLOG("pkt ignored - IP down\n", 0);
822                 freemsg(mp);
823                 continue;
824             }
825
826             /*
827              * Get the first mbuf and put the struct ifnet * in.
828              */
829             MGETHDR(mb1, M_DONTWAIT, MT_DATA);
830             mb1->m_len = 0;
831             if (mb1 == NULL) {
832                 p->pii_ifnet.if_ierrors++;
833                 freemsg(m0);
834                 continue;
835             }
836             len = MHLEN;
837             mbtail = mb2 = mb1;
838             pklen = 0;
839
840             rptr = mp->b_rptr + PPP_HDRLEN;
841             xlen = mp->b_wptr - rptr;
842             for(;;) {
843                 if (xlen == 0) {        /* move to the next mblk */
844                     mp = mp->b_cont;
845                     if (mp == NULL)
846                         break;
847                     xlen = mp->b_wptr - (rptr = mp->b_rptr);
848                     continue;
849                 }
850                 if (len == 0) {
851                     MGET(mb2, M_DONTWAIT, MT_DATA);
852                     if (!mb2) {
853                         /* if we couldn't get a buffer, drop the packet */
854                         p->pii_ifnet.if_ierrors++;
855                         m_freem(mb1);   /* discard what we've used already */
856                         mb1 = NULL;
857                         break;
858                     }
859                     len = MLEN;
860                     mb2->m_len = 0;
861                     mbtail->m_next = mb2;
862                     mbtail = mb2;
863                 }
864                 count = MIN(xlen, len);
865                 bcopy((char *) rptr, mtod(mb2, char *) + mb2->m_len, count);
866                 rptr += count;
867                 len -= count;
868                 xlen -= count;
869                 pklen += count;
870                 mb2->m_len += count;
871             }
872
873             freemsg(m0);
874             if (mb1 == NULL)
875                 continue;
876
877 #ifdef PPP_SNIT
878             if (p->pii_ifnet.if_flags & IFF_PROMISC) {
879                 struct mbuf *m = mb1;
880
881                 len = 0;
882                 do {
883                     len += m->m_len;
884                 } while (m = m->m_next);
885                 nif.nif_bodylen = len - sizeof(struct ifnet *);
886                 mb1->m_off += sizeof(struct ifnet *);
887                 snit_intr(&p->pii_ifnet, mb1, &nif);
888                 mb1->m_off -= sizeof(struct ifnet *);
889             }
890 #endif
891 /*
892             if (IF_QFULL(&ipintrq)) {
893                 IF_DROP(&ipintrq);
894                 p->pii_ifnet.if_ierrors++;
895                 m_freem(mb1);
896             }
897             else {
898 */
899             ifp =  &p->pii_ifnet;
900             mb1->m_pkthdr.len = pklen;
901             mb1->m_pkthdr.rcvif = ifp;
902             find_input_type(0x0800, mb1, ifp, 0);
903         }
904     }   /* end while */
905 }
906
907 /* ifp output procedure */
908 int
909 ppp_output(ifp, m0, dst)
910     struct ifnet *ifp;
911     struct mbuf *m0;
912     struct sockaddr *dst;
913 {
914     register PII *p = &pii[ifp->if_unit];
915     struct mbuf *m1;
916     int error, s, len;
917     u_short protocol;
918 #ifdef  VJC
919     int type;
920     u_char *vjhdr;
921 #endif
922     mblk_t *mp;
923     enum NPmode npmode;
924
925     error = 0;
926     if (!(ifp->if_flags & IFF_UP)) {
927         error = ENETDOWN;
928         goto getout;
929     }
930
931     switch (dst->sa_family) {
932 #ifdef  INET
933     case AF_INET:
934 #ifdef PPP_SNIT
935         if (ifp->if_flags & IFF_PROMISC) {
936             struct mbuf *m = m0;
937
938             len = 0;
939             do {
940                 len += m->m_len;
941             } while (m = m->m_next);
942             nif.nif_bodylen = len;
943             snit_intr(ifp, m0, &nif);
944         }
945 #endif
946         protocol = PPP_IP;
947         npmode = p->pii_npmode[NP_IP];
948         break;
949 #endif
950
951     default:
952         DLOG("ppp: af%d not supported\n", dst->sa_family);
953         error = EAFNOSUPPORT;
954         goto getout;
955     }
956
957     if (!p->pii_writeq) {
958         DLOG("ppp_if%d: no queue\n", p - pii);
959         error = EHOSTUNREACH;
960         goto getout;
961     }
962
963     switch (npmode) {
964     case NPMODE_DROP:
965         goto getout;
966     case NPMODE_ERROR:
967         error = ENETDOWN;
968         goto getout;
969     }
970
971 #ifdef  VJC
972     if ((protocol == PPP_IP) && (p->pii_flags & PII_FLAGS_VJC_ON)) {
973         register struct ip *ip;
974         ip = mtod(m0, struct ip *);
975         if (ip->ip_p == IPPROTO_TCP) {
976             type = vj_compress_tcp(ip, m0->m_len, &p->pii_sc_comp,
977                                    !(p->pii_flags & PII_FLAGS_VJC_NOCCID),
978                                    &vjhdr);
979             switch (type) {
980             case TYPE_UNCOMPRESSED_TCP :
981                 protocol = PPP_VJC_UNCOMP;
982                 break;
983             case TYPE_COMPRESSED_TCP :
984                 protocol = PPP_VJC_COMP;
985                 len = vjhdr - (u_char *) ip;
986                 m0->m_data += len;
987                 m0->m_len -= len;
988                 break;  
989             }
990         }
991     }
992 #endif
993
994     len = PPP_HDRLEN;
995     for (m1 = m0; m1; m1 = m1->m_next) 
996         len += m1->m_len;
997
998     if (!(mp = allocb(len, BPRI_MED))) {
999         DLOG("ppp_if%d: allocb failed\n", p - pii);
1000         error = ENOBUFS;
1001         goto getout;
1002     }
1003
1004 #ifdef  PPP_STATS
1005     p->pii_stats.ppp_obytes += len;
1006 #endif
1007
1008     *mp->b_wptr++ = PPP_ALLSTATIONS;
1009     *mp->b_wptr++ = PPP_UI;
1010     *mp->b_wptr++ = 0;
1011     *mp->b_wptr++ = protocol;
1012     for (m1 = m0; m1; m1 = m1->m_next) {        /* copy all data */
1013         bcopy(mtod(m1, char *), (char *) mp->b_wptr, m1->m_len);
1014         mp->b_wptr += m1->m_len;
1015     }
1016
1017     p->pii_ifnet.if_opackets++;
1018 DLOG("ppp_output npmode is %d\n",npmode);
1019     if (npmode == NPMODE_PASS) {
1020         putq(p->pii_writeq, mp);
1021     } else {
1022         mp->b_next = NULL;
1023         *p->pii_npq_tail = mp;
1024         p->pii_npq_tail = &mp;
1025     }
1026
1027  getout:
1028     m_freem(m0);
1029     if (error) {
1030         INCR(ppp_oerrors);
1031         p->pii_ifnet.if_oerrors++;
1032     }
1033     return (error);
1034 }
1035
1036 /*
1037  * if_ ioctl requests 
1038 */
1039 ppp_ioctl(ifp, cmd, data)
1040     register struct ifnet *ifp;
1041     unsigned int        cmd;
1042     caddr_t     data;
1043 {
1044     register struct ifaddr *ifa = (struct ifaddr *) data;
1045     register struct ifreq *ifr = (struct ifreq *) data;
1046     struct ppp_stats *psp;
1047     struct ppp_comp_stats *pcp;
1048     PII *p;
1049     int error = 0;
1050
1051     switch (cmd) {
1052     case SIOCSIFFLAGS :
1053         /* This happens every time IFF_PROMISC has been changed. */
1054         if (!ifr)
1055             break;
1056         if (!suser()) {
1057             error = EPERM;
1058             break;
1059         }
1060
1061         /* clear the flags that can be cleared */
1062         ifp->if_flags &= (IFF_CANTCHANGE);      
1063         /* or in the flags that can be changed */
1064         ifp->if_flags |= (ifr->ifr_flags & ~IFF_CANTCHANGE);
1065         break;
1066
1067     case SIOCGIFFLAGS :
1068         ifr->ifr_flags = ifp->if_flags;
1069         break;
1070
1071     case SIOCSIFADDR :
1072         if( ifa->ifa_addr->sa_family != AF_INET) 
1073             error = EAFNOSUPPORT;
1074         break;
1075
1076     case SIOCSIFDSTADDR :
1077         if (ifa->ifa_addr->sa_family != AF_INET)
1078             error = EAFNOSUPPORT;
1079         break;
1080
1081     case SIOCSIFMTU :
1082         if (!suser()) {
1083             error = EPERM;
1084             break;
1085         }
1086         if (ifr->ifr_mtu > MAX_PKTSIZE - PPP_FRAMING) {
1087             error = EINVAL;
1088             break;
1089         }
1090         ifp->if_mtu = ifr->ifr_mtu;
1091         break;
1092
1093     case SIOCGIFMTU :
1094         ifr->ifr_mtu = ifp->if_mtu;
1095         break;
1096
1097     case SIOCGPPPSTATS:
1098         p = &pii[ifp->if_unit];
1099         psp = (struct ppp_stats *) &((struct ifpppstatsreq *)data)->stats;
1100         bzero(psp, sizeof(struct ppp_stats));
1101 #ifdef PPP_STATS
1102         psp->p = p->pii_stats;
1103 #endif
1104 #if defined(VJC) && !defined(VJ_NO_STATS)
1105         psp->vj = p->pii_sc_comp.stats;
1106 #endif
1107         break;
1108
1109     case SIOCGPPPCSTATS:
1110         p = &pii[ifp->if_unit];
1111         pcp = (struct ppp_comp_stats *)&((struct ifpppcstatsreq *)data)->stats;
1112         bzero(pcp, sizeof(struct ppp_comp_stats));
1113         /* XXX we need to fill in the compression stats */
1114         break;
1115
1116     default :
1117         error = EINVAL;
1118         break;
1119     }
1120     return(error);
1121 }
1122
1123 #endif