remove IOR kludge; added get idle time ioctl
[ppp.git] / ultrix / if_ppp.c
1 /*
2  * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
3  *
4  * Copyright (c) 1989 Carnegie Mellon University.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms are permitted
8  * provided that the above copyright notice and this paragraph are
9  * duplicated in all such forms and that any documentation,
10  * advertising materials, and other materials related to such
11  * distribution and use acknowledge that the software was developed
12  * by Carnegie Mellon University.  The name of the
13  * University may not be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  *
19  * Drew D. Perkins
20  * Carnegie Mellon University
21  * 4910 Forbes Ave.
22  * Pittsburgh, PA 15213
23  * (412) 268-8576
24  * ddp@andrew.cmu.edu
25  *
26  * Based on:
27  *      @(#)if_sl.c     7.6.1.2 (Berkeley) 2/15/89
28  *
29  * Copyright (c) 1987 Regents of the University of California.
30  * All rights reserved.
31  *
32  * Redistribution and use in source and binary forms are permitted
33  * provided that the above copyright notice and this paragraph are
34  * duplicated in all such forms and that any documentation,
35  * advertising materials, and other materials related to such
36  * distribution and use acknowledge that the software was developed
37  * by the University of California, Berkeley.  The name of the
38  * University may not be used to endorse or promote products derived
39  * from this software without specific prior written permission.
40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
41  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
42  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
43  *
44  * Serial Line interface
45  *
46  * Rick Adams
47  * Center for Seismic Studies
48  * 1300 N 17th Street, Suite 1450
49  * Arlington, Virginia 22209
50  * (703)276-7900
51  * rick@seismo.ARPA
52  * seismo!rick
53  *
54  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
55  * Converted to 4.3BSD Beta by Chris Torek.
56  * Other changes made at Berkeley, based in part on code by Kirk Smith.
57  *
58  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
59  * Added VJ tcp header compression; more unified ioctls
60  *
61  * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
62  * Cleaned up a lot of the mbuf-related code to fix bugs that
63  * caused system crashes and packet corruption.  Changed pppstart
64  * so that it doesn't just give up with a collision if the whole
65  * packet doesn't fit in the output ring buffer.
66  *
67  * Added priority queueing for interactive IP packets, following
68  * the model of if_sl.c, plus hooks for bpf.
69  * Paul Mackerras (paulus@cs.anu.edu.au).
70  *
71  * Ultrix port by Per Sundstrom <sundstrom@stkhlm.enet.dec.com>,
72  * Robert Olsson <robert@robur.slu.se> and Paul Mackerras.
73  */
74
75 /* $Id: if_ppp.c,v 1.3 1994/11/28 01:38:25 paulus Exp $ */
76 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
77
78 #include "ppp.h"
79 #if NPPP > 0
80
81 #define VJC
82 #define PPP_COMPRESS
83
84 #include "../h/param.h"
85 #include "../h/user.h"
86 #include "../h/proc.h"
87 #include "../h/mbuf.h"
88 #include "../h/buf.h"
89 #include "../h/socket.h"
90 #include "../h/ioctl.h"
91 #include "../h/systm.h"
92
93 #include "../net/net/if.h"
94 #include "../net/net/netisr.h"
95 #include "../net/net/route.h"
96
97 #if INET
98 #include "../net/netinet/in.h"
99 #include "../net/netinet/in_systm.h"
100 #include "../net/netinet/in_var.h"
101 #include "../net/netinet/ip.h"
102 #endif
103
104 #ifdef vax
105 #include "../machine/mtpr.h"
106 #endif
107
108 #include "ppp_defs.h"
109 #include "if_ppp.h"
110
111 #ifdef VJC
112 #include "slcompress.h"
113 #endif
114
115 #include "if_pppvar.h"
116
117 #ifdef PPP_COMPRESS
118 #define PACKETPTR       struct mbuf *
119 #include "ppp-comp.h"
120 #endif
121
122 void    pppattach __P((void));
123 int     pppioctl __P((struct ppp_softc *sc, int cmd, caddr_t data, int flag,
124                       struct proc *));
125 int     pppoutput __P((struct ifnet *ifp, struct mbuf *m0,
126                        struct sockaddr *dst));
127 int     pppsioctl __P((struct ifnet *ifp, int cmd, caddr_t data));
128 void    pppintr __P((void));
129
130 static void     ppp_outpkt __P((struct ppp_softc *));
131 static int      ppp_ccp __P((struct ppp_softc *, struct mbuf *m, int rcvd));
132 static void     ppp_ccp_closed __P((struct ppp_softc *));
133 static void     ppp_inproc __P((struct ppp_softc *, struct mbuf *));
134 static void     pppdumpm __P((struct mbuf *m0));
135
136 /*
137  * Some useful mbuf macros not in mbuf.h.
138  */
139 #define M_IS_CLUSTER(m) ((m)->m_off > MMAXOFF)
140
141 #define M_TRAILINGSPACE(m) \
142         ((M_IS_CLUSTER(m) ? (u_int)(m)->m_clptr + M_CLUSTERSZ : MSIZE) \
143          - ((m)->m_off + (m)->m_len))
144
145 #define M_OFFSTART(m)   \
146         (M_IS_CLUSTER(m) ? (u_int)(m)->m_clptr : MMINOFF)
147
148 #define M_DATASIZE(m)   \
149         (M_IS_CLUSTER(m) ? M_CLUSTERSZ : MLEN)
150
151 /*
152  * The following disgusting hack gets around the problem that IP TOS
153  * can't be set yet.  We want to put "interactive" traffic on a high
154  * priority queue.  To decide if traffic is interactive, we check that
155  * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
156  */
157 static u_short interactive_ports[8] = {
158         0,      513,    0,      0,
159         0,      21,     0,      23,
160 };
161 #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
162
163 #ifdef PPP_COMPRESS
164 /*
165  * List of compressors we know about.
166  */
167
168 extern struct compressor ppp_bsd_compress;
169
170 struct compressor *ppp_compressors[] = {
171     &ppp_bsd_compress,
172     NULL
173 };
174 #endif /* PPP_COMPRESS */
175
176 /*
177  * Called from boot code to establish ppp interfaces.
178  */
179 void
180 pppattach()
181 {
182     register struct ppp_softc *sc;
183     register int i = 0;
184
185     for (sc = ppp_softc; i < NPPP; sc++) {
186         sc->sc_if.if_name = "ppp";
187         sc->sc_if.if_unit = i++;
188         sc->sc_if.if_mtu = PPP_MTU;
189         sc->sc_if.if_flags = IFF_POINTOPOINT;
190         sc->sc_if.if_type = IFT_PPP;
191         sc->sc_if.if_ioctl = pppsioctl;
192         sc->sc_if.if_output = pppoutput;
193         sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
194         sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
195         sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
196         sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN;
197         if_attach(&sc->sc_if);
198 #if NBPFILTER > 0
199         bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN);
200 #endif
201     }
202 }
203
204 /*
205  * Allocate a ppp interface unit and initialize it.
206  */
207 struct ppp_softc *
208 pppalloc(pid)
209     pid_t pid;
210 {
211     int nppp, i;
212     struct ppp_softc *sc;
213
214     for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
215         if (sc->sc_xfer == pid) {
216             sc->sc_xfer = 0;
217             break;
218         }
219     if (nppp >= NPPP)
220         for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
221             if (sc->sc_devp == NULL)
222                 break;
223     if (nppp >= NPPP)
224         return NULL;
225
226     sc->sc_flags = 0;
227     sc->sc_mru = PPP_MRU;
228 #ifdef VJC
229     sl_compress_init(&sc->sc_comp);
230 #endif
231 #ifdef PPP_COMPRESS
232     sc->sc_xc_state = NULL;
233     sc->sc_rc_state = NULL;
234 #endif /* PPP_COMPRESS */
235     for (i = 0; i < NUM_NP; ++i)
236         sc->sc_npmode[i] = NPMODE_ERROR;
237     sc->sc_if.if_flags |= IFF_RUNNING;
238
239     return sc;
240 }
241
242 /*
243  * Deallocate a ppp unit.
244  */
245 void
246 pppdealloc(sc)
247     struct ppp_softc *sc;
248 {
249     struct mbuf *m;
250
251     if_down(&sc->sc_if);
252     sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
253     sc->sc_devp = NULL;
254     sc->sc_xfer = 0;
255     for (;;) {
256         IF_DEQUEUE(&sc->sc_rawq, m);
257         if (m == NULL)
258             break;
259         m_freem(m);
260     }
261     for (;;) {
262         IF_DEQUEUE(&sc->sc_inq, m);
263         if (m == NULL)
264             break;
265         m_freem(m);
266     }
267     for (;;) {
268         IF_DEQUEUE(&sc->sc_fastq, m);
269         if (m == NULL)
270             break;
271         m_freem(m);
272     }
273     if (sc->sc_togo != NULL) {
274         m_freem(sc->sc_togo);
275         sc->sc_togo = NULL;
276     }
277 #ifdef PPP_COMPRESS
278     ppp_ccp_closed(sc);
279     sc->sc_xc_state = NULL;
280     sc->sc_rc_state = NULL;
281 #endif /* PPP_COMPRESS */
282 }
283
284 /*
285  * Ioctl routine for generic ppp devices.
286  */
287 int
288 pppioctl(sc, cmd, data, flag)
289     struct ppp_softc *sc;
290     caddr_t data;
291     int cmd, flag;
292 {
293     struct proc *p = u.u_procp;
294     int s, error, flags, mru, nb, npx;
295     struct ppp_option_data *odp;
296     struct compressor **cp;
297     struct npioctl *npi;
298     u_char ccp_option[CCP_MAX_OPTION_LENGTH];
299
300     switch (cmd) {
301     case FIONREAD:
302         *(int *)data = sc->sc_inq.ifq_len;
303         break;
304
305     case PPPIOCGUNIT:
306         *(int *)data = sc->sc_if.if_unit;
307         break;
308
309     case PPPIOCGFLAGS:
310         *(u_int *)data = sc->sc_flags;
311         break;
312
313     case PPPIOCSFLAGS:
314         if (!suser())
315             return EPERM;
316         flags = *(int *)data & SC_MASK;
317         s = splnet();
318         if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN))
319             ppp_ccp_closed(sc);
320         splimp();
321         sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
322         splx(s);
323         break;
324
325     case PPPIOCSMRU:
326         if (!suser())
327             return EPERM;
328         mru = *(int *)data;
329         if (mru >= PPP_MRU && mru <= PPP_MAXMRU)
330             sc->sc_mru = mru;
331         break;
332
333     case PPPIOCGMRU:
334         *(int *)data = sc->sc_mru;
335         break;
336
337 #ifdef VJC
338     case PPPIOCSMAXCID:
339         if (!suser())
340             return EPERM;
341         s = splnet();
342         sl_compress_setup(&sc->sc_comp, *(int *)data);
343         splx(s);
344         break;
345 #endif
346
347     case PPPIOCXFERUNIT:
348         if (!suser())
349             return EPERM;
350         sc->sc_xfer = p->p_pid;
351         break;
352
353 #ifdef PPP_COMPRESS
354     case PPPIOCSCOMPRESS:
355         if (!suser())
356             return EPERM;
357         odp = (struct ppp_option_data *) data;
358         nb = odp->length;
359         if (nb > sizeof(ccp_option))
360             nb = sizeof(ccp_option);
361         if (error = copyin(odp->ptr, ccp_option, nb))
362             return (error);
363         if (ccp_option[1] < 2)  /* preliminary check on the length byte */
364             return (EINVAL);
365         for (cp = ppp_compressors; *cp != NULL; ++cp)
366             if ((*cp)->compress_proto == ccp_option[0]) {
367                 /*
368                  * Found a handler for the protocol - try to allocate
369                  * a compressor or decompressor.
370                  */
371                 error = 0;
372                 s = splnet();
373                 if (odp->transmit) {
374                     if (sc->sc_xc_state != NULL)
375                         (*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
376                     sc->sc_xcomp = *cp;
377                     sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb);
378                     if (sc->sc_xc_state == NULL) {
379                         if (sc->sc_flags & SC_DEBUG)
380                             printf("ppp%d: comp_alloc failed\n",
381                                sc->sc_if.if_unit);
382                         error = ENOBUFS;
383                     }
384                     splimp();
385                     sc->sc_flags &= ~SC_COMP_RUN;
386                 } else {
387                     if (sc->sc_rc_state != NULL)
388                         (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
389                     sc->sc_rcomp = *cp;
390                     sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb);
391                     if (sc->sc_rc_state == NULL) {
392                         if (sc->sc_flags & SC_DEBUG)
393                             printf("ppp%d: decomp_alloc failed\n",
394                                sc->sc_if.if_unit);
395                         error = ENOBUFS;
396                     }
397                     splimp();
398                     sc->sc_flags &= ~SC_DECOMP_RUN;
399                 }
400                 splx(s);
401                 return (error);
402             }
403         if (sc->sc_flags & SC_DEBUG)
404             printf("ppp%d: no compressor for [%x %x %x], %x\n",
405                    sc->sc_if.if_unit, ccp_option[0], ccp_option[1],
406                    ccp_option[2], nb);
407         return (EINVAL);        /* no handler found */
408 #endif /* PPP_COMPRESS */
409
410     case PPPIOCGNPMODE:
411     case PPPIOCSNPMODE:
412         npi = (struct npioctl *) data;
413         switch (npi->protocol) {
414         case PPP_IP:
415             npx = NP_IP;
416             break;
417         default:
418             return EINVAL;
419         }
420         if (cmd == PPPIOCGNPMODE) {
421             npi->mode = sc->sc_npmode[npx];
422         } else {
423             if (!suser())
424                 return EPERM;
425             if (npi->mode != sc->sc_npmode[npx]) {
426                 s = splimp();
427                 sc->sc_npmode[npx] = npi->mode;
428                 if (npi->mode != NPMODE_QUEUE)
429                     (*sc->sc_start)(sc);
430                 splx(s);
431             }
432         }
433         break;
434
435     default:
436         return (-1);
437     }
438     return (0);
439 }
440
441 /*
442  * Process an ioctl request to the ppp network interface.
443  */
444 int
445 pppsioctl(ifp, cmd, data)
446     register struct ifnet *ifp;
447     int cmd;
448     caddr_t data;
449 {
450     struct proc *p = u.u_procp;
451     register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
452     register struct ifaddr *ifa = (struct ifaddr *)data;
453     register struct ifreq *ifr = (struct ifreq *)data;
454     struct ppp_stats *psp;
455     struct ppp_comp_stats *pcp;
456     int s = splimp(), error = 0;
457
458     switch (cmd) {
459     case SIOCSIFFLAGS:
460         if ((ifp->if_flags & IFF_RUNNING) == 0)
461             ifp->if_flags &= ~IFF_UP;
462         break;
463
464     case SIOCSIFADDR:
465         if (ifa->ifa_addr.sa_family != AF_INET)
466             error = EAFNOSUPPORT;
467         break;
468
469     case SIOCSIFDSTADDR:
470         if (ifa->ifa_addr.sa_family != AF_INET)
471             error = EAFNOSUPPORT;
472         break;
473
474     case SIOCSIFMTU:
475         if (!suser())
476             return EPERM;
477         sc->sc_if.if_mtu = ifr->ifr_mtu;
478         break;
479
480     case SIOCGIFMTU:
481         ifr->ifr_mtu = sc->sc_if.if_mtu;
482         break;
483
484     case SIOCGPPPSTATS:
485         psp = &((struct ifpppstatsreq *) data)->stats;
486         bzero(psp, sizeof(*psp));
487         psp->p.ppp_ibytes = sc->sc_bytesrcvd;
488         psp->p.ppp_ipackets = ifp->if_ipackets;
489         psp->p.ppp_ierrors = ifp->if_ierrors;
490         psp->p.ppp_obytes = sc->sc_bytessent;
491         psp->p.ppp_opackets = ifp->if_opackets;
492         psp->p.ppp_oerrors = ifp->if_oerrors;
493 #ifdef VJC
494         psp->vj.vjs_packets = sc->sc_comp.sls_packets;
495         psp->vj.vjs_compressed = sc->sc_comp.sls_compressed;
496         psp->vj.vjs_searches = sc->sc_comp.sls_searches;
497         psp->vj.vjs_misses = sc->sc_comp.sls_misses;
498         psp->vj.vjs_uncompressedin = sc->sc_comp.sls_uncompressedin;
499         psp->vj.vjs_compressedin = sc->sc_comp.sls_compressedin;
500         psp->vj.vjs_errorin = sc->sc_comp.sls_errorin;
501         psp->vj.vjs_tossed = sc->sc_comp.sls_tossed;
502 #endif /* VJC */
503         break;
504
505 #ifdef PPP_COMPRESS
506     case SIOCGPPPCSTATS:
507         pcp = &((struct ifpppcstatsreq *) data)->stats;
508         bzero(pcp, sizeof(*pcp));
509         if (sc->sc_xc_state != NULL)
510             (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c);
511         if (sc->sc_rc_state != NULL)
512             (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d);
513         break;
514 #endif /* PPP_COMPRESS */
515
516     default:
517         error = EINVAL;
518     }
519     splx(s);
520     return (error);
521 }
522
523 /*
524  * Queue a packet.  Start transmission if not active.
525  * Packet is placed in Information field of PPP frame.
526  */
527 int
528 pppoutput(ifp, m0, dst)
529     struct ifnet *ifp;
530     struct mbuf *m0;
531     struct sockaddr *dst;
532 {
533     register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
534     struct ppp_header *ph;
535     int protocol, address, control;
536     u_char *cp;
537     int s, error;
538     struct ip *ip;
539     struct ifqueue *ifq;
540     enum NPmode mode;
541
542     if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
543         || (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) {
544         error = ENETDOWN;       /* sort of */
545         goto bad;
546     }
547
548     /*
549      * Compute PPP header.
550      */
551     ifq = &ifp->if_snd;
552     switch (dst->sa_family) {
553 #ifdef INET
554     case AF_INET:
555         address = PPP_ALLSTATIONS;
556         control = PPP_UI;
557         protocol = PPP_IP;
558         mode = sc->sc_npmode[NP_IP];
559         
560         /*
561          * If this is a TCP packet to or from an "interactive" port,
562          * put the packet on the fastq instead.
563          */
564         if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) {
565             register int p = ntohl(((int *)ip)[ip->ip_hl]);
566             if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16))
567                 ifq = &sc->sc_fastq;
568         }
569         break;
570 #endif
571     case AF_UNSPEC:
572         address = PPP_ADDRESS(dst->sa_data);
573         control = PPP_CONTROL(dst->sa_data);
574         protocol = PPP_PROTOCOL(dst->sa_data);
575         mode = NPMODE_PASS;
576         break;
577     default:
578         printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
579         error = EAFNOSUPPORT;
580         goto bad;
581     }
582
583     /*
584      * Drop this packet, or return an error, if necessary.
585      */
586     if (mode == NPMODE_ERROR) {
587         error = ENETDOWN;
588         goto bad;
589     }
590     if (mode == NPMODE_DROP) {
591         error = 0;
592         goto bad;
593     }
594
595     /*
596      * Add PPP header.  If no space in first mbuf, allocate another.
597      */
598     if (M_IS_CLUSTER(m0) || m0->m_off < MMINOFF + PPP_HDRLEN) {
599         struct mbuf *m;
600
601         MGET(m, M_DONTWAIT, MT_DATA);
602         if (m == NULL) {
603             m_freem(m0);
604             return (ENOBUFS);
605         }
606         m->m_len = 0;
607         m->m_next = m0;
608         m0 = m;
609     } else
610         m0->m_off -= PPP_HDRLEN;
611
612     cp = mtod(m0, u_char *);
613     *cp++ = address;
614     *cp++ = control;
615     *cp++ = protocol >> 8;
616     *cp++ = protocol & 0xff;
617     m0->m_len += PPP_HDRLEN;
618
619     if (sc->sc_flags & SC_LOG_OUTPKT) {
620         printf("ppp%d output: ", ifp->if_unit);
621         pppdumpm(m0);
622     }
623
624 #if NBPFILTER > 0
625     /*
626      * See if bpf wants to look at the packet.
627      */
628     if (sc->sc_bpf)
629         bpf_mtap(sc->sc_bpf, m0);
630 #endif
631
632     /*
633      * Put the packet on the appropriate queue.
634      */
635     s = splimp();               /* splnet should be OK now */
636     if (IF_QFULL(ifq)) {
637         IF_DROP(ifq);
638         splx(s);
639         sc->sc_if.if_oerrors++;
640         error = ENOBUFS;
641         goto bad;
642     }
643     IF_ENQUEUE(ifq, m0);
644
645     /*
646      * Tell the device to send it out.
647      */
648     if (mode == NPMODE_PASS)
649         (*sc->sc_start)(sc);
650
651     splx(s);
652     return (0);
653
654 bad:
655     m_freem(m0);
656     return (error);
657 }
658
659 /*
660  * Get a packet to send.  This procedure is intended to be called
661  * at spltty()/splimp(), so it takes little time.  If there isn't
662  * a packet waiting to go out, it schedules a software interrupt
663  * to prepare a new packet; the device start routine gets called
664  * again when a packet is ready.
665  */
666 struct mbuf *
667 ppp_dequeue(sc)
668     struct ppp_softc *sc;
669 {
670     struct mbuf *m;
671
672     m = sc->sc_togo;
673     if (m) {
674         /*
675          * Had a packet waiting - send it.
676          */
677         sc->sc_togo = NULL;
678         sc->sc_flags |= SC_TBUSY;
679         return m;
680     }
681     /*
682      * Remember we wanted a packet and schedule a software interrupt.
683      */
684     sc->sc_flags &= ~SC_TBUSY;
685     schednetisr(NETISR_PPP);
686     return NULL;
687 }
688
689 /*
690  * Software interrupt routine, called at splnet().
691  */
692 void
693 pppintr()
694 {
695     struct ppp_softc *sc;
696     int i, s;
697     struct mbuf *m;
698
699     sc = ppp_softc;
700     for (i = 0; i < NPPP; ++i, ++sc) {
701         if (!(sc->sc_flags & SC_TBUSY) && sc->sc_togo == NULL
702             && (sc->sc_if.if_snd.ifq_head || sc->sc_fastq.ifq_head))
703             ppp_outpkt(sc);
704         for (;;) {
705             IF_DEQUEUE(&sc->sc_rawq, m);
706             if (m == NULL)
707                 break;
708             ppp_inproc(sc, m);
709         }
710     }
711 }
712
713 /*
714  * Grab another packet off a queue and apply VJ compression,
715  * packet compression, address/control and/or protocol compression
716  * if enabled.  Should be called at splnet.
717  */
718 static void
719 ppp_outpkt(sc)
720     struct ppp_softc *sc;
721 {
722     int s;
723     struct mbuf *m, *mp, **mpp;
724     u_char *cp;
725     int address, control, protocol;
726     struct ifqueue *ifq;
727     enum NPmode mode;
728
729     /*
730      * Scan through the send queues looking for a packet
731      * which can be sent: first the fast queue, then the normal queue.
732      */
733     ifq = &sc->sc_fastq;
734     for (;;) {
735         mpp = &ifq->ifq_head;
736         mp = NULL;
737         while ((m = *mpp) != NULL) {
738             switch (PPP_PROTOCOL(mtod(m, u_char *))) {
739             case PPP_IP:
740                 mode = sc->sc_npmode[NP_IP];
741                 break;
742             default:
743                 mode = NPMODE_PASS;
744             }
745             if (mode == NPMODE_PASS)
746                 break;
747             switch (mode) {
748             case NPMODE_DROP:
749             case NPMODE_ERROR:
750                 *mpp = m->m_act;
751                 --ifq->ifq_len;
752                 m_freem(m);
753                 break;
754             case NPMODE_QUEUE:
755                 mpp = &m->m_act;
756                 mp = m;
757                 break;
758             }
759         }
760         if (m != NULL)
761             break;
762
763         if (ifq == &sc->sc_if.if_snd)
764             break;
765         /* Finished the fast queue; do the normal queue. */
766         ifq = &sc->sc_if.if_snd;
767     }
768
769     if (m == NULL)
770         return;
771
772     if ((*mpp = m->m_act) == NULL)
773         ifq->ifq_tail = mp;
774     m->m_act = NULL;
775     --ifq->ifq_len;
776
777     /*
778      * Extract the ppp header of the new packet.
779      * The ppp header will be in one mbuf.
780      */
781     cp = mtod(m, u_char *);
782     address = PPP_ADDRESS(cp);
783     control = PPP_CONTROL(cp);
784     protocol = PPP_PROTOCOL(cp);
785
786     switch (protocol) {
787 #ifdef VJC
788     case PPP_IP:
789         /*
790          * If the packet is a TCP/IP packet, see if we can compress it.
791          */
792         if (sc->sc_flags & SC_COMP_TCP) {
793             struct ip *ip;
794             int type;
795
796             mp = m;
797             ip = (struct ip *) (cp + PPP_HDRLEN);
798             if (mp->m_len <= PPP_HDRLEN) {
799                 mp = mp->m_next;
800                 if (mp == NULL)
801                     break;
802                 ip = mtod(mp, struct ip *);
803             }
804             /* this code assumes the IP/TCP header is in one non-shared mbuf */
805             if (ip->ip_p == IPPROTO_TCP) {
806                 type = sl_compress_tcp(mp, ip, &sc->sc_comp,
807                                        !(sc->sc_flags & SC_NO_TCP_CCID));
808                 switch (type) {
809                 case TYPE_UNCOMPRESSED_TCP:
810                     protocol = PPP_VJC_UNCOMP;
811                     break;
812                 case TYPE_COMPRESSED_TCP:
813                     protocol = PPP_VJC_COMP;
814                     cp = mtod(m, u_char *);
815                     cp[0] = address;    /* header has moved */
816                     cp[1] = control;
817                     cp[2] = 0;
818                     break;
819                 }
820                 cp[3] = protocol;       /* update protocol in PPP header */
821             }
822         }
823         break;
824 #endif  /* VJC */
825
826 #ifdef PPP_COMPRESS
827     case PPP_CCP:
828         ppp_ccp(sc, m, 0);
829         break;
830 #endif  /* PPP_COMPRESS */
831     }
832
833 #ifdef PPP_COMPRESS
834     if (protocol != PPP_LCP && protocol != PPP_CCP
835         && sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) {
836         struct mbuf *mcomp;
837         int slen, clen;
838
839         slen = 0;
840         for (mp = m; mp != NULL; mp = mp->m_next)
841             slen += mp->m_len;
842         clen = (*sc->sc_xcomp->compress)
843             (sc->sc_xc_state, &mcomp, m, slen,
844              (sc->sc_flags & SC_CCP_UP? sc->sc_if.if_mtu: 0));
845         if (mcomp != NULL) {
846             m_freem(m);
847             m = mcomp;
848             cp = mtod(m, u_char *);
849             protocol = cp[3];
850         }
851     }
852 #endif  /* PPP_COMPRESS */
853
854     /*
855      * Compress the address/control and protocol, if possible.
856      */
857     if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
858         control == PPP_UI && protocol != PPP_ALLSTATIONS &&
859         protocol != PPP_LCP) {
860         /* can compress address/control */
861         m->m_off += 2;
862         m->m_len -= 2;
863     }
864     if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
865         /* can compress protocol */
866         if (mtod(m, u_char *) == cp) {
867             cp[2] = cp[1];      /* move address/control up */
868             cp[1] = cp[0];
869         }
870         ++m->m_off;
871         --m->m_len;
872     }
873
874     s = splimp();
875     sc->sc_togo = m;
876     (*sc->sc_start)(sc);
877     splx(s);
878 }
879
880 #ifdef PPP_COMPRESS
881 /*
882  * Handle a CCP packet.  `rcvd' is 1 if the packet was received,
883  * 0 if it is about to be transmitted.
884  */
885 static int
886 ppp_ccp(sc, m, rcvd)
887     struct ppp_softc *sc;
888     struct mbuf *m;
889     int rcvd;
890 {
891     u_char *dp, *ep;
892     struct mbuf *mp;
893     int slen, s;
894     struct bsd_db *db;
895
896     /*
897      * Get a pointer to the data after the PPP header.
898      */
899     if (m->m_len <= PPP_HDRLEN) {
900         mp = m->m_next;
901         if (mp == NULL)
902             return;
903         dp = (mp != NULL)? mtod(mp, u_char *): NULL;
904     } else {
905         mp = m;
906         dp = mtod(mp, u_char *) + PPP_HDRLEN;
907     }
908
909     ep = mtod(mp, u_char *) + mp->m_len;
910     if (dp + CCP_HDRLEN > ep)
911         return;
912     slen = CCP_LENGTH(dp);
913     if (dp + slen > ep) {
914         if (sc->sc_flags & SC_DEBUG)
915             printf("if_ppp/ccp: not enough data in mbuf (%x+%x > %x+%x)\n",
916                    dp, slen, mtod(mp, u_char *), mp->m_len);
917         return;
918     }
919
920     switch (CCP_CODE(dp)) {
921     case CCP_CONFREQ:
922     case CCP_TERMREQ:
923     case CCP_TERMACK:
924         /* CCP must be going down - disable compression */
925         if (sc->sc_flags & SC_CCP_UP) {
926             s = splimp();
927             sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
928             splx(s);
929         }
930         break;
931
932     case CCP_CONFACK:
933         if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP)
934             && slen >= CCP_HDRLEN + CCP_OPT_MINLEN
935             && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) {
936             if (!rcvd) {
937                 /* we're agreeing to send compressed packets. */
938                 if (sc->sc_xc_state != NULL
939                     && (*sc->sc_xcomp->comp_init)
940                         (sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
941                          sc->sc_if.if_unit, sc->sc_flags & SC_DEBUG)) {
942                     s = splimp();
943                     sc->sc_flags |= SC_COMP_RUN;
944                     splx(s);
945                 }
946             } else {
947                 /* peer is agreeing to send compressed packets. */
948                 if (sc->sc_rc_state != NULL
949                     && (*sc->sc_rcomp->decomp_init)
950                         (sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
951                          sc->sc_if.if_unit, sc->sc_mru,
952                          sc->sc_flags & SC_DEBUG)) {
953                     s = splimp();
954                     sc->sc_flags |= SC_DECOMP_RUN;
955                     sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
956                     splx(s);
957                 }
958             }
959         }
960         break;
961
962     case CCP_RESETACK:
963         if (sc->sc_flags & SC_CCP_UP) {
964             if (!rcvd) {
965                 if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN))
966                     (*sc->sc_xcomp->comp_reset)(sc->sc_xc_state);
967             } else {
968                 if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
969                     (*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state);
970                     s = splimp();
971                     sc->sc_flags &= ~SC_DC_ERROR;
972                     splx(s);
973                 }
974             }
975         }
976         break;
977     }
978 }
979
980 /*
981  * CCP is down; free (de)compressor state if necessary.
982  */
983 static void
984 ppp_ccp_closed(sc)
985     struct ppp_softc *sc;
986 {
987     if (sc->sc_xc_state) {
988         (*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
989         sc->sc_xc_state = NULL;
990     }
991     if (sc->sc_rc_state) {
992         (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
993         sc->sc_rc_state = NULL;
994     }
995 }
996 #endif /* PPP_COMPRESS */
997
998 /*
999  * PPP packet input routine.
1000  * The caller has checked and removed the FCS and has inserted
1001  * the address/control bytes and the protocol high byte if they
1002  * were omitted.  Should be called at splimp/spltty.
1003  */
1004 void
1005 ppppktin(sc, m, lost)
1006     struct ppp_softc *sc;
1007     struct mbuf *m;
1008     int lost;
1009 {
1010     m->m_context = lost;
1011     IF_ENQUEUE(&sc->sc_rawq, m);
1012     schednetisr(NETISR_PPP);
1013 }
1014
1015 /*
1016  * Process a received PPP packet, doing decompression as necessary.
1017  */
1018 #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
1019                          TYPE_UNCOMPRESSED_TCP)
1020
1021 static void
1022 ppp_inproc(sc, m)
1023     struct ppp_softc *sc;
1024     struct mbuf *m;
1025 {
1026     struct ifqueue *inq, *lock;
1027     int s, ilen, xlen, proto, rv;
1028     u_char *cp, adrs, ctrl;
1029     struct mbuf *mp, *dmp, *pc;
1030     u_char *iphdr;
1031     u_int hlen;
1032
1033     sc->sc_if.if_ipackets++;
1034
1035     if (sc->sc_flags & SC_LOG_INPKT) {
1036         printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen);
1037         pppdumpm(m);
1038     }
1039
1040     cp = mtod(m, u_char *);
1041     adrs = PPP_ADDRESS(cp);
1042     ctrl = PPP_CONTROL(cp);
1043     proto = PPP_PROTOCOL(cp);
1044
1045     if (m->m_context) {
1046         s = splimp();
1047         sc->sc_flags |= SC_VJ_RESET;
1048         splx(s);
1049     }
1050
1051 #ifdef PPP_COMPRESS
1052     /*
1053      * Decompress this packet if necessary, update the receiver's
1054      * dictionary, or take appropriate action on a CCP packet.
1055      */
1056     if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)
1057         && !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) {
1058         /* decompress this packet */
1059         rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp);
1060         if (dmp != NULL) {
1061             m_freem(m);
1062             m = dmp;
1063             cp = mtod(m, u_char *);
1064             proto = PPP_PROTOCOL(cp);
1065
1066         } else {
1067             /* pass the compressed packet up to pppd, which may take
1068                CCP down or issue a Reset-Req. */
1069             if (sc->sc_flags & SC_DEBUG)
1070                 printf("ppp%d: decompress failed %d\n", sc->sc_if.if_unit, rv);
1071             s = splimp();
1072             sc->sc_flags |= SC_VJ_RESET;
1073             switch (rv) {
1074             case DECOMP_OK:
1075                 /* no error, but no decompressed packet produced */
1076                 splx(s);
1077                 m_freem(m);
1078                 return;
1079             case DECOMP_ERROR:
1080                 sc->sc_flags |= SC_DC_ERROR;
1081                 break;
1082             case DECOMP_FATALERROR:
1083                 sc->sc_flags |= SC_DC_FERROR;
1084                 break;
1085             }
1086             splx(s);
1087         }
1088
1089     } else {
1090         if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
1091             (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m);
1092         }
1093         if (proto == PPP_CCP) {
1094             ppp_ccp(sc, m, 1);
1095         }
1096     }
1097 #endif
1098
1099     ilen = 0;
1100     for (mp = m; mp != NULL; mp = mp->m_next)
1101         ilen += mp->m_len;
1102
1103 #ifdef VJC
1104     if (sc->sc_flags & SC_VJ_RESET) {
1105         /*
1106          * If we've missed a packet, we must toss subsequent compressed
1107          * packets which don't have an explicit connection ID.
1108          */
1109         sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp);
1110         s = splimp();
1111         sc->sc_flags &= ~SC_VJ_RESET;
1112         splx(s);
1113     }
1114
1115     /*
1116      * See if we have a VJ-compressed packet to uncompress.
1117      */
1118     if (proto == PPP_VJC_COMP) {
1119         if (sc->sc_flags & SC_REJ_COMP_TCP)
1120             goto bad;
1121
1122         xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
1123                                       ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP,
1124                                       &sc->sc_comp, &iphdr, &hlen);
1125
1126         if (xlen <= 0) {
1127             if (sc->sc_flags & SC_DEBUG)
1128                 printf("ppp%d: VJ uncompress failed on type comp\n",
1129                         sc->sc_if.if_unit);
1130             goto bad;
1131         }
1132
1133         /* Copy the PPP and IP headers into a new mbuf. */
1134         MGET(mp, M_DONTWAIT, MT_DATA);
1135         if (mp == NULL)
1136             goto bad;
1137         mp->m_len = 0;
1138         mp->m_next = NULL;
1139         if (hlen + PPP_HDRLEN > MLEN) {
1140             MCLGET(mp, pc);
1141             if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) {
1142                 m_freem(mp);
1143                 goto bad;       /* lose if big headers and no clusters */
1144             }
1145         }
1146         cp = mtod(mp, u_char *);
1147         cp[0] = adrs;
1148         cp[1] = ctrl;
1149         cp[2] = 0;
1150         cp[3] = PPP_IP;
1151         proto = PPP_IP;
1152         bcopy(iphdr, cp + PPP_HDRLEN, hlen);
1153         mp->m_len = hlen + PPP_HDRLEN;
1154
1155         /*
1156          * Trim the PPP and VJ headers off the old mbuf
1157          * and stick the new and old mbufs together.
1158          */
1159         m->m_off += PPP_HDRLEN + xlen;
1160         m->m_len -= PPP_HDRLEN + xlen;
1161         if (m->m_len <= M_TRAILINGSPACE(mp)) {
1162             bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len);
1163             mp->m_len += m->m_len;
1164             MFREE(m, mp->m_next);
1165         } else
1166             mp->m_next = m;
1167         m = mp;
1168         ilen += hlen - xlen;
1169
1170     } else if (proto == PPP_VJC_UNCOMP) {
1171         if (sc->sc_flags & SC_REJ_COMP_TCP)
1172             goto bad;
1173
1174         xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
1175                                       ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP,
1176                                       &sc->sc_comp, &iphdr, &hlen);
1177
1178         if (xlen < 0) {
1179             if (sc->sc_flags & SC_DEBUG)
1180                 printf("ppp%d: VJ uncompress failed on type uncomp\n",
1181                         sc->sc_if.if_unit);
1182             goto bad;
1183         }
1184
1185         proto = PPP_IP;
1186         cp[3] = PPP_IP;
1187     }
1188 #endif /* VJC */
1189
1190     /*
1191      * If the packet will fit in an ordinary mbuf, don't waste a
1192      * whole cluster on it.
1193      */
1194     if (ilen <= MLEN && M_IS_CLUSTER(m)) {
1195         MGET(mp, M_DONTWAIT, MT_DATA);
1196         if (mp != NULL) {
1197             m_copydata(m, mtod(mp, caddr_t), ilen);
1198             m_freem(m);
1199             m = mp;
1200             m->m_len = ilen;
1201         }
1202     }
1203
1204 #if NBPFILTER > 0
1205     /* See if bpf wants to look at the packet. */
1206     if (sc->sc_bpf)
1207         bpf_mtap(sc->sc_bpf, m);
1208 #endif
1209
1210     switch (proto) {
1211 #ifdef INET
1212     case PPP_IP:
1213         /*
1214          * IP packet - take off the ppp header and pass it up to IP.
1215          */
1216         if ((sc->sc_if.if_flags & IFF_UP) == 0
1217             || sc->sc_npmode[NP_IP] != NPMODE_PASS) {
1218             /* interface is down - drop the packet. */
1219             m_freem(m);
1220             return;
1221         }
1222         m->m_off += PPP_HDRLEN;
1223         m->m_len -= PPP_HDRLEN;
1224         schednetisr(NETISR_IP);
1225         inq = &ipintrq;
1226         break;
1227 #endif
1228
1229     default:
1230         /*
1231          * Some other protocol - place on input queue for read().
1232          */
1233         inq = &sc->sc_inq;
1234         rv = 1;
1235         break;
1236     }
1237
1238     /*
1239      * Put the packet on the appropriate input queue.
1240      */
1241     s = splimp();
1242     lock = inq;
1243     smp_lock(&lock->lk_ifqueue, LK_RETRY);
1244     if (IF_QFULL(inq)) {
1245         IF_DROP(inq);
1246         /* XXX should we unlock here? */
1247         splx(s);
1248         if (sc->sc_flags & SC_DEBUG)
1249             printf("ppp%d: input queue full\n", sc->sc_if.if_unit);
1250         goto bad;
1251     }
1252     IF_ENQUEUEIF(inq, m, &sc->sc_if);
1253     smp_unlock(&lock->lk_ifqueue);
1254     splx(s);
1255
1256     if (rv)
1257         (*sc->sc_ctlp)(sc);
1258
1259     return;
1260
1261  bad:
1262     m_freem(m);
1263     sc->sc_if.if_ierrors++;
1264 }
1265
1266 #define MAX_DUMP_BYTES  128
1267
1268 static void
1269 pppdumpm(m0)
1270     struct mbuf *m0;
1271 {
1272     char buf[3*MAX_DUMP_BYTES+4];
1273     char *bp = buf;
1274     struct mbuf *m;
1275     static char digits[] = "0123456789abcdef";
1276
1277     for (m = m0; m; m = m->m_next) {
1278         int l = m->m_len;
1279         u_char *rptr = mtod(m, u_char *);
1280
1281         while (l--) {
1282             if (bp > buf + sizeof(buf) - 4)
1283                 goto done;
1284             *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
1285             *bp++ = digits[*rptr++ & 0xf];
1286         }
1287
1288         if (m->m_next) {
1289             if (bp > buf + sizeof(buf) - 3)
1290                 goto done;
1291             *bp++ = '|';
1292         } else
1293             *bp++ = ' ';
1294     }
1295 done:
1296     if (m)
1297         *bp++ = '>';
1298     *bp = 0;
1299     printf("%s\n", buf);
1300 }
1301
1302 #endif  /* NPPP > 0 */