ip.c revision 78189
178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD: head/usr.sbin/ppp/ip.c 78189 2001-06-13 21:52:19Z brian $
296059Samurai */
3078189Sbrian
3143313Sbrian#include <sys/param.h>
3231195Sbrian#include <sys/socket.h>
3330715Sbrian#include <netinet/in.h>
346059Samurai#include <netinet/in_systm.h>
356059Samurai#include <netinet/ip.h>
366059Samurai#include <netinet/ip_icmp.h>
376059Samurai#include <netinet/udp.h>
386059Samurai#include <netinet/tcp.h>
3913389Sphk#include <arpa/inet.h>
4036285Sbrian#include <sys/un.h>
4130715Sbrian
4230092Sbrian#include <errno.h>
4330715Sbrian#include <stdio.h>
4430715Sbrian#include <string.h>
4546686Sbrian#include <termios.h>
4630715Sbrian#include <unistd.h>
4730715Sbrian
4846686Sbrian#include "layer.h"
4946686Sbrian#include "proto.h"
5030715Sbrian#include "mbuf.h"
5130715Sbrian#include "log.h"
5230715Sbrian#include "defs.h"
5330715Sbrian#include "timer.h"
5430715Sbrian#include "fsm.h"
5536285Sbrian#include "lqr.h"
5630715Sbrian#include "hdlc.h"
5736285Sbrian#include "throughput.h"
5836285Sbrian#include "iplist.h"
5936285Sbrian#include "slcompress.h"
6036285Sbrian#include "ipcp.h"
616059Samurai#include "filter.h"
6236285Sbrian#include "descriptor.h"
6336285Sbrian#include "lcp.h"
6436285Sbrian#include "ccp.h"
6536285Sbrian#include "link.h"
6636285Sbrian#include "mp.h"
6743313Sbrian#ifndef NORADIUS
6843313Sbrian#include "radius.h"
6943313Sbrian#endif
7036285Sbrian#include "bundle.h"
7131195Sbrian#include "tun.h"
7230715Sbrian#include "ip.h"
736059Samurai
7458033Sbrian
7558033Sbrian#define OPCODE_QUERY	0
7658033Sbrian#define OPCODE_IQUERY	1
7758033Sbrian#define OPCODE_STATUS	2
7858033Sbrian
7958033Sbrianstruct dns_header {
8058033Sbrian  u_short id;
8158033Sbrian  unsigned qr : 1;
8258033Sbrian  unsigned opcode : 4;
8358033Sbrian  unsigned aa : 1;
8458033Sbrian  unsigned tc : 1;
8558033Sbrian  unsigned rd : 1;
8658033Sbrian  unsigned ra : 1;
8758033Sbrian  unsigned z : 3;
8858033Sbrian  unsigned rcode : 4;
8958033Sbrian  u_short qdcount;
9058033Sbrian  u_short ancount;
9158033Sbrian  u_short nscount;
9258033Sbrian  u_short arcount;
9355146Sbrian};
946059Samurai
9558033Sbrianstatic const char *
9658033Sbriandns_Qclass2Txt(u_short qclass)
9758033Sbrian{
9858033Sbrian  static char failure[6];
9958033Sbrian  struct {
10058033Sbrian    u_short id;
10158033Sbrian    const char *txt;
10258033Sbrian  } qtxt[] = {
10358033Sbrian    /* rfc1035 */
10458033Sbrian    { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" }
10558033Sbrian  };
10658033Sbrian  int f;
10758033Sbrian
10858033Sbrian  for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
10958033Sbrian    if (qtxt[f].id == qclass)
11058033Sbrian      return qtxt[f].txt;
11158033Sbrian
11258034Sbrian  return HexStr(qclass, failure, sizeof failure);
11358033Sbrian}
11458033Sbrian
11558033Sbrianstatic const char *
11658033Sbriandns_Qtype2Txt(u_short qtype)
11758033Sbrian{
11858033Sbrian  static char failure[6];
11958033Sbrian  struct {
12058033Sbrian    u_short id;
12158033Sbrian    const char *txt;
12258033Sbrian  } qtxt[] = {
12358033Sbrian    /* rfc1035/rfc1700 */
12458033Sbrian    { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
12558033Sbrian    { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
12658033Sbrian    { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
12758033Sbrian    { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
12858033Sbrian    { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
12958033Sbrian    { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
13058033Sbrian    { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
13158033Sbrian    { 254, "MAILA" }, { 255, "*" }
13258033Sbrian  };
13358033Sbrian  int f;
13458033Sbrian
13558033Sbrian  for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
13658033Sbrian    if (qtxt[f].id == qtype)
13758033Sbrian      return qtxt[f].txt;
13858033Sbrian
13958034Sbrian  return HexStr(qtype, failure, sizeof failure);
14058033Sbrian}
14158033Sbrian
14249140Sbrianstatic __inline int
14328679SbrianPortMatch(int op, u_short pport, u_short rport)
1446059Samurai{
1456059Samurai  switch (op) {
14649140Sbrian  case OP_EQ:
14762977Sbrian    return pport == rport;
1486059Samurai  case OP_GT:
14962977Sbrian    return pport > rport;
1506059Samurai  case OP_LT:
15162977Sbrian    return pport < rport;
1526059Samurai  default:
15362977Sbrian    return 0;
1546059Samurai  }
1556059Samurai}
1566059Samurai
1576059Samurai/*
15846686Sbrian *  Check a packet against a defined filter
15949140Sbrian *  Returns 0 to accept the packet, non-zero to drop the packet
16049140Sbrian *
16149140Sbrian *  If filtering is enabled, the initial fragment of a datagram must
16249140Sbrian *  contain the complete protocol header, and subsequent fragments
16349140Sbrian *  must not attempt to over-write it.
1646059Samurai */
1656059Samuraistatic int
16662977SbrianFilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
1676059Samurai{
16849140Sbrian  int gotinfo;			/* true if IP payload decoded */
16949140Sbrian  int cproto;			/* P_* protocol type if (gotinfo) */
17049140Sbrian  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
17149140Sbrian  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
17249140Sbrian  int n;			/* filter rule to process */
17349140Sbrian  int len;			/* bytes used in dbuff */
17449140Sbrian  int didname;			/* true if filter header printed */
17549140Sbrian  int match;			/* true if condition matched */
17649140Sbrian  const struct filterent *fp = filter->rule;
17765181Sbrian  char dbuff[100], dstip[16];
1786059Samurai
17949140Sbrian  if (fp->f_action == A_NONE)
18062977Sbrian    return 0;		/* No rule is given. Permit this packet */
18136285Sbrian
18262977Sbrian  /*
18362977Sbrian   * Deny any packet fragment that tries to over-write the header.
18449140Sbrian   * Since we no longer have the real header available, punt on the
18549140Sbrian   * largest normal header - 20 bytes for TCP without options, rounded
18649140Sbrian   * up to the next possible fragment boundary.  Since the smallest
18749140Sbrian   * `legal' MTU is 576, and the smallest recommended MTU is 296, any
18862977Sbrian   * fragmentation within this range is dubious at best
18962977Sbrian   */
19049140Sbrian  len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
19149140Sbrian  if (len > 0) {		/* Not first fragment within datagram */
19265181Sbrian    if (len < (24 >> 3)) {	/* don't allow fragment to over-write header */
19365181Sbrian      log_Printf(LogFILTER, " error: illegal header\n");
19462977Sbrian      return 1;
19565181Sbrian    }
19649140Sbrian    /* permit fragments on in and out filter */
19765181Sbrian    if (!filter->fragok) {
19865181Sbrian      log_Printf(LogFILTER, " error: illegal fragmentation\n");
19965181Sbrian      return 1;
20065181Sbrian    } else
20165181Sbrian      return 0;
20249140Sbrian  }
20349140Sbrian
20449140Sbrian  cproto = gotinfo = estab = syn = finrst = didname = 0;
20549140Sbrian  sport = dport = 0;
20649140Sbrian  for (n = 0; n < MAXFILTERS; ) {
20749140Sbrian    if (fp->f_action == A_NONE) {
20849140Sbrian      n++;
20949140Sbrian      fp++;
21049140Sbrian      continue;
21149140Sbrian    }
21236285Sbrian
21349140Sbrian    if (!didname) {
21449140Sbrian      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
21549140Sbrian      didname = 1;
21649140Sbrian    }
2176059Samurai
21849140Sbrian    match = 0;
21949140Sbrian    if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
22062977Sbrian          fp->f_src.mask.s_addr) &&
22162977Sbrian        !((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
22262977Sbrian          fp->f_dst.mask.s_addr)) {
22349140Sbrian      if (fp->f_proto != P_NONE) {
22462977Sbrian        if (!gotinfo) {
22562977Sbrian          const char *ptop = (const char *) pip + (pip->ip_hl << 2);
22662977Sbrian          const struct tcphdr *th;
22762977Sbrian          const struct udphdr *uh;
22862977Sbrian          const struct icmp *ih;
22962977Sbrian          int datalen;	/* IP datagram length */
23049140Sbrian
23162977Sbrian          datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
23262977Sbrian          switch (pip->ip_p) {
23362977Sbrian          case IPPROTO_ICMP:
23462977Sbrian            cproto = P_ICMP;
23565181Sbrian            if (datalen < 8) {	/* ICMP must be at least 8 octets */
23665181Sbrian              log_Printf(LogFILTER, " error: ICMP must be at least 8 octets\n");
23762977Sbrian              return 1;
23865181Sbrian            }
23965181Sbrian
24062977Sbrian            ih = (const struct icmp *) ptop;
24162977Sbrian            sport = ih->icmp_type;
24262977Sbrian            estab = syn = finrst = -1;
24362977Sbrian            if (log_IsKept(LogDEBUG))
24462977Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
24562977Sbrian            break;
24662977Sbrian          case IPPROTO_IGMP:
24762977Sbrian            cproto = P_IGMP;
24865181Sbrian            if (datalen < 8) {	/* IGMP uses 8-octet messages */
24965181Sbrian              log_Printf(LogFILTER, " error: IGMP must be at least 8 octets\n");
25062977Sbrian              return 1;
25165181Sbrian            }
25262977Sbrian            estab = syn = finrst = -1;
25362977Sbrian            sport = ntohs(0);
25462977Sbrian            break;
25551809Sbrian#ifdef IPPROTO_GRE
25651809Sbrian          case IPPROTO_GRE:
25751809Sbrian            cproto = P_GRE;
25865181Sbrian            if (datalen < 2) {    /* GRE uses 2-octet+ messages */
25965181Sbrian              log_Printf(LogFILTER, " error: GRE must be at least 2 octets\n");
26062977Sbrian              return 1;
26165181Sbrian            }
26251809Sbrian            estab = syn = finrst = -1;
26351809Sbrian            sport = ntohs(0);
26451809Sbrian            break;
26551809Sbrian#endif
26649374Sbrian#ifdef IPPROTO_OSPFIGP
26762977Sbrian          case IPPROTO_OSPFIGP:
26862977Sbrian            cproto = P_OSPF;
26965181Sbrian            if (datalen < 8) {	/* IGMP uses 8-octet messages */
27065181Sbrian              log_Printf(LogFILTER, " error: IGMP must be at least 8 octets\n");
27162977Sbrian              return 1;
27265181Sbrian            }
27362977Sbrian            estab = syn = finrst = -1;
27462977Sbrian            sport = ntohs(0);
27562977Sbrian            break;
27649374Sbrian#endif
27765846Sbrian          case IPPROTO_ESP:
27865846Sbrian            cproto = P_ESP;
27965846Sbrian            estab = syn = finrst = -1;
28065846Sbrian            sport = ntohs(0);
28165846Sbrian            break;
28265846Sbrian          case IPPROTO_AH:
28365846Sbrian            cproto = P_AH;
28465846Sbrian            estab = syn = finrst = -1;
28565846Sbrian            sport = ntohs(0);
28665846Sbrian            break;
28775894Sbrian          case IPPROTO_IPIP:
28875894Sbrian            cproto = P_IPIP;
28975894Sbrian            sport = dport = 0;
29075894Sbrian            estab = syn = finrst = -1;
29175894Sbrian            break;
29262977Sbrian          case IPPROTO_UDP:
29362977Sbrian            cproto = P_UDP;
29465181Sbrian            if (datalen < 8) {	/* UDP header is 8 octets */
29575894Sbrian              log_Printf(LogFILTER, " error: UDP/IPIP"
29675894Sbrian                         " must be at least 8 octets\n");
29762977Sbrian              return 1;
29865181Sbrian            }
29965181Sbrian
30062977Sbrian            uh = (const struct udphdr *) ptop;
30162977Sbrian            sport = ntohs(uh->uh_sport);
30262977Sbrian            dport = ntohs(uh->uh_dport);
30362977Sbrian            estab = syn = finrst = -1;
30462977Sbrian            if (log_IsKept(LogDEBUG))
30562977Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
30662977Sbrian                       sport, dport);
30762977Sbrian            break;
30862977Sbrian          case IPPROTO_TCP:
30962977Sbrian            cproto = P_TCP;
31062977Sbrian            th = (const struct tcphdr *) ptop;
31162977Sbrian            /* TCP headers are variable length.  The following code
31262977Sbrian             * ensures that the TCP header length isn't de-referenced if
31362977Sbrian             * the datagram is too short
31462977Sbrian             */
31565181Sbrian            if (datalen < 20 || datalen < (th->th_off << 2)) {
31665181Sbrian              log_Printf(LogFILTER, " error: TCP header incorrect\n");
31762977Sbrian              return 1;
31865181Sbrian            }
31962977Sbrian            sport = ntohs(th->th_sport);
32062977Sbrian            dport = ntohs(th->th_dport);
32162977Sbrian            estab = (th->th_flags & TH_ACK);
32262977Sbrian            syn = (th->th_flags & TH_SYN);
32362977Sbrian            finrst = (th->th_flags & (TH_FIN|TH_RST));
32462977Sbrian            if (log_IsKept(LogDEBUG)) {
32562977Sbrian              if (!estab)
32662977Sbrian                snprintf(dbuff, sizeof dbuff,
32762977Sbrian                         "flags = %02x, sport = %d, dport = %d",
32862977Sbrian                         th->th_flags, sport, dport);
32962977Sbrian              else
33062977Sbrian                *dbuff = '\0';
33162977Sbrian            }
33262977Sbrian            break;
33362977Sbrian          default:
33465181Sbrian            log_Printf(LogFILTER, " error: unknown protocol\n");
33562977Sbrian            return 1;		/* We'll block unknown type of packet */
33662977Sbrian          }
33726516Sbrian
33862977Sbrian          if (log_IsKept(LogDEBUG)) {
33962977Sbrian            if (estab != -1) {
34062977Sbrian              len = strlen(dbuff);
34162977Sbrian              snprintf(dbuff + len, sizeof dbuff - len,
34262977Sbrian                       ", estab = %d, syn = %d, finrst = %d",
34362977Sbrian                       estab, syn, finrst);
34462977Sbrian            }
34562977Sbrian            log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
34662977Sbrian                       filter_Proto2Nam(cproto), dbuff);
34762977Sbrian          }
34862977Sbrian          gotinfo = 1;
34962977Sbrian        }
35062977Sbrian        if (log_IsKept(LogDEBUG)) {
35162977Sbrian          if (fp->f_srcop != OP_NONE) {
35262977Sbrian            snprintf(dbuff, sizeof dbuff, ", src %s %d",
35362977Sbrian                     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
35462977Sbrian            len = strlen(dbuff);
35562977Sbrian          } else
35662977Sbrian            len = 0;
35762977Sbrian          if (fp->f_dstop != OP_NONE) {
35862977Sbrian            snprintf(dbuff + len, sizeof dbuff - len,
35962977Sbrian                     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
36062977Sbrian                     fp->f_dstport);
36162977Sbrian          } else if (!len)
36262977Sbrian            *dbuff = '\0';
36349140Sbrian
36462977Sbrian          log_Printf(LogDEBUG, "  rule = %d: Address match, "
36562977Sbrian                     "check against proto %s%s, action = %s\n",
36662977Sbrian                     n, filter_Proto2Nam(fp->f_proto),
36762977Sbrian                     dbuff, filter_Action2Nam(fp->f_action));
36862977Sbrian        }
36949140Sbrian
37062977Sbrian        if (cproto == fp->f_proto) {
37162977Sbrian          if ((fp->f_srcop == OP_NONE ||
37262977Sbrian               PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
37362977Sbrian              (fp->f_dstop == OP_NONE ||
37462977Sbrian               PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
37562977Sbrian              (fp->f_estab == 0 || estab) &&
37662977Sbrian              (fp->f_syn == 0 || syn) &&
37762977Sbrian              (fp->f_finrst == 0 || finrst)) {
37862977Sbrian            match = 1;
37962977Sbrian          }
38062977Sbrian        }
38149140Sbrian      } else {
38262977Sbrian        /* Address is matched and no protocol specified. Make a decision. */
38362977Sbrian        log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
38462977Sbrian                   filter_Action2Nam(fp->f_action));
38562977Sbrian        match = 1;
3866059Samurai      }
38749140Sbrian    } else
38849140Sbrian      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
38949140Sbrian
39049140Sbrian    if (match != fp->f_invert) {
39149140Sbrian      /* Take specified action */
39249140Sbrian      if (fp->f_action < A_NONE)
39362977Sbrian        fp = &filter->rule[n = fp->f_action];
39465181Sbrian      else {
39562977Sbrian        if (fp->f_action == A_PERMIT) {
39662977Sbrian          if (psecs != NULL)
39762977Sbrian            *psecs = fp->timeout;
39865181Sbrian          if (strcmp(filter->name, "DIAL") == 0) {
39965181Sbrian            /* If dial filter then even print out accept packets */
40065181Sbrian            if (log_IsKept(LogFILTER)) {
40165181Sbrian              snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
40265181Sbrian              log_Printf(LogFILTER, "%sbound rule = %d accept %s "
40365181Sbrian                         "src = %s/%d dst = %s/%d\n",
40465181Sbrian                         filter->name, n, filter_Proto2Nam(cproto),
40565181Sbrian                         inet_ntoa(pip->ip_src), sport, dstip, dport);
40665181Sbrian            }
40765181Sbrian          }
40862977Sbrian          return 0;
40965181Sbrian        } else {
41065181Sbrian          if (log_IsKept(LogFILTER)) {
41165181Sbrian            snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
41265181Sbrian            log_Printf(LogFILTER,
41365181Sbrian                       "%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n",
41465181Sbrian                       filter->name, n, filter_Proto2Nam(cproto),
41565181Sbrian                       inet_ntoa(pip->ip_src), sport, dstip, dport);
41665181Sbrian          }
41765181Sbrian          return 1;
41865181Sbrian        }		/* Explict math.  Deny this packet */
41965181Sbrian      }
42049140Sbrian    } else {
42149140Sbrian      n++;
4226059Samurai      fp++;
4236059Samurai    }
4246059Samurai  }
42565181Sbrian
42665181Sbrian  if (log_IsKept(LogFILTER)) {
42765181Sbrian    snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
42865181Sbrian    log_Printf(LogFILTER,
42965181Sbrian               "%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n",
43065181Sbrian               filter->name, filter_Proto2Nam(cproto),
43165181Sbrian               inet_ntoa(pip->ip_src), sport, dstip, dport);
43265181Sbrian  }
43365181Sbrian
43462977Sbrian  return 1;		/* No rule is mached. Deny this packet */
4356059Samurai}
4366059Samurai
43736285Sbrian#ifdef notdef
4386059Samuraistatic void
43946828SbrianIcmpError(struct ip *pip, int code)
4406059Samurai{
4416059Samurai  struct mbuf *bp;
4426059Samurai
4436059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
44454912Sbrian    bp = m_get(m_len, MB_IPIN);
44554912Sbrian    memcpy(MBUF_CTOP(bp), ptr, m_len);
44636285Sbrian    vj_SendFrame(bp);
44754912Sbrian    ipcp_AddOutOctets(m_len);
4486059Samurai  }
44936285Sbrian}
4506059Samurai#endif
4516059Samurai
45258033Sbrianstatic void
45358033Sbrianip_LogDNS(const struct udphdr *uh, const char *direction)
45458033Sbrian{
45558033Sbrian  struct dns_header header;
45658033Sbrian  const u_short *pktptr;
45758033Sbrian  const u_char *ptr;
45877487Sbrian  u_short *hptr, tmp;
45958033Sbrian  int len;
46058033Sbrian
46158033Sbrian  ptr = (const char *)uh + sizeof *uh;
46258033Sbrian  len = ntohs(uh->uh_ulen) - sizeof *uh;
46358033Sbrian  if (len < sizeof header + 5)		/* rfc1024 */
46458033Sbrian    return;
46558033Sbrian
46658033Sbrian  pktptr = (const u_short *)ptr;
46758033Sbrian  hptr = (u_short *)&header;
46858033Sbrian  ptr += sizeof header;
46958033Sbrian  len -= sizeof header;
47058033Sbrian
47158033Sbrian  while (pktptr < (const u_short *)ptr) {
47262977Sbrian    *hptr++ = ntohs(*pktptr);		/* Careful of macro side-effects ! */
47358033Sbrian    pktptr++;
47458033Sbrian  }
47558033Sbrian
47658033Sbrian  if (header.opcode == OPCODE_QUERY && header.qr == 0) {
47758033Sbrian    /* rfc1035 */
47874049Sbrian    char namewithdot[MAXHOSTNAMELEN + 1], *n;
47958033Sbrian    const char *qtype, *qclass;
48058033Sbrian    const u_char *end;
48158033Sbrian
48274049Sbrian    n = namewithdot;
48358033Sbrian    end = ptr + len - 4;
48474049Sbrian    if (end - ptr >= sizeof namewithdot)
48574049Sbrian      end = ptr + sizeof namewithdot - 1;
48658033Sbrian    while (ptr < end) {
48758033Sbrian      len = *ptr++;
48858033Sbrian      if (len > end - ptr)
48958033Sbrian        len = end - ptr;
49074049Sbrian      if (n != namewithdot)
49158033Sbrian        *n++ = '.';
49258033Sbrian      memcpy(n, ptr, len);
49358033Sbrian      ptr += len;
49458033Sbrian      n += len;
49558033Sbrian    }
49658033Sbrian    *n = '\0';
49758033Sbrian
49877487Sbrian    if (log_IsKept(LogDNS)) {
49977487Sbrian      memcpy(&tmp, end, sizeof tmp);
50077487Sbrian      qtype = dns_Qtype2Txt(ntohs(tmp));
50177487Sbrian      memcpy(&tmp, end + 2, sizeof tmp);
50277487Sbrian      qclass = dns_Qclass2Txt(ntohs(tmp));
50377487Sbrian
50477487Sbrian      log_Printf(LogDNS, "%sbound query %s %s %s\n",
50577487Sbrian                 direction, qclass, qtype, namewithdot);
50677487Sbrian    }
50758033Sbrian  }
50858033Sbrian}
50958033Sbrian
5106059Samurai/*
5116059Samurai *  For debugging aid.
5126059Samurai */
5136059Samuraiint
51462778SbrianPacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
51562977Sbrian            struct filter *filter, const char *prefix, unsigned *psecs)
5166059Samurai{
51758033Sbrian  static const char *const TcpFlags[] = {
51858033Sbrian    "FIN", "SYN", "RST", "PSH", "ACK", "URG"
51958033Sbrian  };
5206059Samurai  struct ip *pip;
5216059Samurai  struct tcphdr *th;
5226059Samurai  struct udphdr *uh;
5236059Samurai  struct icmp *icmph;
52462778Sbrian  unsigned char *ptop;
52558033Sbrian  int mask, len, n, pri, logit, loglen, result;
52637010Sbrian  char logbuf[200];
5276059Samurai
52858776Sbrian  logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
52958776Sbrian          (!filter || filter->logok);
53026692Sbrian  loglen = 0;
53158033Sbrian  pri = 0;
5326059Samurai
53358033Sbrian  pip = (struct ip *)cp;
53458033Sbrian  uh = NULL;
5358857Srgrimes
53626692Sbrian  if (logit && loglen < sizeof logbuf) {
53762778Sbrian    if (prefix)
53862778Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", prefix);
53962778Sbrian    else if (filter)
54058776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
54158776Sbrian    else
54258776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "  ");
54328679Sbrian    loglen += strlen(logbuf + loglen);
54426692Sbrian  }
5456059Samurai  ptop = (cp + (pip->ip_hl << 2));
5466059Samurai
5476059Samurai  switch (pip->ip_p) {
5486059Samurai  case IPPROTO_ICMP:
54926692Sbrian    if (logit && loglen < sizeof logbuf) {
55062778Sbrian      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - sizeof *icmph;
55128679Sbrian      icmph = (struct icmp *) ptop;
55228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
55362977Sbrian               "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
55428679Sbrian      loglen += strlen(logbuf + loglen);
55528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
55662977Sbrian               "%s:%d (%d/%d)", inet_ntoa(pip->ip_dst), icmph->icmp_type,
55762778Sbrian               len, nb);
55828679Sbrian      loglen += strlen(logbuf + loglen);
5596059Samurai    }
5606059Samurai    break;
56151048Sbrian
5626059Samurai  case IPPROTO_UDP:
56351048Sbrian    uh = (struct udphdr *) ptop;
56461430Sbrian    if (pip->ip_tos == IPTOS_LOWDELAY && bundle->ncp.ipcp.cfg.urgent.tos)
56551048Sbrian      pri++;
56651048Sbrian
56751048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
56851048Sbrian        ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
56951048Sbrian                          ntohs(uh->uh_dport)))
57051048Sbrian      pri++;
57151048Sbrian
57226692Sbrian    if (logit && loglen < sizeof logbuf) {
57362778Sbrian      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - sizeof *uh;
57428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
57562977Sbrian               "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
57628679Sbrian      loglen += strlen(logbuf + loglen);
57728679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
57862977Sbrian               "%s:%d (%d/%d)", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport),
57962977Sbrian               len, nb);
58028679Sbrian      loglen += strlen(logbuf + loglen);
5816059Samurai    }
58262778Sbrian
58362778Sbrian    if (Enabled(bundle, OPT_FILTERDECAP) &&
58462778Sbrian        ptop[sizeof *uh] == HDLC_ADDR && ptop[sizeof *uh + 1] == HDLC_UI) {
58562778Sbrian      u_short proto;
58662778Sbrian      const char *type;
58762778Sbrian
58862778Sbrian      memcpy(&proto, ptop + sizeof *uh + 2, sizeof proto);
58962778Sbrian      type = NULL;
59062778Sbrian
59162778Sbrian      switch (ntohs(proto)) {
59262778Sbrian        case PROTO_IP:
59362778Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
59462778Sbrian          result = PacketCheck(bundle, ptop + sizeof *uh + 4,
59562778Sbrian                               nb - (ptop - cp) - sizeof *uh - 4, filter,
59662977Sbrian                               logbuf, psecs);
59762778Sbrian          if (result != -2)
59862778Sbrian              return result;
59962778Sbrian          type = "IP";
60062778Sbrian          break;
60162778Sbrian
60262778Sbrian        case PROTO_VJUNCOMP: type = "compressed VJ";   break;
60362778Sbrian        case PROTO_VJCOMP:   type = "uncompressed VJ"; break;
60462778Sbrian        case PROTO_MP:       type = "Multi-link"; break;
60562778Sbrian        case PROTO_ICOMPD:   type = "Individual link CCP"; break;
60662778Sbrian        case PROTO_COMPD:    type = "CCP"; break;
60762778Sbrian        case PROTO_IPCP:     type = "IPCP"; break;
60862778Sbrian        case PROTO_LCP:      type = "LCP"; break;
60962778Sbrian        case PROTO_PAP:      type = "PAP"; break;
61062778Sbrian        case PROTO_CBCP:     type = "CBCP"; break;
61162778Sbrian        case PROTO_LQR:      type = "LQR"; break;
61262778Sbrian        case PROTO_CHAP:     type = "CHAP"; break;
61362778Sbrian      }
61462778Sbrian      if (type) {
61562778Sbrian        snprintf(logbuf + loglen, sizeof logbuf - loglen,
61662778Sbrian                 " - %s data", type);
61762778Sbrian        loglen += strlen(logbuf + loglen);
61862778Sbrian      }
61962778Sbrian    }
62062778Sbrian
6216059Samurai    break;
62251048Sbrian
62351809Sbrian#ifdef IPPROTO_GRE
62451809Sbrian  case IPPROTO_GRE:
62551809Sbrian    if (logit && loglen < sizeof logbuf) {
62662778Sbrian      len = ntohs(pip->ip_len) - (pip->ip_hl << 2);
62751809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
62851809Sbrian          "GRE: %s ---> ", inet_ntoa(pip->ip_src));
62951809Sbrian      loglen += strlen(logbuf + loglen);
63051809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
63162778Sbrian              "%s (%d/%d)", inet_ntoa(pip->ip_dst), len, nb);
63251809Sbrian      loglen += strlen(logbuf + loglen);
63351809Sbrian    }
63451809Sbrian    break;
63551809Sbrian#endif
63651809Sbrian
63749374Sbrian#ifdef IPPROTO_OSPFIGP
63849372Sbrian  case IPPROTO_OSPFIGP:
63949372Sbrian    if (logit && loglen < sizeof logbuf) {
64062778Sbrian      len = ntohs(pip->ip_len) - (pip->ip_hl << 2);
64149372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
64262977Sbrian               "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
64349372Sbrian      loglen += strlen(logbuf + loglen);
64449372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
64562977Sbrian               "%s (%d/%d)", inet_ntoa(pip->ip_dst), len, nb);
64649372Sbrian      loglen += strlen(logbuf + loglen);
64749372Sbrian    }
64849372Sbrian    break;
64949374Sbrian#endif
65051048Sbrian
65136961Sbrian  case IPPROTO_IPIP:
65236961Sbrian    if (logit && loglen < sizeof logbuf) {
65336961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
65475894Sbrian               "IPIP: %s ---> ", inet_ntoa(pip->ip_src));
65536961Sbrian      loglen += strlen(logbuf + loglen);
65636961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
65775894Sbrian               "%s", inet_ntoa(pip->ip_dst));
65836961Sbrian      loglen += strlen(logbuf + loglen);
65975894Sbrian
66075894Sbrian      if (((struct ip *)ptop)->ip_v == 4) {
66175894Sbrian        snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
66275894Sbrian        result = PacketCheck(bundle, ptop, nb - (ptop - cp), filter,
66375894Sbrian                             logbuf, psecs);
66475894Sbrian        if (result != -2)
66575894Sbrian          return result;
66675894Sbrian      }
66736961Sbrian    }
66836961Sbrian    break;
66951048Sbrian
67065846Sbrian  case IPPROTO_ESP:
67165846Sbrian    if (logit && loglen < sizeof logbuf) {
67265846Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
67365846Sbrian               "ESP: %s ---> ", inet_ntoa(pip->ip_src));
67465846Sbrian      loglen += strlen(logbuf + loglen);
67571781Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
67671781Sbrian               inet_ntoa(pip->ip_dst), ptop);
67765846Sbrian      loglen += strlen(logbuf + loglen);
67865846Sbrian    }
67965846Sbrian    break;
68065846Sbrian
68165846Sbrian  case IPPROTO_AH:
68265846Sbrian    if (logit && loglen < sizeof logbuf) {
68365846Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
68465846Sbrian               "AH: %s ---> ", inet_ntoa(pip->ip_src));
68565846Sbrian      loglen += strlen(logbuf + loglen);
68671781Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
68771781Sbrian               inet_ntoa(pip->ip_dst), ptop + sizeof(u_int32_t));
68865846Sbrian      loglen += strlen(logbuf + loglen);
68965846Sbrian    }
69065846Sbrian    break;
69165846Sbrian
69236961Sbrian  case IPPROTO_IGMP:
69336961Sbrian    if (logit && loglen < sizeof logbuf) {
69436961Sbrian      uh = (struct udphdr *) ptop;
69536961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
69662977Sbrian               "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src),
69762977Sbrian               ntohs(uh->uh_sport));
69836961Sbrian      loglen += strlen(logbuf + loglen);
69936961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
70062977Sbrian               "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
70136961Sbrian      loglen += strlen(logbuf + loglen);
70236961Sbrian    }
70336961Sbrian    break;
70451048Sbrian
7056059Samurai  case IPPROTO_TCP:
70628679Sbrian    th = (struct tcphdr *) ptop;
70761430Sbrian    if (pip->ip_tos == IPTOS_LOWDELAY && bundle->ncp.ipcp.cfg.urgent.tos)
70850867Sbrian      pri++;
70951048Sbrian
71051048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
71151048Sbrian        ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
71251048Sbrian                          ntohs(th->th_dport)))
71350867Sbrian      pri++;
71450867Sbrian
71526692Sbrian    if (logit && loglen < sizeof logbuf) {
7166059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
71728679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
71862977Sbrian           "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
71928679Sbrian      loglen += strlen(logbuf + loglen);
72028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
72162977Sbrian               "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
72228679Sbrian      loglen += strlen(logbuf + loglen);
7236059Samurai      n = 0;
7246059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
72562977Sbrian        if (th->th_flags & mask) {
72662977Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
72762977Sbrian          loglen += strlen(logbuf + loglen);
72862977Sbrian        }
72962977Sbrian        n++;
7306059Samurai      }
73128679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
73262977Sbrian               "  seq:%lx  ack:%lx (%d/%d)",
73362977Sbrian               (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
73428679Sbrian      loglen += strlen(logbuf + loglen);
7356059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
73662977Sbrian        u_short *sp;
7376059Samurai
73862977Sbrian        ptop += 20;
73962977Sbrian        sp = (u_short *) ptop;
74062977Sbrian        if (ntohs(sp[0]) == 0x0204) {
74162977Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen,
74262977Sbrian                   " MSS = %d", ntohs(sp[1]));
74362977Sbrian          loglen += strlen(logbuf + loglen);
74462977Sbrian        }
7456059Samurai      }
7466059Samurai    }
7476059Samurai    break;
74862778Sbrian
74962778Sbrian  default:
75062778Sbrian    if (prefix)
75162778Sbrian      return -2;
7526059Samurai  }
75326692Sbrian
75462977Sbrian  if (filter && FilterCheck(pip, filter, psecs)) {
75531142Sbrian    if (logit)
75636285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
75736285Sbrian#ifdef notdef
75828679Sbrian    if (direction == 0)
75928679Sbrian      IcmpError(pip, pri);
76036285Sbrian#endif
76158033Sbrian    result = -1;
7626059Samurai  } else {
76336285Sbrian    /* Check Keep Alive filter */
76458033Sbrian    if (logit && log_IsKept(LogTCPIP)) {
76562977Sbrian      unsigned alivesecs;
76662977Sbrian
76762977Sbrian      alivesecs = 0;
76862977Sbrian      if (filter && FilterCheck(pip, &bundle->filter.alive, &alivesecs))
76936285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
77062977Sbrian      else if (psecs != NULL) {
77162977Sbrian        if(*psecs == 0)
77262977Sbrian          *psecs = alivesecs;
77362977Sbrian        if (*psecs) {
77462977Sbrian          if (*psecs != alivesecs)
77562977Sbrian            log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n",
77662977Sbrian                       logbuf, *psecs, alivesecs);
77762977Sbrian          else
77862977Sbrian            log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs);
77962977Sbrian        } else
78062977Sbrian          log_Printf(LogTCPIP, "%s\n", logbuf);
78162977Sbrian      }
7826735Samurai    }
78358033Sbrian    result = pri;
7846059Samurai  }
78558033Sbrian
78658776Sbrian  if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
78758033Sbrian    ip_LogDNS(uh, filter->name);
78858033Sbrian
78958033Sbrian  return result;
7906059Samurai}
7916059Samurai
79246686Sbrianstruct mbuf *
79346686Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
79436285Sbrian{
7956059Samurai  int nb, nw;
79631343Sbrian  struct tun_data tun;
79746686Sbrian  struct ip *pip;
79856413Sbrian  char *data;
79962977Sbrian  unsigned secs, alivesecs;
8006059Samurai
80146686Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
80246686Sbrian    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
80354912Sbrian    m_freem(bp);
80446686Sbrian    return NULL;
8056059Samurai  }
8066059Samurai
80754912Sbrian  m_settype(bp, MB_IPIN);
80854912Sbrian  nb = m_length(bp);
80947168Sbrian  if (nb > sizeof tun.data) {
81047168Sbrian    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
81147168Sbrian               l->name, nb, (int)(sizeof tun.data));
81254912Sbrian    m_freem(bp);
81347168Sbrian    return NULL;
81447168Sbrian  }
81546686Sbrian  mbuf_Read(bp, tun.data, nb);
81626031Sbrian
81762977Sbrian  secs = 0;
81862977Sbrian  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in, NULL, &secs) < 0)
81946686Sbrian    return NULL;
82026031Sbrian
82146686Sbrian  pip = (struct ip *)tun.data;
82262977Sbrian  alivesecs = 0;
82362977Sbrian  if (!FilterCheck(pip, &bundle->filter.alive, &alivesecs)) {
82462977Sbrian    if (secs == 0)
82562977Sbrian      secs = alivesecs;
82662977Sbrian    bundle_StartIdleTimer(bundle, secs);
82762977Sbrian  }
82826031Sbrian
82946686Sbrian  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
83036285Sbrian
83156413Sbrian  if (bundle->dev.header) {
83262977Sbrian    tun.header.family = htonl(AF_INET);
83356413Sbrian    nb += sizeof tun - sizeof tun.data;
83456413Sbrian    data = (char *)&tun;
83556413Sbrian  } else
83656413Sbrian    data = tun.data;
83756413Sbrian
83856413Sbrian  nw = write(bundle->dev.fd, data, nb);
83946686Sbrian  if (nw != nb) {
84046686Sbrian    if (nw == -1)
84147168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
84247168Sbrian                 l->name, nb, strerror(errno));
84346686Sbrian    else
84447168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
84546686Sbrian  }
84636285Sbrian
84746686Sbrian  return NULL;
8486059Samurai}
8496059Samurai
8506059Samuraivoid
85138557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
8526059Samurai{
8536059Samurai  struct mbuf *bp;
8546059Samurai
85550867Sbrian  if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
85638557Sbrian    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
85738557Sbrian  else {
85846686Sbrian    /*
85946686Sbrian     * We allocate an extra 6 bytes, four at the front and two at the end.
86046686Sbrian     * This is an optimisation so that we need to do less work in
86154912Sbrian     * m_prepend() in acf_LayerPush() and proto_LayerPush() and
86246686Sbrian     * appending in hdlc_LayerPush().
86346686Sbrian     */
86454912Sbrian    bp = m_get(count + 6, MB_IPOUT);
86554912Sbrian    bp->m_offset += 4;
86654912Sbrian    bp->m_len -= 6;
86738557Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
86854912Sbrian    m_enqueue(ipcp->Queue + pri, bp);
86938557Sbrian  }
8706059Samurai}
8716059Samurai
87238544Sbrianvoid
87338557Sbrianip_DeleteQueue(struct ipcp *ipcp)
87438544Sbrian{
87538544Sbrian  struct mqueue *queue;
87638544Sbrian
87750867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
87838544Sbrian    while (queue->top)
87954912Sbrian      m_freem(m_dequeue(queue));
88038544Sbrian}
88138544Sbrian
88254912Sbriansize_t
88338557Sbrianip_QueueLen(struct ipcp *ipcp)
8847001Samurai{
8857001Samurai  struct mqueue *queue;
88654912Sbrian  size_t result;
88728679Sbrian
88854912Sbrian  result = 0;
88950867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
89054912Sbrian    result += queue->len;
89136285Sbrian
89236285Sbrian  return result;
8937001Samurai}
8947001Samurai
89536285Sbrianint
89646686Sbrianip_PushPacket(struct link *l, struct bundle *bundle)
8976059Samurai{
89838557Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
8996059Samurai  struct mqueue *queue;
9006059Samurai  struct mbuf *bp;
90146686Sbrian  struct ip *pip;
90254912Sbrian  int m_len;
90362977Sbrian  u_int32_t secs = 0;
90462977Sbrian  unsigned alivesecs = 0;
9056059Samurai
90638557Sbrian  if (ipcp->fsm.state != ST_OPENED)
90736285Sbrian    return 0;
90836285Sbrian
90950867Sbrian  queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
91050867Sbrian  do {
9116059Samurai    if (queue->top) {
91262977Sbrian      bp = m_dequeue(queue);
91362977Sbrian      bp = mbuf_Read(bp, &secs, sizeof secs);
91462977Sbrian      bp = m_pullup(bp);
91554912Sbrian      m_len = m_length(bp);
91646686Sbrian      pip = (struct ip *)MBUF_CTOP(bp);
91762977Sbrian      if (!FilterCheck(pip, &bundle->filter.alive, &alivesecs)) {
91862977Sbrian        if (secs == 0)
91962977Sbrian          secs = alivesecs;
92062977Sbrian        bundle_StartIdleTimer(bundle, secs);
92162977Sbrian      }
92250867Sbrian      link_PushPacket(l, bp, bundle, 0, PROTO_IP);
92354912Sbrian      ipcp_AddOutOctets(ipcp, m_len);
92446686Sbrian      return 1;
9256059Samurai    }
92650867Sbrian  } while (queue-- != ipcp->Queue);
92736285Sbrian
92836285Sbrian  return 0;
9296059Samurai}
930