Updates from Charlie Wick
[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     struct ppp_comp_stats pii_cstats;
94 #endif
95 };
96
97 /*
98  * Values for pii_flags.
99  */
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 */
106
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
113
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
121
122 static  int     ppp_if_open(), ppp_if_close(), ppp_if_rput(), ppp_if_wput(),
123                 ppp_if_wsrv(), ppp_if_rsrv();
124
125 static  struct  module_info     minfo ={
126         0xbad,"ppp_if",0, INFPSZ, 16384, 4096
127 };
128
129 static  struct  qinit   r_init = {
130         ppp_if_rput, ppp_if_rsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL
131 };
132 static  struct  qinit   w_init = {
133         ppp_if_wput, ppp_if_wsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL
134 };
135 struct  streamtab       ppp_ifinfo = {
136         &r_init, &w_init, NULL, NULL
137 };
138
139 typedef struct ppp_if_info      PII;
140
141 PII     *pii;
142
143 int ppp_output(), ppp_ioctl();
144 static void if_release_addrs(), if_delete_route();
145
146 strconf_t pppconf = {
147     "pppif", &ppp_ifinfo, STR_NEW_OPEN, 0, SQLVL_DEFAULT, (void *) 0
148 };
149
150 int ppp_load(int cmd, struct uio *uiop)
151 {
152     int rc = 0;
153
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;
164     }
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);
169
170     return(rc);
171 }
172
173 int
174 ppp_attach(unit)
175     int unit;
176 {
177     register struct ifnet *ifp = &pii[unit].pii_ifnet;
178
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;
190 }
191
192
193 int
194 ppp_unattach(unit)
195     int unit;
196 {
197     struct ifnet *ifp = &pii[unit].pii_ifnet;
198     struct ifnet **p;
199     int s;
200
201     if (!(pii[unit].pii_flags & PII_FLAGS_ATTACHED))
202         return 0;
203
204     /* remove interface from interface list */
205     for (p = &ifp; *p; p = &((*p)->if_next)) {
206         if (*p == ifp) {
207             *p = (*p)->if_next;
208
209             /* mark it down and flush it's que */
210             if_down(ifp);
211
212             /* free any addresses hanging off the intf */
213             if_release_addrs(ifp);
214
215             pii[unit].pii_flags &= ~PII_FLAGS_ATTACHED;
216
217             return 0;
218         }
219     }
220
221     return -1;
222 }
223
224
225 static void
226 if_release_addrs(ifp)
227 register struct ifnet *ifp;
228 {
229     register struct in_ifaddr **addr;
230     register struct ifaddr *ifa, *ifanxt;
231     register int s;
232  
233     if_delete_route(ifp);
234  
235     for (addr = &in_ifaddr; *addr; ) {
236         if ((*addr)->ia_ifp == ifp)
237             *addr = (*addr)->ia_next;
238         else
239             addr = &((*addr)->ia_next);
240     }
241  
242     /*
243      * Free all mbufs holding down this interface's address(es).
244      */
245     for (ifa = ifp->if_addrlist; ifa; ifa = ifanxt) {
246         ifanxt = ifa->ifa_next;
247         m_free(dtom(ifa));
248     }
249     ifp->if_addrlist = 0;
250 }
251
252 /*
253  * Delete routes to the specified interface.
254  * Hacked from rtrequest().
255  */
256 static void
257 if_delete_route(ifp)
258 struct ifnet *ifp;
259 {
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;
264  
265     /* search host rt tbl */
266 /*
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);
279                 }
280             } else
281                 mprev = &m->m_next;
282         }
283     }
284 */
285  
286     /* search net rt tbl */
287 /*
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);
300                 }
301             } else
302                 mprev = &m->m_next;
303         }
304     }
305 */
306
307
308 int
309 ppp_busy()
310 {
311     int x;
312
313     for (x = 0; x < NUM_PPP; x++) {
314         if (pii[x].pii_flags & PII_FLAGS_INUSE)
315             return 1;
316     }
317     return 0;
318 }
319
320 static PII *
321 ppp_if_alloc()
322 {
323     int s, x;
324     PII *p;
325
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;
331     }
332     p = &pii[x];
333     p->pii_flags |= PII_FLAGS_INUSE;
334     return p;
335 }
336
337 static void
338 ppp_if_init(q, p)
339     queue_t *q;
340     PII *p;
341 {
342     int s, n;
343
344
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;
365
366     DLOG("ppp_if%d: init\n", p - pii);
367 }
368
369 static int
370 ppp_if_open(q, dev, flag, sflag)
371     queue_t     *q;
372     dev_t       dev;
373     int         flag, sflag;
374
375 {
376     if (!suser()) {
377         return(EPERM);
378     }
379
380     return (0);
381 }
382
383 static int
384 ppp_if_close(q)
385     queue_t     *q;                     /* queue info */
386 {
387     PII *p = (PII *) q->q_ptr;
388     int s, n;
389     mblk_t *mp, *mq;
390
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);
399         }
400         p->pii_npq = NULL;
401         p->pii_npq_tail = &p->pii_npq;
402         DLOG("ppp_if%d: closed\n", p - pii);
403     }
404     return(0);                  /* no work to be done */
405 }
406
407
408 static int
409 ppp_if_wput(q, mp)
410     queue_t  *q;
411     register mblk_t *mp;
412 {
413     register struct iocblk *i;
414     register PII *p;
415     int bits, flags, error, unit, s;
416     queue_t *oq;
417     int npix;
418     struct npioctl *npi;
419     mblk_t *mq, **mqnext;
420     struct ppp_stats *psp;
421
422     switch (mp->b_datap->db_type) {
423
424     case M_FLUSH:
425         if (*mp->b_rptr & FLUSHW)
426             flushq(q, FLUSHDATA);
427         putnext(q, mp);         /* send it along too */
428         break;
429
430     case M_DATA:
431         putq(q, mp);    /* queue it for my service routine */
432         break;
433
434     case M_IOCTL:
435         i = (struct iocblk *) mp->b_rptr;
436         p = (PII *) q->q_ptr;
437         switch ((unsigned int)i->ioc_cmd) {
438
439         case SIOCSIFVJCOMP:     /* enable or disable VJ compression */
440 #ifdef  VJC
441             if (i->ioc_count == TRANSPARENT) {
442                 bits = *(u_int *) mp->b_cont->b_rptr;
443                 DLOG("ppp_if: SIFVJCOMP %d\n", bits);
444                 if (bits & 1) 
445                     p->pii_flags |= PII_FLAGS_VJC_ON;
446                 else
447                     p->pii_flags &= ~PII_FLAGS_VJC_ON;
448                 if (bits & 2)
449                     p->pii_flags |= PII_FLAGS_VJC_NOCCID;
450                 else
451                     p->pii_flags &= ~PII_FLAGS_VJC_NOCCID;
452                 if (bits & 4)
453                     p->pii_flags |= PII_FLAGS_VJC_REJ;
454                 else
455                     p->pii_flags &= ~PII_FLAGS_VJC_REJ;
456                 bits >>= 4;             /* now max conn id. */
457                 if (bits)
458                     vj_compress_init(&p->pii_sc_comp, bits);
459                 mp->b_datap->db_type = M_IOCACK;
460                 i->ioc_count = 0;
461                 qreply(q, mp);
462                 break;
463             }
464 #endif
465             putnext(q, mp);
466             break;
467
468         case SIOCGETU:  /* get unit number */
469             /*
470              * Allocate a unit if we don't already have one.
471              */
472             error = 0;
473             if (p == (PII *) 0) {
474                 p = ppp_if_alloc();
475                 if (p == NULL)
476                     error = ENOBUFS;
477                 else
478                     ppp_if_init(RD(q), p);
479             }
480             if (error == 0
481                 && (mp->b_cont = allocb(sizeof(int), BPRI_MED)) == NULL)
482                 error = ENOSR;
483             if (error == 0) {
484                 *(int *) mp->b_cont->b_wptr = p->pii_ifnet.if_unit;
485                 mp->b_cont->b_wptr += i->ioc_count = sizeof(int);
486                 mp->b_datap->db_type = M_IOCACK;
487             } else {
488                 i->ioc_error = error;
489                 i->ioc_count = 0;
490                 mp->b_datap->db_type = M_IOCNAK;
491             }
492             qreply(q,mp);
493             break;
494
495         case SIOCSETU:  /* set unit number */
496             if ((i->ioc_count == sizeof(int)) ||
497                 (i->ioc_count == TRANSPARENT)) {
498                 unit = *(int *)mp->b_cont->b_rptr;
499                 if (p != NULL || (unsigned) unit > NUM_PPP) {
500                     mp->b_datap->db_type = M_IOCNAK;
501                     i->ioc_error = EINVAL;
502                     i->ioc_count = 0;
503                     error = EINVAL;
504                 } else {
505                     p = &pii[unit];
506                     if (p->pii_flags & PII_FLAGS_INUSE) {
507                         oq = p->pii_writeq;
508                         oq->q_ptr = RD(oq)->q_ptr = NULL;
509                         q->q_ptr = RD(q)->q_ptr = (caddr_t) p;
510                         p->pii_writeq = q;
511                     } else {
512                         ppp_if_init(RD(q), p);
513                     }
514                     mp->b_datap->db_type = M_IOCACK;
515                 }
516                 qreply(q, mp);
517                 break;
518             }
519             putnext(q, mp);
520             break;
521
522         case SIOCSIFDEBUG :
523             /* catch it on the way past to set our debug flag as well */
524             if (i->ioc_count == TRANSPARENT) {
525                 flags = *(int *)mp->b_cont->b_rptr;
526                 if (flags & 1)
527                     p->pii_flags |= PII_FLAGS_DEBUG;
528                 else
529                     p->pii_flags &= ~PII_FLAGS_DEBUG;
530             }
531             putnext(q, mp);
532             break;
533
534         case SIOCGETNPMODE:
535         case SIOCSETNPMODE:
536             if (i->ioc_count == TRANSPARENT && p != NULL) {
537                 npi = *((struct npioctl **) mp->b_cont->b_rptr);
538                 switch (npi->protocol) {
539                 case PPP_IP:
540                     npix = NP_IP;
541                     break;
542                 default:
543                     npix = -1;
544                 }
545                 if (npix < 0) {
546                     i->ioc_error = EAFNOSUPPORT;
547                     i->ioc_count = 0;
548                     mp->b_datap->db_type = M_IOCNAK;
549                     qreply(q, mp);
550                     break;
551                 }
552                 if (i->ioc_cmd == SIOCSETNPMODE) {
553                     if (p->pii_npmode[npix] == NPMODE_QUEUE
554                         && npi->mode != NPMODE_QUEUE) {
555                         for (mqnext = &p->pii_npq; (mq = *mqnext) != NULL; ) {
556                             if (PPP_PROTOCOL(mq->b_rptr) != npi->protocol){
557                                 mqnext = &mq->b_next;
558                                 continue;
559                             }
560                             *mqnext = mq->b_next;
561                             if (npi->mode == NPMODE_PASS) {
562                                 putq(q, mq); /* q it for service routine */
563                             } else {
564                                 freemsg(mq);
565                             }
566                         }
567                         p->pii_npq_tail = mqnext;
568                     }
569                     p->pii_npmode[npix] = npi->mode;
570                     i->ioc_count = 0;
571                 } else
572                     npi->mode = p->pii_npmode[npix];
573                 mp->b_datap->db_type = M_IOCACK;
574                 qreply(q, mp);
575                 break;
576             }
577             putnext(q, mp);
578             break;
579
580         default:                /* unknown IOCTL call */
581             putnext(q, mp);     /* pass it along */
582         }
583         break;
584
585     default:
586         putnext(q, mp); /* don't know what to do with this, so send it along*/
587     }
588 }
589
590 static int
591 ppp_if_wsrv(q)
592     queue_t     *q;
593 {
594     register mblk_t *mp;
595     register PII *p;
596
597     p = (PII *) q->q_ptr;
598
599     while ((mp = getq(q)) != NULL) {
600         /*
601          * we can only get M_DATA types into our Queue,
602          * due to our Put function
603          */
604         if (!canput(q->q_next)) {
605             putbq(q, mp);
606             return;
607         }
608
609         /* increment count of outgoing packets */
610         if (p != NULL)
611             INCR(ppp_opackets);
612
613         /* just pass it along, nothing to do in this direction */
614         putnext(q, mp);
615     }   /* end while */
616 }
617
618
619 static int
620 ppp_if_rput(q, mp)
621     queue_t *q;
622     register mblk_t *mp;
623 {
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             switch (*(u_char *) mp->b_rptr) {
642             case IF_INPUT_ERROR :
643                 p->pii_ifnet.if_ierrors++;
644                 INCR(ppp_ierrors);
645                 DLOG("ppp_if: input error inc to %d\n",
646                      p->pii_ifnet.if_ierrors);
647                 break;
648             case IF_OUTPUT_ERROR :
649                 p->pii_ifnet.if_oerrors++;
650                 INCR(ppp_oerrors);
651                 DLOG("ppp_if: output error inc to %d\n",
652                      p->pii_ifnet.if_oerrors);
653                 break;
654             case IF_CSTATS:
655                 bcopy(mp->b_rptr + sizeof(u_long), &p->pii_cstats,
656                       sizeof(struct ppp_comp_stats));
657                 freemsg(mp);
658                 break;
659             default:
660                 putnext(q, mp);         /* send it up to pppd */
661                 break;
662             }
663         }
664         break;
665
666     default:
667         putnext(q, mp);         /* send along other message types */
668     }
669 }
670
671 static int
672 ppp_if_rsrv(q)
673     queue_t     *q;
674 {
675     register mblk_t *mp,*m0;
676 #ifdef  VJC
677     register mblk_t *mvjc;
678     unsigned char *cp, *iphdr;
679     u_int hlen;
680 #endif
681     register PII *p;
682     struct mbuf *mb1, *mb2, *mbtail;
683     struct ifnet        *ifp;
684     int len, xlen, count, s, pklen;
685     u_char *rptr;
686     int address, control;
687     int dlen;
688
689     p = (PII *) q->q_ptr;
690
691     while ((mp = getq(q)) != NULL) {
692         /*
693          * we can only get M_DATA types into our Queue,
694          * due to our Put function
695          */
696
697         if (p == NULL) {
698             if (!canput(q->q_next)) {
699                 putbq(q, mp);
700                 return;
701             }
702             putnext(q, mp);
703             continue;
704         }
705
706         len = msgdsize(mp);
707         dlen = len - PPP_HDRLEN;
708 #ifdef  PPP_STATS
709         p->pii_stats.ppp_ibytes += len;
710 #endif
711
712         /* make sure ppp_header is completely in first block */
713         if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN
714             && !pullupmsg(mp, PPP_HDRLEN)) {
715             DLOG("pullupmsg failed!\n", 0);
716             freemsg(mp);
717             p->pii_ifnet.if_ierrors++;
718             continue;
719         }
720         m0 = mp;        /* remember first message block */
721
722 #ifdef  VJC
723         switch (PPP_PROTOCOL(mp->b_rptr)) {
724         case PPP_VJC_COMP :
725             if ((p->pii_flags & PII_FLAGS_VJC_REJ)
726                 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
727                 DLOG("VJC rejected\n", 0);
728                 freemsg(mp);
729                 continue;                               
730             }
731             address = PPP_ADDRESS(mp->b_rptr);
732             control = PPP_CONTROL(mp->b_rptr);
733             mp->b_rptr += PPP_HDRLEN;
734             len -= PPP_HDRLEN;
735
736             /*
737              * Make sure the VJ header is in one message block.
738              */
739             xlen = MIN(len, MAX_VJHDR);
740             if (mp->b_rptr + xlen > mp->b_wptr && !pullupmsg(mp, xlen)) {
741                 DLOG("pullupmsg vjc %d failed\n", xlen);
742                 freemsg(mp);
743                 continue;
744             }
745
746             /*
747              * Decompress it, then get a buffer and put the
748              * decompressed header in it.
749              */
750             xlen = vj_uncompress_tcp(mp->b_rptr, mp->b_wptr - mp->b_rptr,
751                                      len, &p->pii_sc_comp, &iphdr, &hlen);
752             if (xlen < 0) {
753                 DLOG("ppp: vj_uncompress failed on type Compressed\n", 0);
754                 freemsg(mp);
755                 continue;
756             }
757             if (!(mvjc = allocb(hlen + PPP_HDRLEN, BPRI_MED))) {
758                 DLOG("allocb mvjc failed (%d)\n", hlen + PPP_HDRLEN);
759                 freemsg(mp);
760                 continue;
761             }
762             dlen = len - xlen + hlen;
763             cp = mvjc->b_rptr;
764             cp[0] = address;
765             cp[1] = control;
766             cp[2] = 0;
767             cp[3] = PPP_IP;
768             bcopy(iphdr, cp + PPP_HDRLEN, hlen);
769             mvjc->b_wptr = cp + PPP_HDRLEN + hlen;
770             mvjc->b_cont = mp;
771             mp->b_rptr += xlen;
772             m0 = mp = mvjc;
773             break;
774
775         case PPP_VJC_UNCOMP :
776             if ((p->pii_flags & PII_FLAGS_VJC_REJ)
777                 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
778                 DLOG("VJU rejected\n", 0);
779                 freemsg(mp);
780                 continue;
781             }
782
783             /*
784              * Make sure the IP header is in one message block.
785              */
786             xlen = MIN(len, MAX_IPHDR + PPP_HDRLEN);
787             if (mp->b_rptr + xlen > mp->b_wptr && !pullupmsg(mp, xlen)) {
788                 DLOG("pullupmsg vju %d failed\n", xlen);
789                 freemsg(mp);
790                 continue;
791             }
792
793             /*
794              * "Uncompress" it.  Basically this just copies information
795              * into p->pii_sc_comp and restores the protocol field of
796              * the IP header.
797              */
798             if (!vj_uncompress_uncomp(mp->b_rptr + PPP_HDRLEN,
799                                       &p->pii_sc_comp)) {
800                 DLOG("ppp: vj_uncompress failed on type Uncompresed\n", 0);
801                 freemsg(mp);
802                 continue;
803             }
804             mp->b_rptr[3] = PPP_IP;
805             break;
806         }
807 #endif
808
809         switch (PPP_PROTOCOL(mp->b_rptr)) {
810         default:
811             if (!canput(q->q_next)) {
812                 putbq(q, mp);
813                 return;
814             }
815             INCR(ppp_ipackets);
816             p->pii_ifnet.if_ipackets++;
817             putnext(q, mp);
818             continue;
819
820         case PPP_IP:
821             /*
822              * Don't let packets through until IPCP is up.
823              */
824             INCR(ppp_ipackets);
825             p->pii_ifnet.if_ipackets++;
826
827             if (!(p->pii_ifnet.if_flags & IFF_UP)
828                 || p->pii_npmode[NP_IP] != NPMODE_PASS) {
829                 DLOG("pkt ignored - IP down\n", 0);
830                 freemsg(mp);
831                 continue;
832             }
833
834             /*
835              * Get the first mbuf and put the struct ifnet * in.
836              */
837             MGETHDR(mb1, M_DONTWAIT, MT_DATA);
838             mb1->m_len = 0;
839             if (mb1 == NULL) {
840                 p->pii_ifnet.if_ierrors++;
841                 freemsg(m0);
842                 continue;
843             }
844             len = MHLEN;
845             mb1->m_pkthdr.rcvif = &(p->pii_ifnet);
846             mb1->m_pkthdr.len = dlen;
847             mbtail = mb2 = mb1;
848             mb1->m_len = 0;
849
850             rptr = mp->b_rptr + PPP_HDRLEN;
851             xlen = mp->b_wptr - rptr;
852             for(;;) {
853                 if (xlen == 0) {        /* move to the next mblk */
854                     mp = mp->b_cont;
855                     if (mp == NULL)
856                         break;
857                     xlen = mp->b_wptr - (rptr = mp->b_rptr);
858                     continue;
859                 }
860                 if (len == 0) {
861                     MGET(mb2, M_DONTWAIT, MT_DATA);
862                     if (!mb2) {
863                         /* if we couldn't get a buffer, drop the packet */
864                         p->pii_ifnet.if_ierrors++;
865                         m_freem(mb1);   /* discard what we've used already */
866                         mb1 = NULL;
867                         break;
868                     }
869                     len = MLEN;
870                     mb2->m_len = 0;
871                     mbtail->m_next = mb2;
872                     mbtail = mb2;
873                 }
874                 count = MIN(xlen, len);
875                 bcopy((char *) rptr, mtod(mb2, char *) + mb2->m_len, count);
876                 rptr += count;
877                 len -= count;
878                 xlen -= count;
879                 mb2->m_len += count;
880             }
881
882             freemsg(m0);
883             if (mb1 == NULL)
884                 continue;
885
886 #ifdef PPP_SNIT
887             if (p->pii_ifnet.if_flags & IFF_PROMISC) {
888                 struct mbuf *m = mb1;
889
890                 len = 0;
891                 do {
892                     len += m->m_len;
893                 } while (m = m->m_next);
894                 nif.nif_bodylen = len - sizeof(struct ifnet *);
895                 mb1->m_off += sizeof(struct ifnet *);
896                 snit_intr(&p->pii_ifnet, mb1, &nif);
897                 mb1->m_off -= sizeof(struct ifnet *);
898             }
899 #endif
900 /*
901             if (IF_QFULL(&ipintrq)) {
902                 IF_DROP(&ipintrq);
903                 p->pii_ifnet.if_ierrors++;
904                 m_freem(mb1);
905             }
906             else {
907 */
908             find_input_type(0x0800, mb1, ifp, 0);
909         }
910     }   /* end while */
911 }
912
913 /* ifp output procedure */
914 int
915 ppp_output(ifp, m0, dst)
916     struct ifnet *ifp;
917     struct mbuf *m0;
918     struct sockaddr *dst;
919 {
920     register PII *p = &pii[ifp->if_unit];
921     struct mbuf *m1;
922     int error, s, len;
923     u_short protocol;
924 #ifdef  VJC
925     int type;
926     u_char *vjhdr;
927 #endif
928     mblk_t *mp;
929     enum NPmode npmode;
930
931     error = 0;
932     if (!(ifp->if_flags & IFF_UP)) {
933         error = ENETDOWN;
934         goto getout;
935     }
936
937     switch (dst->sa_family) {
938 #ifdef  INET
939     case AF_INET:
940 #ifdef PPP_SNIT
941         if (ifp->if_flags & IFF_PROMISC) {
942             struct mbuf *m = m0;
943
944             len = 0;
945             do {
946                 len += m->m_len;
947             } while (m = m->m_next);
948             nif.nif_bodylen = len;
949             snit_intr(ifp, m0, &nif);
950         }
951 #endif
952         protocol = PPP_IP;
953         npmode = p->pii_npmode[NP_IP];
954         break;
955 #endif
956
957     default:
958         DLOG("ppp: af%d not supported\n", dst->sa_family);
959         error = EAFNOSUPPORT;
960         goto getout;
961     }
962
963     if (!p->pii_writeq) {
964         DLOG("ppp_if%d: no queue\n", p - pii);
965         error = EHOSTUNREACH;
966         goto getout;
967     }
968
969     switch (npmode) {
970     case NPMODE_DROP:
971         goto getout;
972     case NPMODE_ERROR:
973         error = ENETDOWN;
974         goto getout;
975     }
976
977 #ifdef  VJC
978     if ((protocol == PPP_IP) && (p->pii_flags & PII_FLAGS_VJC_ON)) {
979         register struct ip *ip;
980         ip = mtod(m0, struct ip *);
981         if (ip->ip_p == IPPROTO_TCP) {
982             type = vj_compress_tcp(ip, m0->m_len, &p->pii_sc_comp,
983                                    !(p->pii_flags & PII_FLAGS_VJC_NOCCID),
984                                    &vjhdr);
985             switch (type) {
986             case TYPE_UNCOMPRESSED_TCP :
987                 protocol = PPP_VJC_UNCOMP;
988                 break;
989             case TYPE_COMPRESSED_TCP :
990                 protocol = PPP_VJC_COMP;
991                 len = vjhdr - (u_char *) ip;
992                 m0->m_data += len;
993                 m0->m_len -= len;
994                 break;  
995             }
996         }
997     }
998 #endif
999
1000     len = PPP_HDRLEN;
1001     for (m1 = m0; m1; m1 = m1->m_next) 
1002         len += m1->m_len;
1003
1004     if (!(mp = allocb(len, BPRI_MED))) {
1005         DLOG("ppp_if%d: allocb failed\n", p - pii);
1006         error = ENOBUFS;
1007         goto getout;
1008     }
1009
1010 #ifdef  PPP_STATS
1011     p->pii_stats.ppp_obytes += len;
1012 #endif
1013
1014     *mp->b_wptr++ = PPP_ALLSTATIONS;
1015     *mp->b_wptr++ = PPP_UI;
1016     *mp->b_wptr++ = 0;
1017     *mp->b_wptr++ = protocol;
1018     for (m1 = m0; m1; m1 = m1->m_next) {        /* copy all data */
1019         bcopy(mtod(m1, char *), (char *) mp->b_wptr, m1->m_len);
1020         mp->b_wptr += m1->m_len;
1021     }
1022
1023     p->pii_ifnet.if_opackets++;
1024 DLOG("ppp_output npmode is %d\n",npmode);
1025     if (npmode == NPMODE_PASS) {
1026         putq(p->pii_writeq, mp);
1027     } else {
1028         mp->b_next = NULL;
1029         *p->pii_npq_tail = mp;
1030         p->pii_npq_tail = &mp;
1031     }
1032
1033  getout:
1034     m_freem(m0);
1035     if (error) {
1036         INCR(ppp_oerrors);
1037         p->pii_ifnet.if_oerrors++;
1038     }
1039     return (error);
1040 }
1041
1042 /*
1043  * if_ ioctl requests 
1044 */
1045 ppp_ioctl(ifp, cmd, data)
1046     register struct ifnet *ifp;
1047     unsigned int        cmd;
1048     caddr_t     data;
1049 {
1050     register struct ifaddr *ifa = (struct ifaddr *) data;
1051     register struct ifreq *ifr = (struct ifreq *) data;
1052     struct ppp_stats *psp;
1053     struct ppp_comp_stats *pcp;
1054     PII *p;
1055     queue_t *q;
1056     int error = 0;
1057
1058     switch (cmd) {
1059     case SIOCSIFFLAGS :
1060         /* This happens every time IFF_PROMISC has been changed. */
1061         if (!ifr)
1062             break;
1063         if (!suser()) {
1064             error = EPERM;
1065             break;
1066         }
1067
1068         /* clear the flags that can be cleared */
1069         ifp->if_flags &= (IFF_CANTCHANGE);      
1070         /* or in the flags that can be changed */
1071         ifp->if_flags |= (ifr->ifr_flags & ~IFF_CANTCHANGE);
1072         break;
1073
1074     case SIOCGIFFLAGS :
1075         ifr->ifr_flags = ifp->if_flags;
1076         break;
1077
1078     case SIOCSIFADDR :
1079         if( ifa->ifa_addr->sa_family != AF_INET) 
1080             error = EAFNOSUPPORT;
1081         break;
1082
1083     case SIOCSIFDSTADDR :
1084         if (ifa->ifa_addr->sa_family != AF_INET)
1085             error = EAFNOSUPPORT;
1086         break;
1087
1088     case SIOCSIFMTU :
1089         if (!suser()) {
1090             error = EPERM;
1091             break;
1092         }
1093         if (ifr->ifr_mtu > MAX_PKTSIZE - PPP_FRAMING) {
1094             error = EINVAL;
1095             break;
1096         }
1097         ifp->if_mtu = ifr->ifr_mtu;
1098         break;
1099
1100     case SIOCGIFMTU :
1101         ifr->ifr_mtu = ifp->if_mtu;
1102         break;
1103
1104     case SIOCGPPPSTATS:
1105         p = &pii[ifp->if_unit];
1106         psp = (struct ppp_stats *) &((struct ifpppstatsreq *)data)->stats;
1107         bzero(psp, sizeof(struct ppp_stats));
1108 #ifdef PPP_STATS
1109         psp->p = p->pii_stats;
1110 #endif
1111 #if defined(VJC) && !defined(VJ_NO_STATS)
1112         psp->vj = p->pii_sc_comp.stats;
1113 #endif
1114         break;
1115
1116     case SIOCGPPPCSTATS:
1117         p = &pii[ifp->if_unit];
1118         bzero(&p->pii_cstats, sizeof(struct ppp_comp_stats));
1119
1120         /* Make a message to send on the interface's write stream */
1121         q = p->pii_writeq;
1122         if (q != NULL) {
1123             putctl1(q, M_CTL, IF_GET_CSTATS);
1124             /*
1125              * We assume the message gets passed along immediately, so
1126              * by the time the putctl1 returns, the request has been
1127              * processed, the values returned and p->pii_cstats has
1128              * been updated.  If not, we just get zeroes.
1129              */
1130         }
1131         pcp = (struct ppp_comp_stats *)&((struct ifpppcstatsreq *)data)->stats;
1132         bcopy(&p->pii_cstats, pcp, sizeof(struct ppp_comp_stats));
1133         break;
1134
1135     default:
1136         error = EINVAL;
1137         break;
1138     }
1139
1140     return(error);
1141 }
1142
1143 #endif