xref: /freebsd/usr.sbin/ppp/ip.c (revision b565321aa194f3671d8a3d0cc9bf7d9715a6c8c0)
1af57ed9fSAtsushi Murai /*
2af57ed9fSAtsushi Murai  *		PPP IP Protocol Interface
3af57ed9fSAtsushi Murai  *
4af57ed9fSAtsushi Murai  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5af57ed9fSAtsushi Murai  *
6af57ed9fSAtsushi Murai  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7af57ed9fSAtsushi Murai  *
8af57ed9fSAtsushi Murai  * Redistribution and use in source and binary forms are permitted
9af57ed9fSAtsushi Murai  * provided that the above copyright notice and this paragraph are
10af57ed9fSAtsushi Murai  * duplicated in all such forms and that any documentation,
11af57ed9fSAtsushi Murai  * advertising materials, and other materials related to such
12af57ed9fSAtsushi Murai  * distribution and use acknowledge that the software was developed
13af57ed9fSAtsushi Murai  * by the Internet Initiative Japan.  The name of the
14af57ed9fSAtsushi Murai  * IIJ may not be used to endorse or promote products derived
15af57ed9fSAtsushi Murai  * from this software without specific prior written permission.
16af57ed9fSAtsushi Murai  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17af57ed9fSAtsushi Murai  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18af57ed9fSAtsushi Murai  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19af57ed9fSAtsushi Murai  *
2097d92980SPeter Wemm  * $FreeBSD$
21af57ed9fSAtsushi Murai  *
22af57ed9fSAtsushi Murai  *	TODO:
23af57ed9fSAtsushi Murai  *		o Return ICMP message for filterd packet
24af57ed9fSAtsushi Murai  *		  and optionaly record it into log.
25af57ed9fSAtsushi Murai  */
26972a1bcfSBrian Somers #include <sys/param.h>
276a6b4bbbSBrian Somers #include <sys/socket.h>
2875240ed1SBrian Somers #include <netinet/in.h>
29af57ed9fSAtsushi Murai #include <netinet/in_systm.h>
30af57ed9fSAtsushi Murai #include <netinet/ip.h>
31af57ed9fSAtsushi Murai #include <netinet/ip_icmp.h>
32af57ed9fSAtsushi Murai #include <netinet/udp.h>
33af57ed9fSAtsushi Murai #include <netinet/tcp.h>
34ed6a16c1SPoul-Henning Kamp #include <arpa/inet.h>
351fa665f5SBrian Somers #include <sys/un.h>
3675240ed1SBrian Somers 
3757fd05c4SBrian Somers #include <errno.h>
3875240ed1SBrian Somers #include <stdio.h>
3975240ed1SBrian Somers #include <string.h>
405d9e6103SBrian Somers #include <termios.h>
4175240ed1SBrian Somers #include <unistd.h>
4275240ed1SBrian Somers 
435d9e6103SBrian Somers #include "layer.h"
445d9e6103SBrian Somers #include "proto.h"
45927145beSBrian Somers #include "mbuf.h"
46927145beSBrian Somers #include "log.h"
4775240ed1SBrian Somers #include "defs.h"
4875240ed1SBrian Somers #include "timer.h"
4975240ed1SBrian Somers #include "fsm.h"
50879ed6faSBrian Somers #include "lqr.h"
5175240ed1SBrian Somers #include "hdlc.h"
525828db6dSBrian Somers #include "throughput.h"
535828db6dSBrian Somers #include "iplist.h"
54eaa4df37SBrian Somers #include "slcompress.h"
5575240ed1SBrian Somers #include "ipcp.h"
561ae349f5Scvs2svn #include "filter.h"
572f786681SBrian Somers #include "descriptor.h"
5875240ed1SBrian Somers #include "lcp.h"
593b0f8d2eSBrian Somers #include "ccp.h"
603b0f8d2eSBrian Somers #include "link.h"
613b0f8d2eSBrian Somers #include "mp.h"
62972a1bcfSBrian Somers #ifndef NORADIUS
63972a1bcfSBrian Somers #include "radius.h"
64972a1bcfSBrian Somers #endif
657a6f8720SBrian Somers #include "bundle.h"
666a6b4bbbSBrian Somers #include "tun.h"
6775240ed1SBrian Somers #include "ip.h"
68af57ed9fSAtsushi Murai 
6952c9ca19SBrian Somers 
7052c9ca19SBrian Somers #define OPCODE_QUERY	0
7152c9ca19SBrian Somers #define OPCODE_IQUERY	1
7252c9ca19SBrian Somers #define OPCODE_STATUS	2
7352c9ca19SBrian Somers 
7452c9ca19SBrian Somers struct dns_header {
7552c9ca19SBrian Somers   u_short id;
7652c9ca19SBrian Somers   unsigned qr : 1;
7752c9ca19SBrian Somers   unsigned opcode : 4;
7852c9ca19SBrian Somers   unsigned aa : 1;
7952c9ca19SBrian Somers   unsigned tc : 1;
8052c9ca19SBrian Somers   unsigned rd : 1;
8152c9ca19SBrian Somers   unsigned ra : 1;
8252c9ca19SBrian Somers   unsigned z : 3;
8352c9ca19SBrian Somers   unsigned rcode : 4;
8452c9ca19SBrian Somers   u_short qdcount;
8552c9ca19SBrian Somers   u_short ancount;
8652c9ca19SBrian Somers   u_short nscount;
8752c9ca19SBrian Somers   u_short arcount;
88182c898aSBrian Somers };
89af57ed9fSAtsushi Murai 
9052c9ca19SBrian Somers static const char *
9152c9ca19SBrian Somers dns_Qclass2Txt(u_short qclass)
9252c9ca19SBrian Somers {
9352c9ca19SBrian Somers   static char failure[6];
9452c9ca19SBrian Somers   struct {
9552c9ca19SBrian Somers     u_short id;
9652c9ca19SBrian Somers     const char *txt;
9752c9ca19SBrian Somers   } qtxt[] = {
9852c9ca19SBrian Somers     /* rfc1035 */
9952c9ca19SBrian Somers     { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" }
10052c9ca19SBrian Somers   };
10152c9ca19SBrian Somers   int f;
10252c9ca19SBrian Somers 
10352c9ca19SBrian Somers   for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
10452c9ca19SBrian Somers     if (qtxt[f].id == qclass)
10552c9ca19SBrian Somers       return qtxt[f].txt;
10652c9ca19SBrian Somers 
107d6d3eeabSBrian Somers   return HexStr(qclass, failure, sizeof failure);
10852c9ca19SBrian Somers }
10952c9ca19SBrian Somers 
11052c9ca19SBrian Somers static const char *
11152c9ca19SBrian Somers dns_Qtype2Txt(u_short qtype)
11252c9ca19SBrian Somers {
11352c9ca19SBrian Somers   static char failure[6];
11452c9ca19SBrian Somers   struct {
11552c9ca19SBrian Somers     u_short id;
11652c9ca19SBrian Somers     const char *txt;
11752c9ca19SBrian Somers   } qtxt[] = {
11852c9ca19SBrian Somers     /* rfc1035/rfc1700 */
11952c9ca19SBrian Somers     { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
12052c9ca19SBrian Somers     { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
12152c9ca19SBrian Somers     { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
12252c9ca19SBrian Somers     { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
12352c9ca19SBrian Somers     { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
12452c9ca19SBrian Somers     { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
12552c9ca19SBrian Somers     { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
12652c9ca19SBrian Somers     { 254, "MAILA" }, { 255, "*" }
12752c9ca19SBrian Somers   };
12852c9ca19SBrian Somers   int f;
12952c9ca19SBrian Somers 
13052c9ca19SBrian Somers   for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
13152c9ca19SBrian Somers     if (qtxt[f].id == qtype)
13252c9ca19SBrian Somers       return qtxt[f].txt;
13352c9ca19SBrian Somers 
134d6d3eeabSBrian Somers   return HexStr(qtype, failure, sizeof failure);
13552c9ca19SBrian Somers }
13652c9ca19SBrian Somers 
137cad7e742SBrian Somers static __inline int
138944f7098SBrian Somers PortMatch(int op, u_short pport, u_short rport)
139af57ed9fSAtsushi Murai {
140af57ed9fSAtsushi Murai   switch (op) {
141af57ed9fSAtsushi Murai   case OP_EQ:
142af57ed9fSAtsushi Murai     return (pport == rport);
143af57ed9fSAtsushi Murai   case OP_GT:
144af57ed9fSAtsushi Murai     return (pport > rport);
145af57ed9fSAtsushi Murai   case OP_LT:
146af57ed9fSAtsushi Murai     return (pport < rport);
147af57ed9fSAtsushi Murai   default:
148af57ed9fSAtsushi Murai     return (0);
149af57ed9fSAtsushi Murai   }
150af57ed9fSAtsushi Murai }
151af57ed9fSAtsushi Murai 
152af57ed9fSAtsushi Murai /*
1535d9e6103SBrian Somers  *  Check a packet against a defined filter
154cad7e742SBrian Somers  *  Returns 0 to accept the packet, non-zero to drop the packet
155cad7e742SBrian Somers  *
156cad7e742SBrian Somers  *  If filtering is enabled, the initial fragment of a datagram must
157cad7e742SBrian Somers  *  contain the complete protocol header, and subsequent fragments
158cad7e742SBrian Somers  *  must not attempt to over-write it.
159af57ed9fSAtsushi Murai  */
160af57ed9fSAtsushi Murai static int
161cad7e742SBrian Somers FilterCheck(const struct ip *pip, const struct filter *filter)
162af57ed9fSAtsushi Murai {
163cad7e742SBrian Somers   int gotinfo;			/* true if IP payload decoded */
164cad7e742SBrian Somers   int cproto;			/* P_* protocol type if (gotinfo) */
165cad7e742SBrian Somers   int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
166cad7e742SBrian Somers   u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
167cad7e742SBrian Somers   int n;			/* filter rule to process */
168cad7e742SBrian Somers   int len;			/* bytes used in dbuff */
169cad7e742SBrian Somers   int didname;			/* true if filter header printed */
170cad7e742SBrian Somers   int match;			/* true if condition matched */
171cad7e742SBrian Somers   const struct filterent *fp = filter->rule;
1728390b576SBrian Somers   char dbuff[100];
173af57ed9fSAtsushi Murai 
174cad7e742SBrian Somers   if (fp->f_action == A_NONE)
175cad7e742SBrian Somers     return (0);		/* No rule is given. Permit this packet */
176cad7e742SBrian Somers 
177cad7e742SBrian Somers   /* Deny any packet fragment that tries to over-write the header.
178cad7e742SBrian Somers    * Since we no longer have the real header available, punt on the
179cad7e742SBrian Somers    * largest normal header - 20 bytes for TCP without options, rounded
180cad7e742SBrian Somers    * up to the next possible fragment boundary.  Since the smallest
181cad7e742SBrian Somers    * `legal' MTU is 576, and the smallest recommended MTU is 296, any
182cad7e742SBrian Somers    * fragmentation within this range is dubious at best */
183cad7e742SBrian Somers   len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
184cad7e742SBrian Somers   if (len > 0) {		/* Not first fragment within datagram */
185cad7e742SBrian Somers     if (len < (24 >> 3))	/* don't allow fragment to over-write header */
186cad7e742SBrian Somers       return (1);
187cad7e742SBrian Somers     /* permit fragments on in and out filter */
1884d9d17feSBrian Somers     return (!filter->fragok);
189cad7e742SBrian Somers   }
190cad7e742SBrian Somers 
19163f98b41SBrian Somers   cproto = gotinfo = estab = syn = finrst = didname = 0;
192af57ed9fSAtsushi Murai   sport = dport = 0;
193cad7e742SBrian Somers   for (n = 0; n < MAXFILTERS; ) {
194cad7e742SBrian Somers     if (fp->f_action == A_NONE) {
195cad7e742SBrian Somers       n++;
196cad7e742SBrian Somers       fp++;
197cad7e742SBrian Somers       continue;
198cad7e742SBrian Somers     }
1995ca5389aSBrian Somers 
200cad7e742SBrian Somers     if (!didname) {
201dd7e2610SBrian Somers       log_Printf(LogDEBUG, "%s filter:\n", filter->name);
2028390b576SBrian Somers       didname = 1;
203cad7e742SBrian Somers     }
2048390b576SBrian Somers 
205cad7e742SBrian Somers     match = 0;
206cad7e742SBrian Somers     if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
207cad7e742SBrian Somers 	  fp->f_src.mask.s_addr) &&
208cad7e742SBrian Somers 	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
209cad7e742SBrian Somers 	  fp->f_dst.mask.s_addr)) {
210cad7e742SBrian Somers       if (fp->f_proto != P_NONE) {
211af57ed9fSAtsushi Murai 	if (!gotinfo) {
212cad7e742SBrian Somers 	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
213cad7e742SBrian Somers 	  const struct tcphdr *th;
214cad7e742SBrian Somers 	  const struct udphdr *uh;
215cad7e742SBrian Somers 	  const struct icmp *ih;
216cad7e742SBrian Somers 	  int datalen;	/* IP datagram length */
217af57ed9fSAtsushi Murai 
218cad7e742SBrian Somers 	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
219af57ed9fSAtsushi Murai 	  switch (pip->ip_p) {
220af57ed9fSAtsushi Murai 	  case IPPROTO_ICMP:
221944f7098SBrian Somers 	    cproto = P_ICMP;
222cad7e742SBrian Somers 	    if (datalen < 8)	/* ICMP must be at least 8 octets */
223cad7e742SBrian Somers 	      return (1);
224cad7e742SBrian Somers 	    ih = (const struct icmp *) ptop;
225944f7098SBrian Somers 	    sport = ih->icmp_type;
22663f98b41SBrian Somers 	    estab = syn = finrst = -1;
227dd7e2610SBrian Somers 	    if (log_IsKept(LogDEBUG))
2288390b576SBrian Somers 	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
229af57ed9fSAtsushi Murai 	    break;
230eee772ecSBrian Somers 	  case IPPROTO_IGMP:
2311f9e5fe5SBrian Somers 	    cproto = P_IGMP;
232cad7e742SBrian Somers 	    if (datalen < 8)	/* IGMP uses 8-octet messages */
233cad7e742SBrian Somers 	      return (1);
2341f9e5fe5SBrian Somers 	    estab = syn = finrst = -1;
2351f9e5fe5SBrian Somers 	    sport = ntohs(0);
2361f9e5fe5SBrian Somers 	    break;
23728149effSBrian Somers #ifdef IPPROTO_GRE
23828149effSBrian Somers           case IPPROTO_GRE:
23928149effSBrian Somers             cproto = P_GRE;
24028149effSBrian Somers             if (datalen < 2)    /* GRE uses 2-octet+ messages */
24128149effSBrian Somers               return (1);
24228149effSBrian Somers             estab = syn = finrst = -1;
24328149effSBrian Somers             sport = ntohs(0);
24428149effSBrian Somers             break;
24528149effSBrian Somers #endif
24662e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
2472faae814SBrian Somers 	  case IPPROTO_OSPFIGP:
2482faae814SBrian Somers 	    cproto = P_OSPF;
2492faae814SBrian Somers 	    if (datalen < 8)	/* IGMP uses 8-octet messages */
2502faae814SBrian Somers 	      return (1);
2512faae814SBrian Somers 	    estab = syn = finrst = -1;
2522faae814SBrian Somers 	    sport = ntohs(0);
2532faae814SBrian Somers 	    break;
25462e85934SBrian Somers #endif
2551f9e5fe5SBrian Somers 	  case IPPROTO_UDP:
256eee772ecSBrian Somers 	  case IPPROTO_IPIP:
257944f7098SBrian Somers 	    cproto = P_UDP;
258cad7e742SBrian Somers 	    if (datalen < 8)	/* UDP header is 8 octets */
259cad7e742SBrian Somers 	      return (1);
260cad7e742SBrian Somers 	    uh = (const struct udphdr *) ptop;
261944f7098SBrian Somers 	    sport = ntohs(uh->uh_sport);
262944f7098SBrian Somers 	    dport = ntohs(uh->uh_dport);
26363f98b41SBrian Somers 	    estab = syn = finrst = -1;
264dd7e2610SBrian Somers 	    if (log_IsKept(LogDEBUG))
2658390b576SBrian Somers 	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
2668390b576SBrian Somers 		       sport, dport);
267af57ed9fSAtsushi Murai 	    break;
268af57ed9fSAtsushi Murai 	  case IPPROTO_TCP:
269944f7098SBrian Somers 	    cproto = P_TCP;
270cad7e742SBrian Somers 	    th = (const struct tcphdr *) ptop;
271cad7e742SBrian Somers 	    /* TCP headers are variable length.  The following code
272cad7e742SBrian Somers 	     * ensures that the TCP header length isn't de-referenced if
273cad7e742SBrian Somers 	     * the datagram is too short
274cad7e742SBrian Somers 	     */
275cad7e742SBrian Somers 	    if (datalen < 20 || datalen < (th->th_off << 2))
276cad7e742SBrian Somers 	      return (1);
277944f7098SBrian Somers 	    sport = ntohs(th->th_sport);
278944f7098SBrian Somers 	    dport = ntohs(th->th_dport);
279af57ed9fSAtsushi Murai 	    estab = (th->th_flags & TH_ACK);
28063f98b41SBrian Somers 	    syn = (th->th_flags & TH_SYN);
28163f98b41SBrian Somers 	    finrst = (th->th_flags & (TH_FIN|TH_RST));
2822b81c773SBrian Somers 	    if (log_IsKept(LogDEBUG)) {
2832b81c773SBrian Somers 	      if (!estab)
2848390b576SBrian Somers 		snprintf(dbuff, sizeof dbuff,
2858390b576SBrian Somers 			 "flags = %02x, sport = %d, dport = %d",
286927145beSBrian Somers 			 th->th_flags, sport, dport);
2872b81c773SBrian Somers 	      else
2882b81c773SBrian Somers 		*dbuff = '\0';
2892b81c773SBrian Somers 	    }
290af57ed9fSAtsushi Murai 	    break;
291af57ed9fSAtsushi Murai 	  default:
292cad7e742SBrian Somers 	    return (1);	/* We'll block unknown type of packet */
293af57ed9fSAtsushi Murai 	  }
294cad7e742SBrian Somers 
295dd7e2610SBrian Somers 	  if (log_IsKept(LogDEBUG)) {
2968390b576SBrian Somers 	    if (estab != -1) {
2978390b576SBrian Somers 	      len = strlen(dbuff);
29863f98b41SBrian Somers 	      snprintf(dbuff + len, sizeof dbuff - len,
29963f98b41SBrian Somers 		       ", estab = %d, syn = %d, finrst = %d",
30063f98b41SBrian Somers 		       estab, syn, finrst);
301af57ed9fSAtsushi Murai 	    }
302dd7e2610SBrian Somers 	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
3038390b576SBrian Somers 		       filter_Proto2Nam(cproto), dbuff);
3048390b576SBrian Somers 	  }
3058390b576SBrian Somers 	  gotinfo = 1;
3068390b576SBrian Somers 	}
307dd7e2610SBrian Somers 	if (log_IsKept(LogDEBUG)) {
308cad7e742SBrian Somers 	  if (fp->f_srcop != OP_NONE) {
3098390b576SBrian Somers 	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
310cad7e742SBrian Somers 		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
3118390b576SBrian Somers 	    len = strlen(dbuff);
3128390b576SBrian Somers 	  } else
3138390b576SBrian Somers 	    len = 0;
314cad7e742SBrian Somers 	  if (fp->f_dstop != OP_NONE) {
3158390b576SBrian Somers 	    snprintf(dbuff + len, sizeof dbuff - len,
316cad7e742SBrian Somers 		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
317cad7e742SBrian Somers 		     fp->f_dstport);
3188390b576SBrian Somers 	  } else if (!len)
3198390b576SBrian Somers 	    *dbuff = '\0';
3208390b576SBrian Somers 
321dd7e2610SBrian Somers 	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
3228390b576SBrian Somers 		     "check against proto %s%s, action = %s\n",
323cad7e742SBrian Somers 		     n, filter_Proto2Nam(fp->f_proto),
324cad7e742SBrian Somers 		     dbuff, filter_Action2Nam(fp->f_action));
3258390b576SBrian Somers 	}
326927145beSBrian Somers 
327cad7e742SBrian Somers 	if (cproto == fp->f_proto) {
328cad7e742SBrian Somers 	  if ((fp->f_srcop == OP_NONE ||
329cad7e742SBrian Somers 	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
330cad7e742SBrian Somers 	      (fp->f_dstop == OP_NONE ||
331cad7e742SBrian Somers 	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
332cad7e742SBrian Somers 	      (fp->f_estab == 0 || estab) &&
333cad7e742SBrian Somers 	      (fp->f_syn == 0 || syn) &&
334cad7e742SBrian Somers 	      (fp->f_finrst == 0 || finrst)) {
335cad7e742SBrian Somers 	    match = 1;
336af57ed9fSAtsushi Murai 	  }
337af57ed9fSAtsushi Murai 	}
338af57ed9fSAtsushi Murai       } else {
339cad7e742SBrian Somers 	/* Address is matched and no protocol specified. Make a decision. */
340dd7e2610SBrian Somers 	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
341cad7e742SBrian Somers 		   filter_Action2Nam(fp->f_action));
342cad7e742SBrian Somers 	match = 1;
343af57ed9fSAtsushi Murai       }
3448390b576SBrian Somers     } else
345dd7e2610SBrian Somers       log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
346cad7e742SBrian Somers 
347cad7e742SBrian Somers     if (match != fp->f_invert) {
348cad7e742SBrian Somers       /* Take specified action */
349cad7e742SBrian Somers       if (fp->f_action < A_NONE)
350cad7e742SBrian Somers 	fp = &filter->rule[n = fp->f_action];
351cad7e742SBrian Somers       else
352cad7e742SBrian Somers 	return (fp->f_action != A_PERMIT);
353cad7e742SBrian Somers     } else {
354cad7e742SBrian Somers       n++;
355af57ed9fSAtsushi Murai       fp++;
356af57ed9fSAtsushi Murai     }
357af57ed9fSAtsushi Murai   }
358cad7e742SBrian Somers   return (1);		/* No rule is mached. Deny this packet */
359af57ed9fSAtsushi Murai }
360af57ed9fSAtsushi Murai 
3615ca5389aSBrian Somers #ifdef notdef
362af57ed9fSAtsushi Murai static void
363944f7098SBrian Somers IcmpError(struct ip *pip, int code)
364af57ed9fSAtsushi Murai {
365af57ed9fSAtsushi Murai   struct mbuf *bp;
366af57ed9fSAtsushi Murai 
367af57ed9fSAtsushi Murai   if (pip->ip_p != IPPROTO_ICMP) {
36826af0ae9SBrian Somers     bp = m_get(m_len, MB_IPIN);
36926af0ae9SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, m_len);
370dd7e2610SBrian Somers     vj_SendFrame(bp);
37126af0ae9SBrian Somers     ipcp_AddOutOctets(m_len);
3721ae349f5Scvs2svn   }
373af57ed9fSAtsushi Murai }
374af57ed9fSAtsushi Murai #endif
375af57ed9fSAtsushi Murai 
37652c9ca19SBrian Somers static void
37752c9ca19SBrian Somers ip_LogDNS(const struct udphdr *uh, const char *direction)
37852c9ca19SBrian Somers {
37952c9ca19SBrian Somers   struct dns_header header;
38052c9ca19SBrian Somers   const u_short *pktptr;
38152c9ca19SBrian Somers   const u_char *ptr;
38252c9ca19SBrian Somers   u_short *hptr;
38352c9ca19SBrian Somers   int len;
38452c9ca19SBrian Somers 
38552c9ca19SBrian Somers   ptr = (const char *)uh + sizeof *uh;
38652c9ca19SBrian Somers   len = ntohs(uh->uh_ulen) - sizeof *uh;
38752c9ca19SBrian Somers   if (len < sizeof header + 5)		/* rfc1024 */
38852c9ca19SBrian Somers     return;
38952c9ca19SBrian Somers 
39052c9ca19SBrian Somers   pktptr = (const u_short *)ptr;
39152c9ca19SBrian Somers   hptr = (u_short *)&header;
39252c9ca19SBrian Somers   ptr += sizeof header;
39352c9ca19SBrian Somers   len -= sizeof header;
39452c9ca19SBrian Somers 
39552c9ca19SBrian Somers   while (pktptr < (const u_short *)ptr) {
39652c9ca19SBrian Somers     *hptr++ = ntohs(*pktptr);	/* Careful of macro side-effects ! */
39752c9ca19SBrian Somers     pktptr++;
39852c9ca19SBrian Somers   }
39952c9ca19SBrian Somers 
40052c9ca19SBrian Somers   if (header.opcode == OPCODE_QUERY && header.qr == 0) {
40152c9ca19SBrian Somers     /* rfc1035 */
40252c9ca19SBrian Somers     char name[MAXHOSTNAMELEN + 1], *n;
40352c9ca19SBrian Somers     const char *qtype, *qclass;
40452c9ca19SBrian Somers     const u_char *end;
40552c9ca19SBrian Somers 
40652c9ca19SBrian Somers     n = name;
40752c9ca19SBrian Somers     end = ptr + len - 4;
40852c9ca19SBrian Somers     if (end - ptr > MAXHOSTNAMELEN)
40952c9ca19SBrian Somers       end = ptr + MAXHOSTNAMELEN;
41052c9ca19SBrian Somers     while (ptr < end) {
41152c9ca19SBrian Somers       len = *ptr++;
41252c9ca19SBrian Somers       if (len > end - ptr)
41352c9ca19SBrian Somers         len = end - ptr;
41452c9ca19SBrian Somers       if (n != name)
41552c9ca19SBrian Somers         *n++ = '.';
41652c9ca19SBrian Somers       memcpy(n, ptr, len);
41752c9ca19SBrian Somers       ptr += len;
41852c9ca19SBrian Somers       n += len;
41952c9ca19SBrian Somers     }
42052c9ca19SBrian Somers     *n = '\0';
42152c9ca19SBrian Somers     qtype = dns_Qtype2Txt(ntohs(*(const u_short *)end));
42252c9ca19SBrian Somers     qclass = dns_Qclass2Txt(ntohs(*(const u_short *)(end + 2)));
42352c9ca19SBrian Somers 
42452c9ca19SBrian Somers     log_Printf(LogDNS, "%sbound query %s %s %s\n",
42552c9ca19SBrian Somers                direction, qclass, qtype, name);
42652c9ca19SBrian Somers   }
42752c9ca19SBrian Somers }
42852c9ca19SBrian Somers 
429af57ed9fSAtsushi Murai /*
430af57ed9fSAtsushi Murai  *  For debugging aid.
431af57ed9fSAtsushi Murai  */
432af57ed9fSAtsushi Murai int
4335ca5389aSBrian Somers PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
434af57ed9fSAtsushi Murai {
43552c9ca19SBrian Somers   static const char *const TcpFlags[] = {
43652c9ca19SBrian Somers     "FIN", "SYN", "RST", "PSH", "ACK", "URG"
43752c9ca19SBrian Somers   };
438af57ed9fSAtsushi Murai   struct ip *pip;
439af57ed9fSAtsushi Murai   struct tcphdr *th;
440af57ed9fSAtsushi Murai   struct udphdr *uh;
441af57ed9fSAtsushi Murai   struct icmp *icmph;
442af57ed9fSAtsushi Murai   char *ptop;
44352c9ca19SBrian Somers   int mask, len, n, pri, logit, loglen, result;
444d93d3a9cSBrian Somers   char logbuf[200];
445af57ed9fSAtsushi Murai 
446b565321aSBrian Somers   logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
447b565321aSBrian Somers           (!filter || filter->logok);
44855a8cdeaSBrian Somers   loglen = 0;
44952c9ca19SBrian Somers   pri = 0;
450af57ed9fSAtsushi Murai 
451af57ed9fSAtsushi Murai   pip = (struct ip *)cp;
45252c9ca19SBrian Somers   uh = NULL;
453af57ed9fSAtsushi Murai 
45455a8cdeaSBrian Somers   if (logit && loglen < sizeof logbuf) {
455b565321aSBrian Somers     if (filter)
4565ca5389aSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
457b565321aSBrian Somers     else
458b565321aSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen, "  ");
45955a8cdeaSBrian Somers     loglen += strlen(logbuf + loglen);
46055a8cdeaSBrian Somers   }
461af57ed9fSAtsushi Murai   ptop = (cp + (pip->ip_hl << 2));
462af57ed9fSAtsushi Murai 
463af57ed9fSAtsushi Murai   switch (pip->ip_p) {
464af57ed9fSAtsushi Murai   case IPPROTO_ICMP:
46555a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
466af57ed9fSAtsushi Murai       icmph = (struct icmp *) ptop;
46755a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
46855a8cdeaSBrian Somers 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
46955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
47055a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
47155a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
47255a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
473af57ed9fSAtsushi Murai     }
474af57ed9fSAtsushi Murai     break;
475da477886SBrian Somers 
476af57ed9fSAtsushi Murai   case IPPROTO_UDP:
477af57ed9fSAtsushi Murai     uh = (struct udphdr *) ptop;
478da477886SBrian Somers     if (pip->ip_tos == IPTOS_LOWDELAY)
479da477886SBrian Somers       pri++;
480da477886SBrian Somers 
481da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
482da477886SBrian Somers         ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
483da477886SBrian Somers                           ntohs(uh->uh_dport)))
484da477886SBrian Somers       pri++;
485da477886SBrian Somers 
486da477886SBrian Somers     if (logit && loglen < sizeof logbuf) {
48755a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
48855a8cdeaSBrian Somers 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
48955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
49055a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
49155a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
49255a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
493af57ed9fSAtsushi Murai     }
494af57ed9fSAtsushi Murai     break;
495da477886SBrian Somers 
49628149effSBrian Somers #ifdef IPPROTO_GRE
49728149effSBrian Somers   case IPPROTO_GRE:
49828149effSBrian Somers     if (logit && loglen < sizeof logbuf) {
49928149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
50028149effSBrian Somers           "GRE: %s ---> ", inet_ntoa(pip->ip_src));
50128149effSBrian Somers       loglen += strlen(logbuf + loglen);
50228149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
50328149effSBrian Somers               "%s", inet_ntoa(pip->ip_dst));
50428149effSBrian Somers       loglen += strlen(logbuf + loglen);
50528149effSBrian Somers     }
50628149effSBrian Somers     break;
50728149effSBrian Somers #endif
50828149effSBrian Somers 
50962e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
5102faae814SBrian Somers   case IPPROTO_OSPFIGP:
5112faae814SBrian Somers     if (logit && loglen < sizeof logbuf) {
5122faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
5132faae814SBrian Somers 	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
5142faae814SBrian Somers       loglen += strlen(logbuf + loglen);
5152faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
5162faae814SBrian Somers 	       "%s", inet_ntoa(pip->ip_dst));
5172faae814SBrian Somers       loglen += strlen(logbuf + loglen);
5182faae814SBrian Somers     }
5192faae814SBrian Somers     break;
52062e85934SBrian Somers #endif
521da477886SBrian Somers 
522eee772ecSBrian Somers   case IPPROTO_IPIP:
523eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
524eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
525eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
526eee772ecSBrian Somers 	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
527eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
528eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
529eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
530eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
531eee772ecSBrian Somers     }
532eee772ecSBrian Somers     break;
533da477886SBrian Somers 
534eee772ecSBrian Somers   case IPPROTO_IGMP:
535eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
536eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
537eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
538eee772ecSBrian Somers 	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
539eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
540eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
541eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
542eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
543eee772ecSBrian Somers     }
544eee772ecSBrian Somers     break;
545da477886SBrian Somers 
546af57ed9fSAtsushi Murai   case IPPROTO_TCP:
547af57ed9fSAtsushi Murai     th = (struct tcphdr *) ptop;
548af57ed9fSAtsushi Murai     if (pip->ip_tos == IPTOS_LOWDELAY)
549442f8495SBrian Somers       pri++;
550da477886SBrian Somers 
551da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
552da477886SBrian Somers         ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
553442f8495SBrian Somers                           ntohs(th->th_dport)))
554442f8495SBrian Somers       pri++;
555442f8495SBrian Somers 
55655a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
557af57ed9fSAtsushi Murai       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
55855a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
55955a8cdeaSBrian Somers 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
56055a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
56155a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
56255a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
56355a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
564af57ed9fSAtsushi Murai       n = 0;
565af57ed9fSAtsushi Murai       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
56655a8cdeaSBrian Somers 	if (th->th_flags & mask) {
56755a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
56855a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
56955a8cdeaSBrian Somers 	}
570af57ed9fSAtsushi Murai 	n++;
571af57ed9fSAtsushi Murai       }
57255a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
5733a2e4f62SBrian Somers 	       "  seq:%lx  ack:%lx (%d/%d)",
5743a2e4f62SBrian Somers 	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
57555a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
576af57ed9fSAtsushi Murai       if ((th->th_flags & TH_SYN) && nb > 40) {
577af57ed9fSAtsushi Murai 	u_short *sp;
578af57ed9fSAtsushi Murai 
579af57ed9fSAtsushi Murai 	ptop += 20;
580af57ed9fSAtsushi Murai 	sp = (u_short *) ptop;
58155a8cdeaSBrian Somers 	if (ntohs(sp[0]) == 0x0204) {
58255a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
58355a8cdeaSBrian Somers 		   " MSS = %d", ntohs(sp[1]));
58455a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
58555a8cdeaSBrian Somers 	}
586af57ed9fSAtsushi Murai       }
587af57ed9fSAtsushi Murai     }
588af57ed9fSAtsushi Murai     break;
589af57ed9fSAtsushi Murai   }
59076bd0c0aSDoug Rabson 
591b565321aSBrian Somers   if (filter && FilterCheck(pip, filter)) {
592710e9c29SBrian Somers     if (logit)
593dd7e2610SBrian Somers       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
5945ca5389aSBrian Somers #ifdef notdef
595944f7098SBrian Somers     if (direction == 0)
596944f7098SBrian Somers       IcmpError(pip, pri);
5975ca5389aSBrian Somers #endif
59852c9ca19SBrian Somers     result = -1;
599af57ed9fSAtsushi Murai   } else {
6005ca5389aSBrian Somers     /* Check Keep Alive filter */
60152c9ca19SBrian Somers     if (logit && log_IsKept(LogTCPIP)) {
602b565321aSBrian Somers       if (filter && FilterCheck(pip, &bundle->filter.alive))
603dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
6041e991daaSBrian Somers       else
605dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s\n", logbuf);
60653c9f6c0SAtsushi Murai     }
60752c9ca19SBrian Somers     result = pri;
608af57ed9fSAtsushi Murai   }
60952c9ca19SBrian Somers 
610b565321aSBrian Somers   if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
61152c9ca19SBrian Somers     ip_LogDNS(uh, filter->name);
61252c9ca19SBrian Somers 
61352c9ca19SBrian Somers   return result;
614af57ed9fSAtsushi Murai }
615af57ed9fSAtsushi Murai 
6165d9e6103SBrian Somers struct mbuf *
6175d9e6103SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
6187a6f8720SBrian Somers {
619af57ed9fSAtsushi Murai   int nb, nw;
620b6e82f33SBrian Somers   struct tun_data tun;
6215d9e6103SBrian Somers   struct ip *pip;
6223a7b6d76SBrian Somers   char *data;
6235d9e6103SBrian Somers 
6245d9e6103SBrian Somers   if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
6255d9e6103SBrian Somers     log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
62626af0ae9SBrian Somers     m_freem(bp);
6275d9e6103SBrian Somers     return NULL;
6285d9e6103SBrian Somers   }
629af57ed9fSAtsushi Murai 
63026af0ae9SBrian Somers   m_settype(bp, MB_IPIN);
63126af0ae9SBrian Somers   nb = m_length(bp);
63276d98538SBrian Somers   if (nb > sizeof tun.data) {
63376d98538SBrian Somers     log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
63476d98538SBrian Somers                l->name, nb, (int)(sizeof tun.data));
63526af0ae9SBrian Somers     m_freem(bp);
63676d98538SBrian Somers     return NULL;
63776d98538SBrian Somers   }
6385d9e6103SBrian Somers   mbuf_Read(bp, tun.data, nb);
639af57ed9fSAtsushi Murai 
6405d9e6103SBrian Somers   if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
6415d9e6103SBrian Somers     return NULL;
6426db75539SBrian Somers 
6435d9e6103SBrian Somers   pip = (struct ip *)tun.data;
644cad7e742SBrian Somers   if (!FilterCheck(pip, &bundle->filter.alive))
6451e991daaSBrian Somers     bundle_StartIdleTimer(bundle);
6461e991daaSBrian Somers 
6475828db6dSBrian Somers   ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
6481e991daaSBrian Somers 
6493a7b6d76SBrian Somers   if (bundle->dev.header) {
6503a7b6d76SBrian Somers     tun.family = htonl(AF_INET);
65170ee81ffSBrian Somers     nb += sizeof tun - sizeof tun.data;
6523a7b6d76SBrian Somers     data = (char *)&tun;
6533a7b6d76SBrian Somers   } else
6543a7b6d76SBrian Somers     data = tun.data;
6553a7b6d76SBrian Somers 
6563a7b6d76SBrian Somers   nw = write(bundle->dev.fd, data, nb);
657c4c4aaacSBrian Somers   if (nw != nb) {
65857fd05c4SBrian Somers     if (nw == -1)
65976d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
66076d98538SBrian Somers                  l->name, nb, strerror(errno));
66157fd05c4SBrian Somers     else
66276d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
6636db75539SBrian Somers   }
6645d9e6103SBrian Somers 
6655d9e6103SBrian Somers   return NULL;
666af57ed9fSAtsushi Murai }
667af57ed9fSAtsushi Murai 
668af57ed9fSAtsushi Murai void
6695a72b6edSBrian Somers ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
670af57ed9fSAtsushi Murai {
671af57ed9fSAtsushi Murai   struct mbuf *bp;
672af57ed9fSAtsushi Murai 
673442f8495SBrian Somers   if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
6745a72b6edSBrian Somers     log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
6755a72b6edSBrian Somers   else {
6765d9e6103SBrian Somers     /*
6775d9e6103SBrian Somers      * We allocate an extra 6 bytes, four at the front and two at the end.
6785d9e6103SBrian Somers      * This is an optimisation so that we need to do less work in
67926af0ae9SBrian Somers      * m_prepend() in acf_LayerPush() and proto_LayerPush() and
6805d9e6103SBrian Somers      * appending in hdlc_LayerPush().
6815d9e6103SBrian Somers      */
68226af0ae9SBrian Somers     bp = m_get(count + 6, MB_IPOUT);
68326af0ae9SBrian Somers     bp->m_offset += 4;
68426af0ae9SBrian Somers     bp->m_len -= 6;
68575240ed1SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, count);
68626af0ae9SBrian Somers     m_enqueue(ipcp->Queue + pri, bp);
6875a72b6edSBrian Somers   }
688af57ed9fSAtsushi Murai }
689af57ed9fSAtsushi Murai 
6906f8e9f0aSBrian Somers void
6915a72b6edSBrian Somers ip_DeleteQueue(struct ipcp *ipcp)
6926f8e9f0aSBrian Somers {
6936f8e9f0aSBrian Somers   struct mqueue *queue;
6946f8e9f0aSBrian Somers 
695442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
6966f8e9f0aSBrian Somers     while (queue->top)
69726af0ae9SBrian Somers       m_freem(m_dequeue(queue));
6986f8e9f0aSBrian Somers }
6996f8e9f0aSBrian Somers 
70026af0ae9SBrian Somers size_t
7015a72b6edSBrian Somers ip_QueueLen(struct ipcp *ipcp)
70284b8a6ebSAtsushi Murai {
70384b8a6ebSAtsushi Murai   struct mqueue *queue;
70426af0ae9SBrian Somers   size_t result;
705944f7098SBrian Somers 
70626af0ae9SBrian Somers   result = 0;
707442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
70826af0ae9SBrian Somers     result += queue->len;
70984b8a6ebSAtsushi Murai 
710f4768038SBrian Somers   return result;
7111ae349f5Scvs2svn }
7121ae349f5Scvs2svn 
7133b0f8d2eSBrian Somers int
7145d9e6103SBrian Somers ip_PushPacket(struct link *l, struct bundle *bundle)
715af57ed9fSAtsushi Murai {
7165a72b6edSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
717af57ed9fSAtsushi Murai   struct mqueue *queue;
718af57ed9fSAtsushi Murai   struct mbuf *bp;
7195d9e6103SBrian Somers   struct ip *pip;
72026af0ae9SBrian Somers   int m_len;
721af57ed9fSAtsushi Murai 
7225a72b6edSBrian Somers   if (ipcp->fsm.state != ST_OPENED)
7233b0f8d2eSBrian Somers     return 0;
7241e991daaSBrian Somers 
725442f8495SBrian Somers   queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
726442f8495SBrian Somers   do {
727af57ed9fSAtsushi Murai     if (queue->top) {
72826af0ae9SBrian Somers       bp = m_pullup(m_dequeue(queue));
72926af0ae9SBrian Somers       m_len = m_length(bp);
7305d9e6103SBrian Somers       pip = (struct ip *)MBUF_CTOP(bp);
731cad7e742SBrian Somers       if (!FilterCheck(pip, &bundle->filter.alive))
732ab886ad0SBrian Somers         bundle_StartIdleTimer(bundle);
733442f8495SBrian Somers       link_PushPacket(l, bp, bundle, 0, PROTO_IP);
73426af0ae9SBrian Somers       ipcp_AddOutOctets(ipcp, m_len);
7353b0f8d2eSBrian Somers       return 1;
736af57ed9fSAtsushi Murai     }
737442f8495SBrian Somers   } while (queue-- != ipcp->Queue);
7381e991daaSBrian Somers 
7393b0f8d2eSBrian Somers   return 0;
740af57ed9fSAtsushi Murai }
741