ip.c revision 49374
16059Samurai/*
26059Samurai *		PPP IP Protocol Interface
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
198857Srgrimes *
2049374Sbrian * $Id: ip.c,v 1.66 1999/08/02 11:53:16 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Return ICMP message for filterd packet
246059Samurai *		  and optionaly record it into log.
256059Samurai */
2643313Sbrian#include <sys/param.h>
2746086Sbrian#if defined(__OpenBSD__) || defined(__NetBSD__)
2831195Sbrian#include <sys/socket.h>
2938174Sbrian#endif
3030715Sbrian#include <netinet/in.h>
316059Samurai#include <netinet/in_systm.h>
326059Samurai#include <netinet/ip.h>
336059Samurai#include <netinet/ip_icmp.h>
346059Samurai#include <netinet/udp.h>
356059Samurai#include <netinet/tcp.h>
3613389Sphk#include <arpa/inet.h>
3736285Sbrian#include <sys/un.h>
3830715Sbrian
3930092Sbrian#include <errno.h>
4030715Sbrian#include <stdio.h>
4130715Sbrian#include <stdlib.h>
4230715Sbrian#include <string.h>
4346686Sbrian#include <termios.h>
4430715Sbrian#include <unistd.h>
4530715Sbrian
4646686Sbrian#include "layer.h"
4746686Sbrian#include "proto.h"
4830715Sbrian#include "mbuf.h"
4930715Sbrian#include "log.h"
5030715Sbrian#include "defs.h"
5130715Sbrian#include "timer.h"
5230715Sbrian#include "fsm.h"
5336285Sbrian#include "lqr.h"
5430715Sbrian#include "hdlc.h"
5536285Sbrian#include "throughput.h"
5636285Sbrian#include "iplist.h"
5736285Sbrian#include "slcompress.h"
5836285Sbrian#include "ipcp.h"
596059Samurai#include "filter.h"
6036285Sbrian#include "descriptor.h"
6136285Sbrian#include "lcp.h"
6236285Sbrian#include "ccp.h"
6336285Sbrian#include "link.h"
6436285Sbrian#include "mp.h"
6543313Sbrian#ifndef NORADIUS
6643313Sbrian#include "radius.h"
6743313Sbrian#endif
6836285Sbrian#include "bundle.h"
6930715Sbrian#include "vjcomp.h"
7031195Sbrian#include "tun.h"
7130715Sbrian#include "ip.h"
726059Samurai
7331343Sbrianstatic const u_short interactive_ports[32] = {
7428679Sbrian  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7546223Sbrian  80, 81, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
766059Samurai};
776059Samurai
7813733Sdfr#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
796059Samurai
8031343Sbrianstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
816059Samurai
8249140Sbrianstatic __inline int
8328679SbrianPortMatch(int op, u_short pport, u_short rport)
846059Samurai{
856059Samurai  switch (op) {
8649140Sbrian  case OP_EQ:
8728679Sbrian    return (pport == rport);
886059Samurai  case OP_GT:
8928679Sbrian    return (pport > rport);
906059Samurai  case OP_LT:
9128679Sbrian    return (pport < rport);
926059Samurai  default:
9328679Sbrian    return (0);
946059Samurai  }
956059Samurai}
966059Samurai
976059Samurai/*
9846686Sbrian *  Check a packet against a defined filter
9949140Sbrian *  Returns 0 to accept the packet, non-zero to drop the packet
10049140Sbrian *
10149140Sbrian *  If filtering is enabled, the initial fragment of a datagram must
10249140Sbrian *  contain the complete protocol header, and subsequent fragments
10349140Sbrian *  must not attempt to over-write it.
1046059Samurai */
1056059Samuraistatic int
10649140SbrianFilterCheck(const struct ip *pip, const struct filter *filter)
1076059Samurai{
10849140Sbrian  int gotinfo;			/* true if IP payload decoded */
10949140Sbrian  int cproto;			/* P_* protocol type if (gotinfo) */
11049140Sbrian  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
11149140Sbrian  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
11249140Sbrian  int n;			/* filter rule to process */
11349140Sbrian  int len;			/* bytes used in dbuff */
11449140Sbrian  int didname;			/* true if filter header printed */
11549140Sbrian  int match;			/* true if condition matched */
11649140Sbrian  const struct filterent *fp = filter->rule;
11736285Sbrian  char dbuff[100];
1186059Samurai
11949140Sbrian  if (fp->f_action == A_NONE)
12049140Sbrian    return (0);		/* No rule is given. Permit this packet */
12136285Sbrian
12249140Sbrian  /* Deny any packet fragment that tries to over-write the header.
12349140Sbrian   * Since we no longer have the real header available, punt on the
12449140Sbrian   * largest normal header - 20 bytes for TCP without options, rounded
12549140Sbrian   * up to the next possible fragment boundary.  Since the smallest
12649140Sbrian   * `legal' MTU is 576, and the smallest recommended MTU is 296, any
12749140Sbrian   * fragmentation within this range is dubious at best */
12849140Sbrian  len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
12949140Sbrian  if (len > 0) {		/* Not first fragment within datagram */
13049140Sbrian    if (len < (24 >> 3))	/* don't allow fragment to over-write header */
13149140Sbrian      return (1);
13249140Sbrian    /* permit fragments on in and out filter */
13349140Sbrian    return (filter->fragok);
13449140Sbrian  }
13549140Sbrian
13649140Sbrian  cproto = gotinfo = estab = syn = finrst = didname = 0;
13749140Sbrian  sport = dport = 0;
13849140Sbrian  for (n = 0; n < MAXFILTERS; ) {
13949140Sbrian    if (fp->f_action == A_NONE) {
14049140Sbrian      n++;
14149140Sbrian      fp++;
14249140Sbrian      continue;
14349140Sbrian    }
14436285Sbrian
14549140Sbrian    if (!didname) {
14649140Sbrian      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
14749140Sbrian      didname = 1;
14849140Sbrian    }
1496059Samurai
15049140Sbrian    match = 0;
15149140Sbrian    if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
15249140Sbrian	  fp->f_src.mask.s_addr) &&
15349140Sbrian	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
15449140Sbrian	  fp->f_dst.mask.s_addr)) {
15549140Sbrian      if (fp->f_proto != P_NONE) {
15649140Sbrian	if (!gotinfo) {
15749140Sbrian	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
15849140Sbrian	  const struct tcphdr *th;
15949140Sbrian	  const struct udphdr *uh;
16049140Sbrian	  const struct icmp *ih;
16149140Sbrian	  int datalen;	/* IP datagram length */
16249140Sbrian
16349140Sbrian	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
16449140Sbrian	  switch (pip->ip_p) {
16549140Sbrian	  case IPPROTO_ICMP:
16649140Sbrian	    cproto = P_ICMP;
16749140Sbrian	    if (datalen < 8)	/* ICMP must be at least 8 octets */
16849140Sbrian	      return (1);
16949140Sbrian	    ih = (const struct icmp *) ptop;
17049140Sbrian	    sport = ih->icmp_type;
17149140Sbrian	    estab = syn = finrst = -1;
17249140Sbrian	    if (log_IsKept(LogDEBUG))
17349140Sbrian	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
17449140Sbrian	    break;
17549140Sbrian	  case IPPROTO_IGMP:
17649140Sbrian	    cproto = P_IGMP;
17749140Sbrian	    if (datalen < 8)	/* IGMP uses 8-octet messages */
17849140Sbrian	      return (1);
17949140Sbrian	    estab = syn = finrst = -1;
18049140Sbrian	    sport = ntohs(0);
18149140Sbrian	    break;
18249374Sbrian#ifdef IPPROTO_OSPFIGP
18349372Sbrian	  case IPPROTO_OSPFIGP:
18449372Sbrian	    cproto = P_OSPF;
18549372Sbrian	    if (datalen < 8)	/* IGMP uses 8-octet messages */
18649372Sbrian	      return (1);
18749372Sbrian	    estab = syn = finrst = -1;
18849372Sbrian	    sport = ntohs(0);
18949372Sbrian	    break;
19049374Sbrian#endif
19149140Sbrian	  case IPPROTO_UDP:
19249140Sbrian	  case IPPROTO_IPIP:
19349140Sbrian	    cproto = P_UDP;
19449140Sbrian	    if (datalen < 8)	/* UDP header is 8 octets */
19549140Sbrian	      return (1);
19649140Sbrian	    uh = (const struct udphdr *) ptop;
19749140Sbrian	    sport = ntohs(uh->uh_sport);
19849140Sbrian	    dport = ntohs(uh->uh_dport);
19949140Sbrian	    estab = syn = finrst = -1;
20049140Sbrian	    if (log_IsKept(LogDEBUG))
20149140Sbrian	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
20249140Sbrian		       sport, dport);
20349140Sbrian	    break;
20449140Sbrian	  case IPPROTO_TCP:
20549140Sbrian	    cproto = P_TCP;
20649140Sbrian	    th = (const struct tcphdr *) ptop;
20749140Sbrian	    /* TCP headers are variable length.  The following code
20849140Sbrian	     * ensures that the TCP header length isn't de-referenced if
20949140Sbrian	     * the datagram is too short
21049140Sbrian	     */
21149140Sbrian	    if (datalen < 20 || datalen < (th->th_off << 2))
21249140Sbrian	      return (1);
21349140Sbrian	    sport = ntohs(th->th_sport);
21449140Sbrian	    dport = ntohs(th->th_dport);
21549140Sbrian	    estab = (th->th_flags & TH_ACK);
21649140Sbrian	    syn = (th->th_flags & TH_SYN);
21749140Sbrian	    finrst = (th->th_flags & (TH_FIN|TH_RST));
21849140Sbrian	    if (log_IsKept(LogDEBUG)) {
21949140Sbrian	      if (!estab)
22049140Sbrian		snprintf(dbuff, sizeof dbuff,
22149140Sbrian			 "flags = %02x, sport = %d, dport = %d",
22249140Sbrian			 th->th_flags, sport, dport);
22349140Sbrian	      else
22449140Sbrian		*dbuff = '\0';
2256059Samurai	    }
22649140Sbrian	    break;
22749140Sbrian	  default:
22849140Sbrian	    return (1);	/* We'll block unknown type of packet */
22949140Sbrian	  }
23026516Sbrian
23149140Sbrian	  if (log_IsKept(LogDEBUG)) {
23249140Sbrian	    if (estab != -1) {
23349140Sbrian	      len = strlen(dbuff);
23449140Sbrian	      snprintf(dbuff + len, sizeof dbuff - len,
23549140Sbrian		       ", estab = %d, syn = %d, finrst = %d",
23649140Sbrian		       estab, syn, finrst);
2376059Samurai	    }
23849140Sbrian	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
23949140Sbrian		       filter_Proto2Nam(cproto), dbuff);
2406059Samurai	  }
24149140Sbrian	  gotinfo = 1;
24249140Sbrian	}
24349140Sbrian	if (log_IsKept(LogDEBUG)) {
24449140Sbrian	  if (fp->f_srcop != OP_NONE) {
24549140Sbrian	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
24649140Sbrian		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
24749140Sbrian	    len = strlen(dbuff);
24849140Sbrian	  } else
24949140Sbrian	    len = 0;
25049140Sbrian	  if (fp->f_dstop != OP_NONE) {
25149140Sbrian	    snprintf(dbuff + len, sizeof dbuff - len,
25249140Sbrian		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
25349140Sbrian		     fp->f_dstport);
25449140Sbrian	  } else if (!len)
25549140Sbrian	    *dbuff = '\0';
25649140Sbrian
25749140Sbrian	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
25849140Sbrian		     "check against proto %s%s, action = %s\n",
25949140Sbrian		     n, filter_Proto2Nam(fp->f_proto),
26049140Sbrian		     dbuff, filter_Action2Nam(fp->f_action));
26149140Sbrian	}
26249140Sbrian
26349140Sbrian	if (cproto == fp->f_proto) {
26449140Sbrian	  if ((fp->f_srcop == OP_NONE ||
26549140Sbrian	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
26649140Sbrian	      (fp->f_dstop == OP_NONE ||
26749140Sbrian	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
26849140Sbrian	      (fp->f_estab == 0 || estab) &&
26949140Sbrian	      (fp->f_syn == 0 || syn) &&
27049140Sbrian	      (fp->f_finrst == 0 || finrst)) {
27149140Sbrian	    match = 1;
27249140Sbrian	  }
27349140Sbrian	}
27449140Sbrian      } else {
27549140Sbrian	/* Address is matched and no protocol specified. Make a decision. */
27649140Sbrian	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
27749140Sbrian		   filter_Action2Nam(fp->f_action));
27849140Sbrian	match = 1;
2796059Samurai      }
28049140Sbrian    } else
28149140Sbrian      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
28249140Sbrian
28349140Sbrian    if (match != fp->f_invert) {
28449140Sbrian      /* Take specified action */
28549140Sbrian      if (fp->f_action < A_NONE)
28649140Sbrian	fp = &filter->rule[n = fp->f_action];
28749140Sbrian      else
28849140Sbrian	return (fp->f_action != A_PERMIT);
28949140Sbrian    } else {
29049140Sbrian      n++;
2916059Samurai      fp++;
2926059Samurai    }
2936059Samurai  }
29449140Sbrian  return (1);		/* No rule is mached. Deny this packet */
2956059Samurai}
2966059Samurai
29736285Sbrian#ifdef notdef
2986059Samuraistatic void
29946828SbrianIcmpError(struct ip *pip, int code)
3006059Samurai{
3016059Samurai  struct mbuf *bp;
3026059Samurai
3036059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
30436285Sbrian    bp = mbuf_Alloc(cnt, MB_IPIN);
30530715Sbrian    memcpy(MBUF_CTOP(bp), ptr, cnt);
30636285Sbrian    vj_SendFrame(bp);
30736285Sbrian    ipcp_AddOutOctets(cnt);
3086059Samurai  }
30936285Sbrian}
3106059Samurai#endif
3116059Samurai
3126059Samurai/*
3136059Samurai *  For debugging aid.
3146059Samurai */
3156059Samuraiint
31636285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
3176059Samurai{
3186059Samurai  struct ip *pip;
3196059Samurai  struct tcphdr *th;
3206059Samurai  struct udphdr *uh;
3216059Samurai  struct icmp *icmph;
3226059Samurai  char *ptop;
3236059Samurai  int mask, len, n;
3246059Samurai  int pri = PRI_NORMAL;
32526692Sbrian  int logit, loglen;
32637010Sbrian  char logbuf[200];
3276059Samurai
32836285Sbrian  logit = log_IsKept(LogTCPIP) && filter->logok;
32926692Sbrian  loglen = 0;
3306059Samurai
33128679Sbrian  pip = (struct ip *) cp;
3328857Srgrimes
33326692Sbrian  if (logit && loglen < sizeof logbuf) {
33436285Sbrian    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
33528679Sbrian    loglen += strlen(logbuf + loglen);
33626692Sbrian  }
3376059Samurai  ptop = (cp + (pip->ip_hl << 2));
3386059Samurai
3396059Samurai  switch (pip->ip_p) {
3406059Samurai  case IPPROTO_ICMP:
34126692Sbrian    if (logit && loglen < sizeof logbuf) {
34228679Sbrian      icmph = (struct icmp *) ptop;
34328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
34428679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
34528679Sbrian      loglen += strlen(logbuf + loglen);
34628679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
34728679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
34828679Sbrian      loglen += strlen(logbuf + loglen);
3496059Samurai    }
3506059Samurai    break;
3516059Samurai  case IPPROTO_UDP:
35226692Sbrian    if (logit && loglen < sizeof logbuf) {
35328679Sbrian      uh = (struct udphdr *) ptop;
35428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
35528679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
35628679Sbrian      loglen += strlen(logbuf + loglen);
35728679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
35828679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
35928679Sbrian      loglen += strlen(logbuf + loglen);
3606059Samurai    }
3616059Samurai    break;
36249374Sbrian#ifdef IPPROTO_OSPFIGP
36349372Sbrian  case IPPROTO_OSPFIGP:
36449372Sbrian    if (logit && loglen < sizeof logbuf) {
36549372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
36649372Sbrian	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
36749372Sbrian      loglen += strlen(logbuf + loglen);
36849372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
36949372Sbrian	       "%s", inet_ntoa(pip->ip_dst));
37049372Sbrian      loglen += strlen(logbuf + loglen);
37149372Sbrian    }
37249372Sbrian    break;
37349374Sbrian#endif
37436961Sbrian  case IPPROTO_IPIP:
37536961Sbrian    if (logit && loglen < sizeof logbuf) {
37636961Sbrian      uh = (struct udphdr *) ptop;
37736961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
37836961Sbrian	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
37936961Sbrian      loglen += strlen(logbuf + loglen);
38036961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
38136961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
38236961Sbrian      loglen += strlen(logbuf + loglen);
38336961Sbrian    }
38436961Sbrian    break;
38536961Sbrian  case IPPROTO_IGMP:
38636961Sbrian    if (logit && loglen < sizeof logbuf) {
38736961Sbrian      uh = (struct udphdr *) ptop;
38836961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
38936961Sbrian	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
39036961Sbrian      loglen += strlen(logbuf + loglen);
39136961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
39236961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
39336961Sbrian      loglen += strlen(logbuf + loglen);
39436961Sbrian    }
39536961Sbrian    break;
3966059Samurai  case IPPROTO_TCP:
39728679Sbrian    th = (struct tcphdr *) ptop;
3986059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
3996059Samurai      pri = PRI_FAST;
40013733Sdfr    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
4016059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
40228679Sbrian	pri = PRI_FAST;
4036059Samurai    }
40426692Sbrian    if (logit && loglen < sizeof logbuf) {
4056059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
40628679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
40728679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
40828679Sbrian      loglen += strlen(logbuf + loglen);
40928679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
41028679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
41128679Sbrian      loglen += strlen(logbuf + loglen);
4126059Samurai      n = 0;
4136059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
41426692Sbrian	if (th->th_flags & mask) {
41528679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
41628679Sbrian	  loglen += strlen(logbuf + loglen);
41728679Sbrian	}
4186059Samurai	n++;
4196059Samurai      }
42028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
42137210Sbrian	       "  seq:%lx  ack:%lx (%d/%d)",
42237210Sbrian	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
42328679Sbrian      loglen += strlen(logbuf + loglen);
4246059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
42528679Sbrian	u_short *sp;
4266059Samurai
4276059Samurai	ptop += 20;
42828679Sbrian	sp = (u_short *) ptop;
42926692Sbrian	if (ntohs(sp[0]) == 0x0204) {
43028679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
43128679Sbrian		   " MSS = %d", ntohs(sp[1]));
43228679Sbrian	  loglen += strlen(logbuf + loglen);
43328679Sbrian	}
4346059Samurai      }
4356059Samurai    }
4366059Samurai    break;
4376059Samurai  }
43826692Sbrian
43949140Sbrian  if (FilterCheck(pip, filter)) {
44031142Sbrian    if (logit)
44136285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
44236285Sbrian#ifdef notdef
44328679Sbrian    if (direction == 0)
44428679Sbrian      IcmpError(pip, pri);
44536285Sbrian#endif
44628679Sbrian    return (-1);
4476059Samurai  } else {
44836285Sbrian    /* Check Keep Alive filter */
44936285Sbrian    if (logit) {
45049140Sbrian      if (FilterCheck(pip, &bundle->filter.alive))
45136285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
45236285Sbrian      else
45336285Sbrian        log_Printf(LogTCPIP, "%s\n", logbuf);
4546735Samurai    }
45528679Sbrian    return (pri);
4566059Samurai  }
4576059Samurai}
4586059Samurai
45946686Sbrianstruct mbuf *
46046686Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
46136285Sbrian{
4626059Samurai  int nb, nw;
46331343Sbrian  struct tun_data tun;
46446686Sbrian  struct ip *pip;
4656059Samurai
46646686Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
46746686Sbrian    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
46846686Sbrian    mbuf_Free(bp);
46946686Sbrian    return NULL;
4706059Samurai  }
4716059Samurai
47247695Sbrian  mbuf_SetType(bp, MB_IPIN);
47346686Sbrian  tun_fill_header(tun, AF_INET);
47446686Sbrian  nb = mbuf_Length(bp);
47547168Sbrian  if (nb > sizeof tun.data) {
47647168Sbrian    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
47747168Sbrian               l->name, nb, (int)(sizeof tun.data));
47847168Sbrian    mbuf_Free(bp);
47947168Sbrian    return NULL;
48047168Sbrian  }
48146686Sbrian  mbuf_Read(bp, tun.data, nb);
48226031Sbrian
48346686Sbrian  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
48446686Sbrian    return NULL;
48526031Sbrian
48646686Sbrian  pip = (struct ip *)tun.data;
48749140Sbrian  if (!FilterCheck(pip, &bundle->filter.alive))
48846686Sbrian    bundle_StartIdleTimer(bundle);
48926031Sbrian
49046686Sbrian  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
49136285Sbrian
49246686Sbrian  nb += sizeof tun - sizeof tun.data;
49346686Sbrian  nw = write(bundle->dev.fd, &tun, nb);
49446686Sbrian  if (nw != nb) {
49546686Sbrian    if (nw == -1)
49647168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
49747168Sbrian                 l->name, nb, strerror(errno));
49846686Sbrian    else
49947168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
50046686Sbrian  }
50136285Sbrian
50246686Sbrian  return NULL;
5036059Samurai}
5046059Samurai
5056059Samuraivoid
50638557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
5076059Samurai{
5086059Samurai  struct mbuf *bp;
5096059Samurai
51038557Sbrian  if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0])
51138557Sbrian    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
51238557Sbrian  else {
51346686Sbrian    /*
51446686Sbrian     * We allocate an extra 6 bytes, four at the front and two at the end.
51546686Sbrian     * This is an optimisation so that we need to do less work in
51646686Sbrian     * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and
51746686Sbrian     * appending in hdlc_LayerPush().
51846686Sbrian     */
51947695Sbrian    bp = mbuf_Alloc(count + 6, MB_IPOUT);
52046686Sbrian    bp->offset += 4;
52146686Sbrian    bp->cnt -= 6;
52238557Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
52338557Sbrian    mbuf_Enqueue(&ipcp->Queue[pri], bp);
52438557Sbrian  }
5256059Samurai}
5266059Samurai
52738544Sbrianvoid
52838557Sbrianip_DeleteQueue(struct ipcp *ipcp)
52938544Sbrian{
53038544Sbrian  struct mqueue *queue;
53138544Sbrian
53238557Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
53338544Sbrian    while (queue->top)
53438544Sbrian      mbuf_Free(mbuf_Dequeue(queue));
53538544Sbrian}
53638544Sbrian
5378857Srgrimesint
53838557Sbrianip_QueueLen(struct ipcp *ipcp)
5397001Samurai{
5407001Samurai  struct mqueue *queue;
54136285Sbrian  int result = 0;
54228679Sbrian
54338557Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
54436285Sbrian    result += queue->qlen;
54536285Sbrian
54636285Sbrian  return result;
5477001Samurai}
5487001Samurai
54936285Sbrianint
55046686Sbrianip_PushPacket(struct link *l, struct bundle *bundle)
5516059Samurai{
55238557Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
5536059Samurai  struct mqueue *queue;
5546059Samurai  struct mbuf *bp;
55546686Sbrian  struct ip *pip;
55625630Sbrian  int cnt;
5576059Samurai
55838557Sbrian  if (ipcp->fsm.state != ST_OPENED)
55936285Sbrian    return 0;
56036285Sbrian
56138557Sbrian  for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--)
5626059Samurai    if (queue->top) {
56345103Sbrian      bp = mbuf_Contiguous(mbuf_Dequeue(queue));
56446686Sbrian      cnt = mbuf_Length(bp);
56546686Sbrian      pip = (struct ip *)MBUF_CTOP(bp);
56649140Sbrian      if (!FilterCheck(pip, &bundle->filter.alive))
56746686Sbrian        bundle_StartIdleTimer(bundle);
56846686Sbrian      link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP);
56946686Sbrian      ipcp_AddOutOctets(ipcp, cnt);
57046686Sbrian      return 1;
5716059Samurai    }
57236285Sbrian
57336285Sbrian  return 0;
5746059Samurai}
575