xref: /freebsd/usr.sbin/ppp/ip.c (revision d6d3eeab46e7906545356c7571e46f0c61a5a397)
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 
44652c9ca19SBrian Somers   logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) && filter->logok;
44755a8cdeaSBrian Somers   loglen = 0;
44852c9ca19SBrian Somers   pri = 0;
449af57ed9fSAtsushi Murai 
450af57ed9fSAtsushi Murai   pip = (struct ip *)cp;
45152c9ca19SBrian Somers   uh = NULL;
452af57ed9fSAtsushi Murai 
45355a8cdeaSBrian Somers   if (logit && loglen < sizeof logbuf) {
4545ca5389aSBrian Somers     snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
45555a8cdeaSBrian Somers     loglen += strlen(logbuf + loglen);
45655a8cdeaSBrian Somers   }
457af57ed9fSAtsushi Murai   ptop = (cp + (pip->ip_hl << 2));
458af57ed9fSAtsushi Murai 
459af57ed9fSAtsushi Murai   switch (pip->ip_p) {
460af57ed9fSAtsushi Murai   case IPPROTO_ICMP:
46155a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
462af57ed9fSAtsushi Murai       icmph = (struct icmp *) ptop;
46355a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
46455a8cdeaSBrian Somers 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
46555a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
46655a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
46755a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
46855a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
469af57ed9fSAtsushi Murai     }
470af57ed9fSAtsushi Murai     break;
471da477886SBrian Somers 
472af57ed9fSAtsushi Murai   case IPPROTO_UDP:
473af57ed9fSAtsushi Murai     uh = (struct udphdr *) ptop;
474da477886SBrian Somers     if (pip->ip_tos == IPTOS_LOWDELAY)
475da477886SBrian Somers       pri++;
476da477886SBrian Somers 
477da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
478da477886SBrian Somers         ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
479da477886SBrian Somers                           ntohs(uh->uh_dport)))
480da477886SBrian Somers       pri++;
481da477886SBrian Somers 
482da477886SBrian Somers     if (logit && loglen < sizeof logbuf) {
48355a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
48455a8cdeaSBrian Somers 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
48555a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
48655a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
48755a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
48855a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
489af57ed9fSAtsushi Murai     }
490af57ed9fSAtsushi Murai     break;
491da477886SBrian Somers 
49228149effSBrian Somers #ifdef IPPROTO_GRE
49328149effSBrian Somers   case IPPROTO_GRE:
49428149effSBrian Somers     if (logit && loglen < sizeof logbuf) {
49528149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
49628149effSBrian Somers           "GRE: %s ---> ", inet_ntoa(pip->ip_src));
49728149effSBrian Somers       loglen += strlen(logbuf + loglen);
49828149effSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
49928149effSBrian Somers               "%s", inet_ntoa(pip->ip_dst));
50028149effSBrian Somers       loglen += strlen(logbuf + loglen);
50128149effSBrian Somers     }
50228149effSBrian Somers     break;
50328149effSBrian Somers #endif
50428149effSBrian Somers 
50562e85934SBrian Somers #ifdef IPPROTO_OSPFIGP
5062faae814SBrian Somers   case IPPROTO_OSPFIGP:
5072faae814SBrian Somers     if (logit && loglen < sizeof logbuf) {
5082faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
5092faae814SBrian Somers 	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
5102faae814SBrian Somers       loglen += strlen(logbuf + loglen);
5112faae814SBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
5122faae814SBrian Somers 	       "%s", inet_ntoa(pip->ip_dst));
5132faae814SBrian Somers       loglen += strlen(logbuf + loglen);
5142faae814SBrian Somers     }
5152faae814SBrian Somers     break;
51662e85934SBrian Somers #endif
517da477886SBrian Somers 
518eee772ecSBrian Somers   case IPPROTO_IPIP:
519eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
520eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
521eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
522eee772ecSBrian Somers 	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
523eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
524eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
525eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
526eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
527eee772ecSBrian Somers     }
528eee772ecSBrian Somers     break;
529da477886SBrian Somers 
530eee772ecSBrian Somers   case IPPROTO_IGMP:
531eee772ecSBrian Somers     if (logit && loglen < sizeof logbuf) {
532eee772ecSBrian Somers       uh = (struct udphdr *) ptop;
533eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
534eee772ecSBrian Somers 	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
535eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
536eee772ecSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
537eee772ecSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
538eee772ecSBrian Somers       loglen += strlen(logbuf + loglen);
539eee772ecSBrian Somers     }
540eee772ecSBrian Somers     break;
541da477886SBrian Somers 
542af57ed9fSAtsushi Murai   case IPPROTO_TCP:
543af57ed9fSAtsushi Murai     th = (struct tcphdr *) ptop;
544af57ed9fSAtsushi Murai     if (pip->ip_tos == IPTOS_LOWDELAY)
545442f8495SBrian Somers       pri++;
546da477886SBrian Somers 
547da477886SBrian Somers     if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
548da477886SBrian Somers         ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
549442f8495SBrian Somers                           ntohs(th->th_dport)))
550442f8495SBrian Somers       pri++;
551442f8495SBrian Somers 
55255a8cdeaSBrian Somers     if (logit && loglen < sizeof logbuf) {
553af57ed9fSAtsushi Murai       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
55455a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
55555a8cdeaSBrian Somers 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
55655a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
55755a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
55855a8cdeaSBrian Somers 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
55955a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
560af57ed9fSAtsushi Murai       n = 0;
561af57ed9fSAtsushi Murai       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
56255a8cdeaSBrian Somers 	if (th->th_flags & mask) {
56355a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
56455a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
56555a8cdeaSBrian Somers 	}
566af57ed9fSAtsushi Murai 	n++;
567af57ed9fSAtsushi Murai       }
56855a8cdeaSBrian Somers       snprintf(logbuf + loglen, sizeof logbuf - loglen,
5693a2e4f62SBrian Somers 	       "  seq:%lx  ack:%lx (%d/%d)",
5703a2e4f62SBrian Somers 	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
57155a8cdeaSBrian Somers       loglen += strlen(logbuf + loglen);
572af57ed9fSAtsushi Murai       if ((th->th_flags & TH_SYN) && nb > 40) {
573af57ed9fSAtsushi Murai 	u_short *sp;
574af57ed9fSAtsushi Murai 
575af57ed9fSAtsushi Murai 	ptop += 20;
576af57ed9fSAtsushi Murai 	sp = (u_short *) ptop;
57755a8cdeaSBrian Somers 	if (ntohs(sp[0]) == 0x0204) {
57855a8cdeaSBrian Somers 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
57955a8cdeaSBrian Somers 		   " MSS = %d", ntohs(sp[1]));
58055a8cdeaSBrian Somers 	  loglen += strlen(logbuf + loglen);
58155a8cdeaSBrian Somers 	}
582af57ed9fSAtsushi Murai       }
583af57ed9fSAtsushi Murai     }
584af57ed9fSAtsushi Murai     break;
585af57ed9fSAtsushi Murai   }
58676bd0c0aSDoug Rabson 
587cad7e742SBrian Somers   if (FilterCheck(pip, filter)) {
588710e9c29SBrian Somers     if (logit)
589dd7e2610SBrian Somers       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
5905ca5389aSBrian Somers #ifdef notdef
591944f7098SBrian Somers     if (direction == 0)
592944f7098SBrian Somers       IcmpError(pip, pri);
5935ca5389aSBrian Somers #endif
59452c9ca19SBrian Somers     result = -1;
595af57ed9fSAtsushi Murai   } else {
5965ca5389aSBrian Somers     /* Check Keep Alive filter */
59752c9ca19SBrian Somers     if (logit && log_IsKept(LogTCPIP)) {
598cad7e742SBrian Somers       if (FilterCheck(pip, &bundle->filter.alive))
599dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
6001e991daaSBrian Somers       else
601dd7e2610SBrian Somers         log_Printf(LogTCPIP, "%s\n", logbuf);
60253c9f6c0SAtsushi Murai     }
60352c9ca19SBrian Somers     result = pri;
604af57ed9fSAtsushi Murai   }
60552c9ca19SBrian Somers 
60652c9ca19SBrian Somers   if (uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
60752c9ca19SBrian Somers     ip_LogDNS(uh, filter->name);
60852c9ca19SBrian Somers 
60952c9ca19SBrian Somers   return result;
610af57ed9fSAtsushi Murai }
611af57ed9fSAtsushi Murai 
6125d9e6103SBrian Somers struct mbuf *
6135d9e6103SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
6147a6f8720SBrian Somers {
615af57ed9fSAtsushi Murai   int nb, nw;
616b6e82f33SBrian Somers   struct tun_data tun;
6175d9e6103SBrian Somers   struct ip *pip;
6183a7b6d76SBrian Somers   char *data;
6195d9e6103SBrian Somers 
6205d9e6103SBrian Somers   if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
6215d9e6103SBrian Somers     log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
62226af0ae9SBrian Somers     m_freem(bp);
6235d9e6103SBrian Somers     return NULL;
6245d9e6103SBrian Somers   }
625af57ed9fSAtsushi Murai 
62626af0ae9SBrian Somers   m_settype(bp, MB_IPIN);
62726af0ae9SBrian Somers   nb = m_length(bp);
62876d98538SBrian Somers   if (nb > sizeof tun.data) {
62976d98538SBrian Somers     log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
63076d98538SBrian Somers                l->name, nb, (int)(sizeof tun.data));
63126af0ae9SBrian Somers     m_freem(bp);
63276d98538SBrian Somers     return NULL;
63376d98538SBrian Somers   }
6345d9e6103SBrian Somers   mbuf_Read(bp, tun.data, nb);
635af57ed9fSAtsushi Murai 
6365d9e6103SBrian Somers   if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
6375d9e6103SBrian Somers     return NULL;
6386db75539SBrian Somers 
6395d9e6103SBrian Somers   pip = (struct ip *)tun.data;
640cad7e742SBrian Somers   if (!FilterCheck(pip, &bundle->filter.alive))
6411e991daaSBrian Somers     bundle_StartIdleTimer(bundle);
6421e991daaSBrian Somers 
6435828db6dSBrian Somers   ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
6441e991daaSBrian Somers 
6453a7b6d76SBrian Somers   if (bundle->dev.header) {
6463a7b6d76SBrian Somers     tun.family = htonl(AF_INET);
64770ee81ffSBrian Somers     nb += sizeof tun - sizeof tun.data;
6483a7b6d76SBrian Somers     data = (char *)&tun;
6493a7b6d76SBrian Somers   } else
6503a7b6d76SBrian Somers     data = tun.data;
6513a7b6d76SBrian Somers 
6523a7b6d76SBrian Somers   nw = write(bundle->dev.fd, data, nb);
653c4c4aaacSBrian Somers   if (nw != nb) {
65457fd05c4SBrian Somers     if (nw == -1)
65576d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
65676d98538SBrian Somers                  l->name, nb, strerror(errno));
65757fd05c4SBrian Somers     else
65876d98538SBrian Somers       log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
6596db75539SBrian Somers   }
6605d9e6103SBrian Somers 
6615d9e6103SBrian Somers   return NULL;
662af57ed9fSAtsushi Murai }
663af57ed9fSAtsushi Murai 
664af57ed9fSAtsushi Murai void
6655a72b6edSBrian Somers ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
666af57ed9fSAtsushi Murai {
667af57ed9fSAtsushi Murai   struct mbuf *bp;
668af57ed9fSAtsushi Murai 
669442f8495SBrian Somers   if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
6705a72b6edSBrian Somers     log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
6715a72b6edSBrian Somers   else {
6725d9e6103SBrian Somers     /*
6735d9e6103SBrian Somers      * We allocate an extra 6 bytes, four at the front and two at the end.
6745d9e6103SBrian Somers      * This is an optimisation so that we need to do less work in
67526af0ae9SBrian Somers      * m_prepend() in acf_LayerPush() and proto_LayerPush() and
6765d9e6103SBrian Somers      * appending in hdlc_LayerPush().
6775d9e6103SBrian Somers      */
67826af0ae9SBrian Somers     bp = m_get(count + 6, MB_IPOUT);
67926af0ae9SBrian Somers     bp->m_offset += 4;
68026af0ae9SBrian Somers     bp->m_len -= 6;
68175240ed1SBrian Somers     memcpy(MBUF_CTOP(bp), ptr, count);
68226af0ae9SBrian Somers     m_enqueue(ipcp->Queue + pri, bp);
6835a72b6edSBrian Somers   }
684af57ed9fSAtsushi Murai }
685af57ed9fSAtsushi Murai 
6866f8e9f0aSBrian Somers void
6875a72b6edSBrian Somers ip_DeleteQueue(struct ipcp *ipcp)
6886f8e9f0aSBrian Somers {
6896f8e9f0aSBrian Somers   struct mqueue *queue;
6906f8e9f0aSBrian Somers 
691442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
6926f8e9f0aSBrian Somers     while (queue->top)
69326af0ae9SBrian Somers       m_freem(m_dequeue(queue));
6946f8e9f0aSBrian Somers }
6956f8e9f0aSBrian Somers 
69626af0ae9SBrian Somers size_t
6975a72b6edSBrian Somers ip_QueueLen(struct ipcp *ipcp)
69884b8a6ebSAtsushi Murai {
69984b8a6ebSAtsushi Murai   struct mqueue *queue;
70026af0ae9SBrian Somers   size_t result;
701944f7098SBrian Somers 
70226af0ae9SBrian Somers   result = 0;
703442f8495SBrian Somers   for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
70426af0ae9SBrian Somers     result += queue->len;
70584b8a6ebSAtsushi Murai 
706f4768038SBrian Somers   return result;
7071ae349f5Scvs2svn }
7081ae349f5Scvs2svn 
7093b0f8d2eSBrian Somers int
7105d9e6103SBrian Somers ip_PushPacket(struct link *l, struct bundle *bundle)
711af57ed9fSAtsushi Murai {
7125a72b6edSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
713af57ed9fSAtsushi Murai   struct mqueue *queue;
714af57ed9fSAtsushi Murai   struct mbuf *bp;
7155d9e6103SBrian Somers   struct ip *pip;
71626af0ae9SBrian Somers   int m_len;
717af57ed9fSAtsushi Murai 
7185a72b6edSBrian Somers   if (ipcp->fsm.state != ST_OPENED)
7193b0f8d2eSBrian Somers     return 0;
7201e991daaSBrian Somers 
721442f8495SBrian Somers   queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
722442f8495SBrian Somers   do {
723af57ed9fSAtsushi Murai     if (queue->top) {
72426af0ae9SBrian Somers       bp = m_pullup(m_dequeue(queue));
72526af0ae9SBrian Somers       m_len = m_length(bp);
7265d9e6103SBrian Somers       pip = (struct ip *)MBUF_CTOP(bp);
727cad7e742SBrian Somers       if (!FilterCheck(pip, &bundle->filter.alive))
728ab886ad0SBrian Somers         bundle_StartIdleTimer(bundle);
729442f8495SBrian Somers       link_PushPacket(l, bp, bundle, 0, PROTO_IP);
73026af0ae9SBrian Somers       ipcp_AddOutOctets(ipcp, m_len);
7313b0f8d2eSBrian Somers       return 1;
732af57ed9fSAtsushi Murai     }
733442f8495SBrian Somers   } while (queue-- != ipcp->Queue);
7341e991daaSBrian Somers 
7353b0f8d2eSBrian Somers   return 0;
736af57ed9fSAtsushi Murai }
737