]> git.ozlabs.org Git - ppp.git/blob - aix4/ppp_if.c
Minor fix to #if around alloca.h
[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         p->pii_writeq = NULL;
403         DLOG("ppp_if%d: closed\n", p - pii);
404     }
405     return(0);                  /* no work to be done */
406 }
407
408
409 static int
410 ppp_if_wput(q, mp)
411     queue_t  *q;
412     register mblk_t *mp;
413 {
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;
422
423     switch (mp->b_datap->db_type) {
424
425     case M_FLUSH:
426         if (*mp->b_rptr & FLUSHW)
427             flushq(q, FLUSHDATA);
428         putnext(q, mp);         /* send it along too */
429         break;
430
431     case M_DATA:
432         putq(q, mp);    /* queue it for my service routine */
433         break;
434
435     case M_IOCTL:
436         i = (struct iocblk *) mp->b_rptr;
437         p = (PII *) q->q_ptr;
438         switch ((unsigned int)i->ioc_cmd) {
439
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;
464             }
465 #endif
466             putnext(q, mp);
467             break;
468
469         case SIOCGETU:  /* get unit number */
470             /*
471              * Allocate a unit if we don't already have one.
472              */
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);
480             }
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;
492             }
493             qreply(q,mp);
494             break;
495
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);
514                     }
515                     mp->b_datap->db_type = M_IOCACK;
516                 }
517                 qreply(q, mp);
518                 break;
519             }
520             putnext(q, mp);
521             break;
522
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;
531             }
532             putnext(q, mp);
533             break;
534
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;
545                 }
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;
552                 }
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;
560                             }
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);
566                             }
567                         }
568                         p->pii_npq_tail = mqnext;
569                     }
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;
577             }
578             putnext(q, mp);
579             break;
580
581         default:                /* unknown IOCTL call */
582             putnext(q, mp);     /* pass it along */
583         }
584         break;
585
586     default:
587         putnext(q, mp); /* don't know what to do with this, so send it along*/
588     }
589 }
590
591 static int
592 ppp_if_wsrv(q)
593     queue_t     *q;
594 {
595     register mblk_t *mp;
596     register PII *p;
597
598     p = (PII *) q->q_ptr;
599
600     while ((mp = getq(q)) != NULL) {
601         /*
602          * we can only get M_DATA types into our Queue,
603          * due to our Put function
604          */
605         if (!canput(q->q_next)) {
606             putbq(q, mp);
607             return;
608         }
609
610         /* increment count of outgoing packets */
611         if (p != NULL)
612             INCR(ppp_opackets);
613
614         /* just pass it along, nothing to do in this direction */
615         putnext(q, mp);
616     }   /* end while */
617 }
618
619
620 static int
621 ppp_if_rput(q, mp)
622     queue_t *q;
623     register mblk_t *mp;
624 {
625     register PII        *p;
626
627     switch (mp->b_datap->db_type) {
628
629     case M_FLUSH:
630         if (*mp->b_rptr & FLUSHR)
631             flushq(q, FLUSHDATA);
632         putnext(q, mp);         /* send it along too */
633         break;
634
635     case M_DATA:
636         putq(q, mp);            /* queue it for my service routine */
637         break;
638
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;
663             }
664         }
665         break;
666
667     default:
668         putnext(q, mp);         /* send along other message types */
669     }
670 }
671
672 static int
673 ppp_if_rsrv(q)
674     queue_t     *q;
675 {
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;
689
690     p = (PII *) q->q_ptr;
691
692     while ((mp = getq(q)) != NULL) {
693         /*
694          * we can only get M_DATA types into our Queue,
695          * due to our Put function
696          */
697
698         if (p == NULL) {
699             if (!canput(q->q_next)) {
700                 putbq(q, mp);
701                 return;
702             }
703             putnext(q, mp);
704             continue;
705         }
706
707         len = msgdsize(mp);
708         dlen = len - PPP_HDRLEN;
709 #ifdef  PPP_STATS
710         p->pii_stats.ppp_ibytes += len;
711 #endif
712
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;
720         }
721         m0 = mp;        /* remember first message block */
722
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;                               
731             }
732             address = PPP_ADDRESS(mp->b_rptr);
733             control = PPP_CONTROL(mp->b_rptr);
734             mp->b_rptr += PPP_HDRLEN;
735             len -= PPP_HDRLEN;
736
737             /*
738              * Make sure the VJ header is in one message block.
739              */
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;
745             }
746
747             /*
748              * Decompress it, then get a buffer and put the
749              * decompressed header in it.
750              */
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;
757             }
758             if (!(mvjc = allocb(hlen + PPP_HDRLEN, BPRI_MED))) {
759                 DLOG("allocb mvjc failed (%d)\n", hlen + PPP_HDRLEN);
760                 freemsg(mp);
761                 continue;
762             }
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;
775
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;
782             }
783
784             /*
785              * Make sure the IP header is in one message block.
786              */
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;
792             }
793
794             /*
795              * "Uncompress" it.  Basically this just copies information
796              * into p->pii_sc_comp and restores the protocol field of
797              * the IP header.
798              */
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;
804             }
805             mp->b_rptr[3] = PPP_IP;
806             break;
807         }
808 #endif
809
810         switch (PPP_PROTOCOL(mp->b_rptr)) {
811         default:
812             if (!canput(q->q_next)) {
813                 putbq(q, mp);
814                 return;
815             }
816             INCR(ppp_ipackets);
817             p->pii_ifnet.if_ipackets++;
818             putnext(q, mp);
819             continue;
820
821         case PPP_IP:
822             /*
823              * Don't let packets through until IPCP is up.
824              */
825             INCR(ppp_ipackets);
826             p->pii_ifnet.if_ipackets++;
827
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;
833             }
834
835             /*
836              * Get the first mbuf and put the struct ifnet * in.
837              */
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;
844             }
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;
850
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;
860                 }
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;
869                     }
870                     len = MLEN;
871                     mb2->m_len = 0;
872                     mbtail->m_next = mb2;
873                     mbtail = mb2;
874                 }
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;
881             }
882
883             freemsg(m0);
884             if (mb1 == NULL)
885                 continue;
886
887 #ifdef PPP_SNIT
888             if (p->pii_ifnet.if_flags & IFF_PROMISC) {
889                 struct mbuf *m = mb1;
890
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 *);
899             }
900 #endif
901 /*
902             if (IF_QFULL(&ipintrq)) {
903                 IF_DROP(&ipintrq);
904                 p->pii_ifnet.if_ierrors++;
905                 m_freem(mb1);
906             }
907             else {
908 */
909             find_input_type(0x0800, mb1, ifp, 0);
910         }
911     }   /* end while */
912 }
913
914 /* ifp output procedure */
915 int
916 ppp_output(ifp, m0, dst)
917     struct ifnet *ifp;
918     struct mbuf *m0;
919     struct sockaddr *dst;
920 {
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;
931
932     error = 0;
933     if (!(ifp->if_flags & IFF_UP)) {
934         error = ENETDOWN;
935         goto getout;
936     }
937
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;
944
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);
951         }
952 #endif
953         protocol = PPP_IP;
954         npmode = p->pii_npmode[NP_IP];
955         break;
956 #endif
957
958     default:
959         DLOG("ppp: af%d not supported\n", dst->sa_family);
960         error = EAFNOSUPPORT;
961         goto getout;
962     }
963
964     if (!p->pii_writeq) {
965         DLOG("ppp_if%d: no queue\n", p - pii);
966         error = EHOSTUNREACH;
967         goto getout;
968     }
969
970     switch (npmode) {
971     case NPMODE_DROP:
972         goto getout;
973     case NPMODE_ERROR:
974         error = ENETDOWN;
975         goto getout;
976     }
977
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;  
996             }
997         }
998     }
999 #endif
1000
1001     len = PPP_HDRLEN;
1002     for (m1 = m0; m1; m1 = m1->m_next) 
1003         len += m1->m_len;
1004
1005     if (!(mp = allocb(len, BPRI_MED))) {
1006         DLOG("ppp_if%d: allocb failed\n", p - pii);
1007         error = ENOBUFS;
1008         goto getout;
1009     }
1010
1011 #ifdef  PPP_STATS
1012     p->pii_stats.ppp_obytes += len;
1013 #endif
1014
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;
1022     }
1023
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;
1032     }
1033
1034  getout:
1035     m_freem(m0);
1036     if (error) {
1037         INCR(ppp_oerrors);
1038         p->pii_ifnet.if_oerrors++;
1039     }
1040     return (error);
1041 }
1042
1043 /*
1044  * if_ ioctl requests 
1045 */
1046 ppp_ioctl(ifp, cmd, data)
1047     register struct ifnet *ifp;
1048     unsigned int        cmd;
1049     caddr_t     data;
1050 {
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;
1058
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;
1067         }
1068
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;
1074
1075     case SIOCGIFFLAGS :
1076         ifr->ifr_flags = ifp->if_flags;
1077         break;
1078
1079     case SIOCSIFADDR :
1080         if( ifa->ifa_addr->sa_family != AF_INET) 
1081             error = EAFNOSUPPORT;
1082         break;
1083
1084     case SIOCSIFDSTADDR :
1085         if (ifa->ifa_addr->sa_family != AF_INET)
1086             error = EAFNOSUPPORT;
1087         break;
1088
1089     case SIOCSIFMTU :
1090         if (!suser()) {
1091             error = EPERM;
1092             break;
1093         }
1094         if (ifr->ifr_mtu > MAX_PKTSIZE - PPP_FRAMING) {
1095             error = EINVAL;
1096             break;
1097         }
1098         ifp->if_mtu = ifr->ifr_mtu;
1099         break;
1100
1101     case SIOCGIFMTU :
1102         ifr->ifr_mtu = ifp->if_mtu;
1103         break;
1104
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;
1116
1117     case SIOCGPPPCSTATS:
1118         p = &pii[ifp->if_unit];
1119         bzero(&p->pii_cstats, sizeof(struct ppp_comp_stats));
1120
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);
1125             /*
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.
1130              */
1131         }
1132         pcp = (struct ppp_comp_stats *)&((struct ifpppcstatsreq *)data)->stats;
1133         bcopy(&p->pii_cstats, pcp, sizeof(struct ppp_comp_stats));
1134         break;
1135
1136     default:
1137         error = EINVAL;
1138         break;
1139     }
1140
1141     return(error);
1142 }
1143
1144 #endif