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