]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ppp/ip.c
Nuke csu_hdr from struct cspace. csu_hdr is not used anywhere in the
[FreeBSD/FreeBSD.git] / usr.sbin / ppp / ip.c
1 /*
2  *              PPP IP Protocol Interface
3  *
4  *          Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5  *
6  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the Internet Initiative Japan.  The name of the
14  * IIJ may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * $FreeBSD$
21  *
22  *      TODO:
23  *              o Return ICMP message for filterd packet
24  *                and optionaly record it into log.
25  */
26 #include <sys/param.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <netinet/in_systm.h>
30 #include <netinet/ip.h>
31 #include <netinet/ip_icmp.h>
32 #include <netinet/udp.h>
33 #include <netinet/tcp.h>
34 #include <arpa/inet.h>
35 #include <sys/un.h>
36
37 #include <errno.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <termios.h>
41 #include <unistd.h>
42
43 #include "layer.h"
44 #include "proto.h"
45 #include "mbuf.h"
46 #include "log.h"
47 #include "defs.h"
48 #include "timer.h"
49 #include "fsm.h"
50 #include "lqr.h"
51 #include "hdlc.h"
52 #include "throughput.h"
53 #include "iplist.h"
54 #include "slcompress.h"
55 #include "ipcp.h"
56 #include "filter.h"
57 #include "descriptor.h"
58 #include "lcp.h"
59 #include "ccp.h"
60 #include "link.h"
61 #include "mp.h"
62 #ifndef NORADIUS
63 #include "radius.h"
64 #endif
65 #include "bundle.h"
66 #include "tun.h"
67 #include "ip.h"
68
69
70 #define OPCODE_QUERY    0
71 #define OPCODE_IQUERY   1
72 #define OPCODE_STATUS   2
73
74 struct dns_header {
75   u_short id;
76   unsigned qr : 1;
77   unsigned opcode : 4;
78   unsigned aa : 1;
79   unsigned tc : 1;
80   unsigned rd : 1;
81   unsigned ra : 1;
82   unsigned z : 3;
83   unsigned rcode : 4;
84   u_short qdcount;
85   u_short ancount;
86   u_short nscount;
87   u_short arcount;
88 };
89
90 static const char *
91 dns_Qclass2Txt(u_short qclass)
92 {
93   static char failure[6];
94   struct {
95     u_short id;
96     const char *txt;
97   } qtxt[] = {
98     /* rfc1035 */
99     { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" }
100   };
101   int f;
102
103   for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
104     if (qtxt[f].id == qclass)
105       return qtxt[f].txt;
106
107   return HexStr(qclass, failure, sizeof failure);
108 }
109
110 static const char *
111 dns_Qtype2Txt(u_short qtype)
112 {
113   static char failure[6];
114   struct {
115     u_short id;
116     const char *txt;
117   } qtxt[] = {
118     /* rfc1035/rfc1700 */
119     { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
120     { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
121     { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
122     { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
123     { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
124     { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
125     { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
126     { 254, "MAILA" }, { 255, "*" }
127   };
128   int f;
129
130   for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
131     if (qtxt[f].id == qtype)
132       return qtxt[f].txt;
133
134   return HexStr(qtype, failure, sizeof failure);
135 }
136
137 static __inline int
138 PortMatch(int op, u_short pport, u_short rport)
139 {
140   switch (op) {
141   case OP_EQ:
142     return (pport == rport);
143   case OP_GT:
144     return (pport > rport);
145   case OP_LT:
146     return (pport < rport);
147   default:
148     return (0);
149   }
150 }
151
152 /*
153  *  Check a packet against a defined filter
154  *  Returns 0 to accept the packet, non-zero to drop the packet
155  *
156  *  If filtering is enabled, the initial fragment of a datagram must
157  *  contain the complete protocol header, and subsequent fragments
158  *  must not attempt to over-write it.
159  */
160 static int
161 FilterCheck(const struct ip *pip, const struct filter *filter)
162 {
163   int gotinfo;                  /* true if IP payload decoded */
164   int cproto;                   /* P_* protocol type if (gotinfo) */
165   int estab, syn, finrst;       /* TCP state flags if (gotinfo) */
166   u_short sport, dport;         /* src, dest port from packet if (gotinfo) */
167   int n;                        /* filter rule to process */
168   int len;                      /* bytes used in dbuff */
169   int didname;                  /* true if filter header printed */
170   int match;                    /* true if condition matched */
171   const struct filterent *fp = filter->rule;
172   char dbuff[100];
173
174   if (fp->f_action == A_NONE)
175     return (0);         /* No rule is given. Permit this packet */
176
177   /* Deny any packet fragment that tries to over-write the header.
178    * Since we no longer have the real header available, punt on the
179    * largest normal header - 20 bytes for TCP without options, rounded
180    * up to the next possible fragment boundary.  Since the smallest
181    * `legal' MTU is 576, and the smallest recommended MTU is 296, any
182    * fragmentation within this range is dubious at best */
183   len = ntohs(pip->ip_off) & IP_OFFMASK;        /* fragment offset */ 
184   if (len > 0) {                /* Not first fragment within datagram */
185     if (len < (24 >> 3))        /* don't allow fragment to over-write header */
186       return (1);
187     /* permit fragments on in and out filter */
188     return (!filter->fragok);
189   }
190   
191   cproto = gotinfo = estab = syn = finrst = didname = 0;
192   sport = dport = 0;
193   for (n = 0; n < MAXFILTERS; ) {
194     if (fp->f_action == A_NONE) {
195       n++;
196       fp++;
197       continue;
198     }
199
200     if (!didname) {
201       log_Printf(LogDEBUG, "%s filter:\n", filter->name);
202       didname = 1;
203     }
204
205     match = 0;
206     if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
207           fp->f_src.mask.s_addr) &&
208         !((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
209           fp->f_dst.mask.s_addr)) {
210       if (fp->f_proto != P_NONE) {
211         if (!gotinfo) {
212           const char *ptop = (const char *) pip + (pip->ip_hl << 2);
213           const struct tcphdr *th;
214           const struct udphdr *uh;
215           const struct icmp *ih;
216           int datalen;  /* IP datagram length */
217
218           datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
219           switch (pip->ip_p) {
220           case IPPROTO_ICMP:
221             cproto = P_ICMP;
222             if (datalen < 8)    /* ICMP must be at least 8 octets */
223               return (1);
224             ih = (const struct icmp *) ptop;
225             sport = ih->icmp_type;
226             estab = syn = finrst = -1;
227             if (log_IsKept(LogDEBUG))
228               snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
229             break;
230           case IPPROTO_IGMP:
231             cproto = P_IGMP;
232             if (datalen < 8)    /* IGMP uses 8-octet messages */
233               return (1);
234             estab = syn = finrst = -1;
235             sport = ntohs(0);
236             break;
237 #ifdef IPPROTO_GRE
238           case IPPROTO_GRE:
239             cproto = P_GRE;
240             if (datalen < 2)    /* GRE uses 2-octet+ messages */
241               return (1);
242             estab = syn = finrst = -1;
243             sport = ntohs(0);
244             break;
245 #endif
246 #ifdef IPPROTO_OSPFIGP
247           case IPPROTO_OSPFIGP:
248             cproto = P_OSPF;
249             if (datalen < 8)    /* IGMP uses 8-octet messages */
250               return (1);
251             estab = syn = finrst = -1;
252             sport = ntohs(0);
253             break;
254 #endif
255           case IPPROTO_UDP:
256           case IPPROTO_IPIP:
257             cproto = P_UDP;
258             if (datalen < 8)    /* UDP header is 8 octets */
259               return (1);
260             uh = (const struct udphdr *) ptop;
261             sport = ntohs(uh->uh_sport);
262             dport = ntohs(uh->uh_dport);
263             estab = syn = finrst = -1;
264             if (log_IsKept(LogDEBUG))
265               snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
266                        sport, dport);
267             break;
268           case IPPROTO_TCP:
269             cproto = P_TCP;
270             th = (const struct tcphdr *) ptop;
271             /* TCP headers are variable length.  The following code
272              * ensures that the TCP header length isn't de-referenced if
273              * the datagram is too short
274              */
275             if (datalen < 20 || datalen < (th->th_off << 2))
276               return (1);
277             sport = ntohs(th->th_sport);
278             dport = ntohs(th->th_dport);
279             estab = (th->th_flags & TH_ACK);
280             syn = (th->th_flags & TH_SYN);
281             finrst = (th->th_flags & (TH_FIN|TH_RST));
282             if (log_IsKept(LogDEBUG)) {
283               if (!estab)
284                 snprintf(dbuff, sizeof dbuff,
285                          "flags = %02x, sport = %d, dport = %d",
286                          th->th_flags, sport, dport);
287               else
288                 *dbuff = '\0';
289             }
290             break;
291           default:
292             return (1); /* We'll block unknown type of packet */
293           }
294
295           if (log_IsKept(LogDEBUG)) {
296             if (estab != -1) {
297               len = strlen(dbuff);
298               snprintf(dbuff + len, sizeof dbuff - len,
299                        ", estab = %d, syn = %d, finrst = %d",
300                        estab, syn, finrst);
301             }
302             log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
303                        filter_Proto2Nam(cproto), dbuff);
304           }
305           gotinfo = 1;
306         }
307         if (log_IsKept(LogDEBUG)) {
308           if (fp->f_srcop != OP_NONE) {
309             snprintf(dbuff, sizeof dbuff, ", src %s %d",
310                      filter_Op2Nam(fp->f_srcop), fp->f_srcport);
311             len = strlen(dbuff);
312           } else
313             len = 0;
314           if (fp->f_dstop != OP_NONE) {
315             snprintf(dbuff + len, sizeof dbuff - len,
316                      ", dst %s %d", filter_Op2Nam(fp->f_dstop),
317                      fp->f_dstport);
318           } else if (!len)
319             *dbuff = '\0';
320
321           log_Printf(LogDEBUG, "  rule = %d: Address match, "
322                      "check against proto %s%s, action = %s\n",
323                      n, filter_Proto2Nam(fp->f_proto),
324                      dbuff, filter_Action2Nam(fp->f_action));
325         }
326
327         if (cproto == fp->f_proto) {
328           if ((fp->f_srcop == OP_NONE ||
329                PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
330               (fp->f_dstop == OP_NONE ||
331                PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
332               (fp->f_estab == 0 || estab) &&
333               (fp->f_syn == 0 || syn) &&
334               (fp->f_finrst == 0 || finrst)) {
335             match = 1;
336           }
337         }
338       } else {
339         /* Address is matched and no protocol specified. Make a decision. */
340         log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
341                    filter_Action2Nam(fp->f_action));
342         match = 1;
343       }
344     } else
345       log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
346
347     if (match != fp->f_invert) {
348       /* Take specified action */
349       if (fp->f_action < A_NONE)
350         fp = &filter->rule[n = fp->f_action];
351       else
352         return (fp->f_action != A_PERMIT);
353     } else {
354       n++;
355       fp++;
356     }
357   }
358   return (1);           /* No rule is mached. Deny this packet */
359 }
360
361 #ifdef notdef
362 static void
363 IcmpError(struct ip *pip, int code)
364 {
365   struct mbuf *bp;
366
367   if (pip->ip_p != IPPROTO_ICMP) {
368     bp = m_get(m_len, MB_IPIN);
369     memcpy(MBUF_CTOP(bp), ptr, m_len);
370     vj_SendFrame(bp);
371     ipcp_AddOutOctets(m_len);
372   }
373 }
374 #endif
375
376 static void
377 ip_LogDNS(const struct udphdr *uh, const char *direction)
378 {
379   struct dns_header header;
380   const u_short *pktptr;
381   const u_char *ptr;
382   u_short *hptr;
383   int len;
384
385   ptr = (const char *)uh + sizeof *uh;
386   len = ntohs(uh->uh_ulen) - sizeof *uh;
387   if (len < sizeof header + 5)          /* rfc1024 */
388     return;
389
390   pktptr = (const u_short *)ptr;
391   hptr = (u_short *)&header;
392   ptr += sizeof header;
393   len -= sizeof header;
394
395   while (pktptr < (const u_short *)ptr) {
396     *hptr++ = ntohs(*pktptr);   /* Careful of macro side-effects ! */
397     pktptr++;
398   }
399
400   if (header.opcode == OPCODE_QUERY && header.qr == 0) {
401     /* rfc1035 */
402     char name[MAXHOSTNAMELEN + 1], *n;
403     const char *qtype, *qclass;
404     const u_char *end;
405
406     n = name;
407     end = ptr + len - 4;
408     if (end - ptr > MAXHOSTNAMELEN)
409       end = ptr + MAXHOSTNAMELEN;
410     while (ptr < end) {
411       len = *ptr++;
412       if (len > end - ptr)
413         len = end - ptr;
414       if (n != name)
415         *n++ = '.';
416       memcpy(n, ptr, len);
417       ptr += len;
418       n += len;
419     }
420     *n = '\0';
421     qtype = dns_Qtype2Txt(ntohs(*(const u_short *)end));
422     qclass = dns_Qclass2Txt(ntohs(*(const u_short *)(end + 2)));
423
424     log_Printf(LogDNS, "%sbound query %s %s %s\n",
425                direction, qclass, qtype, name);
426   }
427 }
428
429 /*
430  *  For debugging aid.
431  */
432 int
433 PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
434 {
435   static const char *const TcpFlags[] = {
436     "FIN", "SYN", "RST", "PSH", "ACK", "URG"
437   };
438   struct ip *pip;
439   struct tcphdr *th;
440   struct udphdr *uh;
441   struct icmp *icmph;
442   char *ptop;
443   int mask, len, n, pri, logit, loglen, result;
444   char logbuf[200];
445
446   logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
447           (!filter || filter->logok);
448   loglen = 0;
449   pri = 0;
450
451   pip = (struct ip *)cp;
452   uh = NULL;
453
454   if (logit && loglen < sizeof logbuf) {
455     if (filter)
456       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
457     else
458       snprintf(logbuf + loglen, sizeof logbuf - loglen, "  ");
459     loglen += strlen(logbuf + loglen);
460   }
461   ptop = (cp + (pip->ip_hl << 2));
462
463   switch (pip->ip_p) {
464   case IPPROTO_ICMP:
465     if (logit && loglen < sizeof logbuf) {
466       icmph = (struct icmp *) ptop;
467       snprintf(logbuf + loglen, sizeof logbuf - loglen,
468              "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
469       loglen += strlen(logbuf + loglen);
470       snprintf(logbuf + loglen, sizeof logbuf - loglen,
471                "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
472       loglen += strlen(logbuf + loglen);
473     }
474     break;
475
476   case IPPROTO_UDP:
477     uh = (struct udphdr *) ptop;
478     if (pip->ip_tos == IPTOS_LOWDELAY)
479       pri++;
480
481     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
482         ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
483                           ntohs(uh->uh_dport)))
484       pri++;
485
486     if (logit && loglen < sizeof logbuf) {
487       snprintf(logbuf + loglen, sizeof logbuf - loglen,
488            "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
489       loglen += strlen(logbuf + loglen);
490       snprintf(logbuf + loglen, sizeof logbuf - loglen,
491                "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
492       loglen += strlen(logbuf + loglen);
493     }
494     break;
495
496 #ifdef IPPROTO_GRE
497   case IPPROTO_GRE:
498     if (logit && loglen < sizeof logbuf) {
499       snprintf(logbuf + loglen, sizeof logbuf - loglen,
500           "GRE: %s ---> ", inet_ntoa(pip->ip_src));
501       loglen += strlen(logbuf + loglen);
502       snprintf(logbuf + loglen, sizeof logbuf - loglen,
503               "%s", inet_ntoa(pip->ip_dst));
504       loglen += strlen(logbuf + loglen);
505     }
506     break;
507 #endif
508
509 #ifdef IPPROTO_OSPFIGP
510   case IPPROTO_OSPFIGP:
511     if (logit && loglen < sizeof logbuf) {
512       snprintf(logbuf + loglen, sizeof logbuf - loglen,
513            "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
514       loglen += strlen(logbuf + loglen);
515       snprintf(logbuf + loglen, sizeof logbuf - loglen,
516                "%s", inet_ntoa(pip->ip_dst));
517       loglen += strlen(logbuf + loglen);
518     }
519     break;
520 #endif
521
522   case IPPROTO_IPIP:
523     if (logit && loglen < sizeof logbuf) {
524       uh = (struct udphdr *) ptop;
525       snprintf(logbuf + loglen, sizeof logbuf - loglen,
526            "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
527       loglen += strlen(logbuf + loglen);
528       snprintf(logbuf + loglen, sizeof logbuf - loglen,
529                "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
530       loglen += strlen(logbuf + loglen);
531     }
532     break;
533
534   case IPPROTO_IGMP:
535     if (logit && loglen < sizeof logbuf) {
536       uh = (struct udphdr *) ptop;
537       snprintf(logbuf + loglen, sizeof logbuf - loglen,
538            "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
539       loglen += strlen(logbuf + loglen);
540       snprintf(logbuf + loglen, sizeof logbuf - loglen,
541                "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
542       loglen += strlen(logbuf + loglen);
543     }
544     break;
545
546   case IPPROTO_TCP:
547     th = (struct tcphdr *) ptop;
548     if (pip->ip_tos == IPTOS_LOWDELAY)
549       pri++;
550
551     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
552         ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
553                           ntohs(th->th_dport)))
554       pri++;
555
556     if (logit && loglen < sizeof logbuf) {
557       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
558       snprintf(logbuf + loglen, sizeof logbuf - loglen,
559            "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
560       loglen += strlen(logbuf + loglen);
561       snprintf(logbuf + loglen, sizeof logbuf - loglen,
562                "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
563       loglen += strlen(logbuf + loglen);
564       n = 0;
565       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
566         if (th->th_flags & mask) {
567           snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
568           loglen += strlen(logbuf + loglen);
569         }
570         n++;
571       }
572       snprintf(logbuf + loglen, sizeof logbuf - loglen,
573                "  seq:%lx  ack:%lx (%d/%d)",
574                (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
575       loglen += strlen(logbuf + loglen);
576       if ((th->th_flags & TH_SYN) && nb > 40) {
577         u_short *sp;
578
579         ptop += 20;
580         sp = (u_short *) ptop;
581         if (ntohs(sp[0]) == 0x0204) {
582           snprintf(logbuf + loglen, sizeof logbuf - loglen,
583                    " MSS = %d", ntohs(sp[1]));
584           loglen += strlen(logbuf + loglen);
585         }
586       }
587     }
588     break;
589   }
590
591   if (filter && FilterCheck(pip, filter)) {
592     if (logit)
593       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
594 #ifdef notdef
595     if (direction == 0)
596       IcmpError(pip, pri);
597 #endif
598     result = -1;
599   } else {
600     /* Check Keep Alive filter */
601     if (logit && log_IsKept(LogTCPIP)) {
602       if (filter && FilterCheck(pip, &bundle->filter.alive))
603         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
604       else
605         log_Printf(LogTCPIP, "%s\n", logbuf);
606     }
607     result = pri;
608   }
609
610   if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
611     ip_LogDNS(uh, filter->name);
612
613   return result;
614 }
615
616 struct mbuf *
617 ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
618 {
619   int nb, nw;
620   struct tun_data tun;
621   struct ip *pip;
622   char *data;
623
624   if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
625     log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
626     m_freem(bp);
627     return NULL;
628   }
629
630   m_settype(bp, MB_IPIN);
631   nb = m_length(bp);
632   if (nb > sizeof tun.data) {
633     log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
634                l->name, nb, (int)(sizeof tun.data));
635     m_freem(bp);
636     return NULL;
637   }
638   mbuf_Read(bp, tun.data, nb);
639
640   if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
641     return NULL;
642
643   pip = (struct ip *)tun.data;
644   if (!FilterCheck(pip, &bundle->filter.alive))
645     bundle_StartIdleTimer(bundle);
646
647   ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
648
649   if (bundle->dev.header) {
650     tun.family = htonl(AF_INET);
651     nb += sizeof tun - sizeof tun.data;
652     data = (char *)&tun;
653   } else
654     data = tun.data;
655
656   nw = write(bundle->dev.fd, data, nb);
657   if (nw != nb) {
658     if (nw == -1)
659       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
660                  l->name, nb, strerror(errno));
661     else
662       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
663   }
664
665   return NULL;
666 }
667
668 void
669 ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
670 {
671   struct mbuf *bp;
672
673   if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
674     log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
675   else {
676     /*
677      * We allocate an extra 6 bytes, four at the front and two at the end.
678      * This is an optimisation so that we need to do less work in
679      * m_prepend() in acf_LayerPush() and proto_LayerPush() and
680      * appending in hdlc_LayerPush().
681      */
682     bp = m_get(count + 6, MB_IPOUT);
683     bp->m_offset += 4;
684     bp->m_len -= 6;
685     memcpy(MBUF_CTOP(bp), ptr, count);
686     m_enqueue(ipcp->Queue + pri, bp);
687   }
688 }
689
690 void
691 ip_DeleteQueue(struct ipcp *ipcp)
692 {
693   struct mqueue *queue;
694
695   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
696     while (queue->top)
697       m_freem(m_dequeue(queue));
698 }
699
700 size_t
701 ip_QueueLen(struct ipcp *ipcp)
702 {
703   struct mqueue *queue;
704   size_t result;
705
706   result = 0;
707   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
708     result += queue->len;
709
710   return result;
711 }
712
713 int
714 ip_PushPacket(struct link *l, struct bundle *bundle)
715 {
716   struct ipcp *ipcp = &bundle->ncp.ipcp;
717   struct mqueue *queue;
718   struct mbuf *bp;
719   struct ip *pip;
720   int m_len;
721
722   if (ipcp->fsm.state != ST_OPENED)
723     return 0;
724
725   queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
726   do {
727     if (queue->top) {
728       bp = m_pullup(m_dequeue(queue));
729       m_len = m_length(bp);
730       pip = (struct ip *)MBUF_CTOP(bp);
731       if (!FilterCheck(pip, &bundle->filter.alive))
732         bundle_StartIdleTimer(bundle);
733       link_PushPacket(l, bp, bundle, 0, PROTO_IP);
734       ipcp_AddOutOctets(ipcp, m_len);
735       return 1;
736     }
737   } while (queue-- != ipcp->Queue);
738
739   return 0;
740 }