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