ip.c revision 49372
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 *
2049372Sbrian * $Id: ip.c,v 1.65 1999/07/27 23:43:59 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;
18249372Sbrian	  case IPPROTO_OSPFIGP:
18349372Sbrian	    cproto = P_OSPF;
18449372Sbrian	    if (datalen < 8)	/* IGMP uses 8-octet messages */
18549372Sbrian	      return (1);
18649372Sbrian	    estab = syn = finrst = -1;
18749372Sbrian	    sport = ntohs(0);
18849372Sbrian	    break;
18949140Sbrian	  case IPPROTO_UDP:
19049140Sbrian	  case IPPROTO_IPIP:
19149140Sbrian	    cproto = P_UDP;
19249140Sbrian	    if (datalen < 8)	/* UDP header is 8 octets */
19349140Sbrian	      return (1);
19449140Sbrian	    uh = (const struct udphdr *) ptop;
19549140Sbrian	    sport = ntohs(uh->uh_sport);
19649140Sbrian	    dport = ntohs(uh->uh_dport);
19749140Sbrian	    estab = syn = finrst = -1;
19849140Sbrian	    if (log_IsKept(LogDEBUG))
19949140Sbrian	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
20049140Sbrian		       sport, dport);
20149140Sbrian	    break;
20249140Sbrian	  case IPPROTO_TCP:
20349140Sbrian	    cproto = P_TCP;
20449140Sbrian	    th = (const struct tcphdr *) ptop;
20549140Sbrian	    /* TCP headers are variable length.  The following code
20649140Sbrian	     * ensures that the TCP header length isn't de-referenced if
20749140Sbrian	     * the datagram is too short
20849140Sbrian	     */
20949140Sbrian	    if (datalen < 20 || datalen < (th->th_off << 2))
21049140Sbrian	      return (1);
21149140Sbrian	    sport = ntohs(th->th_sport);
21249140Sbrian	    dport = ntohs(th->th_dport);
21349140Sbrian	    estab = (th->th_flags & TH_ACK);
21449140Sbrian	    syn = (th->th_flags & TH_SYN);
21549140Sbrian	    finrst = (th->th_flags & (TH_FIN|TH_RST));
21649140Sbrian	    if (log_IsKept(LogDEBUG)) {
21749140Sbrian	      if (!estab)
21849140Sbrian		snprintf(dbuff, sizeof dbuff,
21949140Sbrian			 "flags = %02x, sport = %d, dport = %d",
22049140Sbrian			 th->th_flags, sport, dport);
22149140Sbrian	      else
22249140Sbrian		*dbuff = '\0';
2236059Samurai	    }
22449140Sbrian	    break;
22549140Sbrian	  default:
22649140Sbrian	    return (1);	/* We'll block unknown type of packet */
22749140Sbrian	  }
22826516Sbrian
22949140Sbrian	  if (log_IsKept(LogDEBUG)) {
23049140Sbrian	    if (estab != -1) {
23149140Sbrian	      len = strlen(dbuff);
23249140Sbrian	      snprintf(dbuff + len, sizeof dbuff - len,
23349140Sbrian		       ", estab = %d, syn = %d, finrst = %d",
23449140Sbrian		       estab, syn, finrst);
2356059Samurai	    }
23649140Sbrian	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
23749140Sbrian		       filter_Proto2Nam(cproto), dbuff);
2386059Samurai	  }
23949140Sbrian	  gotinfo = 1;
24049140Sbrian	}
24149140Sbrian	if (log_IsKept(LogDEBUG)) {
24249140Sbrian	  if (fp->f_srcop != OP_NONE) {
24349140Sbrian	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
24449140Sbrian		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
24549140Sbrian	    len = strlen(dbuff);
24649140Sbrian	  } else
24749140Sbrian	    len = 0;
24849140Sbrian	  if (fp->f_dstop != OP_NONE) {
24949140Sbrian	    snprintf(dbuff + len, sizeof dbuff - len,
25049140Sbrian		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
25149140Sbrian		     fp->f_dstport);
25249140Sbrian	  } else if (!len)
25349140Sbrian	    *dbuff = '\0';
25449140Sbrian
25549140Sbrian	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
25649140Sbrian		     "check against proto %s%s, action = %s\n",
25749140Sbrian		     n, filter_Proto2Nam(fp->f_proto),
25849140Sbrian		     dbuff, filter_Action2Nam(fp->f_action));
25949140Sbrian	}
26049140Sbrian
26149140Sbrian	if (cproto == fp->f_proto) {
26249140Sbrian	  if ((fp->f_srcop == OP_NONE ||
26349140Sbrian	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
26449140Sbrian	      (fp->f_dstop == OP_NONE ||
26549140Sbrian	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
26649140Sbrian	      (fp->f_estab == 0 || estab) &&
26749140Sbrian	      (fp->f_syn == 0 || syn) &&
26849140Sbrian	      (fp->f_finrst == 0 || finrst)) {
26949140Sbrian	    match = 1;
27049140Sbrian	  }
27149140Sbrian	}
27249140Sbrian      } else {
27349140Sbrian	/* Address is matched and no protocol specified. Make a decision. */
27449140Sbrian	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
27549140Sbrian		   filter_Action2Nam(fp->f_action));
27649140Sbrian	match = 1;
2776059Samurai      }
27849140Sbrian    } else
27949140Sbrian      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
28049140Sbrian
28149140Sbrian    if (match != fp->f_invert) {
28249140Sbrian      /* Take specified action */
28349140Sbrian      if (fp->f_action < A_NONE)
28449140Sbrian	fp = &filter->rule[n = fp->f_action];
28549140Sbrian      else
28649140Sbrian	return (fp->f_action != A_PERMIT);
28749140Sbrian    } else {
28849140Sbrian      n++;
2896059Samurai      fp++;
2906059Samurai    }
2916059Samurai  }
29249140Sbrian  return (1);		/* No rule is mached. Deny this packet */
2936059Samurai}
2946059Samurai
29536285Sbrian#ifdef notdef
2966059Samuraistatic void
29746828SbrianIcmpError(struct ip *pip, int code)
2986059Samurai{
2996059Samurai  struct mbuf *bp;
3006059Samurai
3016059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
30236285Sbrian    bp = mbuf_Alloc(cnt, MB_IPIN);
30330715Sbrian    memcpy(MBUF_CTOP(bp), ptr, cnt);
30436285Sbrian    vj_SendFrame(bp);
30536285Sbrian    ipcp_AddOutOctets(cnt);
3066059Samurai  }
30736285Sbrian}
3086059Samurai#endif
3096059Samurai
3106059Samurai/*
3116059Samurai *  For debugging aid.
3126059Samurai */
3136059Samuraiint
31436285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
3156059Samurai{
3166059Samurai  struct ip *pip;
3176059Samurai  struct tcphdr *th;
3186059Samurai  struct udphdr *uh;
3196059Samurai  struct icmp *icmph;
3206059Samurai  char *ptop;
3216059Samurai  int mask, len, n;
3226059Samurai  int pri = PRI_NORMAL;
32326692Sbrian  int logit, loglen;
32437010Sbrian  char logbuf[200];
3256059Samurai
32636285Sbrian  logit = log_IsKept(LogTCPIP) && filter->logok;
32726692Sbrian  loglen = 0;
3286059Samurai
32928679Sbrian  pip = (struct ip *) cp;
3308857Srgrimes
33126692Sbrian  if (logit && loglen < sizeof logbuf) {
33236285Sbrian    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
33328679Sbrian    loglen += strlen(logbuf + loglen);
33426692Sbrian  }
3356059Samurai  ptop = (cp + (pip->ip_hl << 2));
3366059Samurai
3376059Samurai  switch (pip->ip_p) {
3386059Samurai  case IPPROTO_ICMP:
33926692Sbrian    if (logit && loglen < sizeof logbuf) {
34028679Sbrian      icmph = (struct icmp *) ptop;
34128679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
34228679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
34328679Sbrian      loglen += strlen(logbuf + loglen);
34428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
34528679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
34628679Sbrian      loglen += strlen(logbuf + loglen);
3476059Samurai    }
3486059Samurai    break;
3496059Samurai  case IPPROTO_UDP:
35026692Sbrian    if (logit && loglen < sizeof logbuf) {
35128679Sbrian      uh = (struct udphdr *) ptop;
35228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
35328679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
35428679Sbrian      loglen += strlen(logbuf + loglen);
35528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
35628679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
35728679Sbrian      loglen += strlen(logbuf + loglen);
3586059Samurai    }
3596059Samurai    break;
36049372Sbrian  case IPPROTO_OSPFIGP:
36149372Sbrian    if (logit && loglen < sizeof logbuf) {
36249372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
36349372Sbrian	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
36449372Sbrian      loglen += strlen(logbuf + loglen);
36549372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
36649372Sbrian	       "%s", inet_ntoa(pip->ip_dst));
36749372Sbrian      loglen += strlen(logbuf + loglen);
36849372Sbrian    }
36949372Sbrian    break;
37036961Sbrian  case IPPROTO_IPIP:
37136961Sbrian    if (logit && loglen < sizeof logbuf) {
37236961Sbrian      uh = (struct udphdr *) ptop;
37336961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
37436961Sbrian	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
37536961Sbrian      loglen += strlen(logbuf + loglen);
37636961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
37736961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
37836961Sbrian      loglen += strlen(logbuf + loglen);
37936961Sbrian    }
38036961Sbrian    break;
38136961Sbrian  case IPPROTO_IGMP:
38236961Sbrian    if (logit && loglen < sizeof logbuf) {
38336961Sbrian      uh = (struct udphdr *) ptop;
38436961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
38536961Sbrian	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
38636961Sbrian      loglen += strlen(logbuf + loglen);
38736961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
38836961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
38936961Sbrian      loglen += strlen(logbuf + loglen);
39036961Sbrian    }
39136961Sbrian    break;
3926059Samurai  case IPPROTO_TCP:
39328679Sbrian    th = (struct tcphdr *) ptop;
3946059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
3956059Samurai      pri = PRI_FAST;
39613733Sdfr    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
3976059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
39828679Sbrian	pri = PRI_FAST;
3996059Samurai    }
40026692Sbrian    if (logit && loglen < sizeof logbuf) {
4016059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
40228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
40328679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
40428679Sbrian      loglen += strlen(logbuf + loglen);
40528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
40628679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
40728679Sbrian      loglen += strlen(logbuf + loglen);
4086059Samurai      n = 0;
4096059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
41026692Sbrian	if (th->th_flags & mask) {
41128679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
41228679Sbrian	  loglen += strlen(logbuf + loglen);
41328679Sbrian	}
4146059Samurai	n++;
4156059Samurai      }
41628679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
41737210Sbrian	       "  seq:%lx  ack:%lx (%d/%d)",
41837210Sbrian	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
41928679Sbrian      loglen += strlen(logbuf + loglen);
4206059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
42128679Sbrian	u_short *sp;
4226059Samurai
4236059Samurai	ptop += 20;
42428679Sbrian	sp = (u_short *) ptop;
42526692Sbrian	if (ntohs(sp[0]) == 0x0204) {
42628679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
42728679Sbrian		   " MSS = %d", ntohs(sp[1]));
42828679Sbrian	  loglen += strlen(logbuf + loglen);
42928679Sbrian	}
4306059Samurai      }
4316059Samurai    }
4326059Samurai    break;
4336059Samurai  }
43426692Sbrian
43549140Sbrian  if (FilterCheck(pip, filter)) {
43631142Sbrian    if (logit)
43736285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
43836285Sbrian#ifdef notdef
43928679Sbrian    if (direction == 0)
44028679Sbrian      IcmpError(pip, pri);
44136285Sbrian#endif
44228679Sbrian    return (-1);
4436059Samurai  } else {
44436285Sbrian    /* Check Keep Alive filter */
44536285Sbrian    if (logit) {
44649140Sbrian      if (FilterCheck(pip, &bundle->filter.alive))
44736285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
44836285Sbrian      else
44936285Sbrian        log_Printf(LogTCPIP, "%s\n", logbuf);
4506735Samurai    }
45128679Sbrian    return (pri);
4526059Samurai  }
4536059Samurai}
4546059Samurai
45546686Sbrianstruct mbuf *
45646686Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
45736285Sbrian{
4586059Samurai  int nb, nw;
45931343Sbrian  struct tun_data tun;
46046686Sbrian  struct ip *pip;
4616059Samurai
46246686Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
46346686Sbrian    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
46446686Sbrian    mbuf_Free(bp);
46546686Sbrian    return NULL;
4666059Samurai  }
4676059Samurai
46847695Sbrian  mbuf_SetType(bp, MB_IPIN);
46946686Sbrian  tun_fill_header(tun, AF_INET);
47046686Sbrian  nb = mbuf_Length(bp);
47147168Sbrian  if (nb > sizeof tun.data) {
47247168Sbrian    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
47347168Sbrian               l->name, nb, (int)(sizeof tun.data));
47447168Sbrian    mbuf_Free(bp);
47547168Sbrian    return NULL;
47647168Sbrian  }
47746686Sbrian  mbuf_Read(bp, tun.data, nb);
47826031Sbrian
47946686Sbrian  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
48046686Sbrian    return NULL;
48126031Sbrian
48246686Sbrian  pip = (struct ip *)tun.data;
48349140Sbrian  if (!FilterCheck(pip, &bundle->filter.alive))
48446686Sbrian    bundle_StartIdleTimer(bundle);
48526031Sbrian
48646686Sbrian  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
48736285Sbrian
48846686Sbrian  nb += sizeof tun - sizeof tun.data;
48946686Sbrian  nw = write(bundle->dev.fd, &tun, nb);
49046686Sbrian  if (nw != nb) {
49146686Sbrian    if (nw == -1)
49247168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
49347168Sbrian                 l->name, nb, strerror(errno));
49446686Sbrian    else
49547168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
49646686Sbrian  }
49736285Sbrian
49846686Sbrian  return NULL;
4996059Samurai}
5006059Samurai
5016059Samuraivoid
50238557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
5036059Samurai{
5046059Samurai  struct mbuf *bp;
5056059Samurai
50638557Sbrian  if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0])
50738557Sbrian    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
50838557Sbrian  else {
50946686Sbrian    /*
51046686Sbrian     * We allocate an extra 6 bytes, four at the front and two at the end.
51146686Sbrian     * This is an optimisation so that we need to do less work in
51246686Sbrian     * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and
51346686Sbrian     * appending in hdlc_LayerPush().
51446686Sbrian     */
51547695Sbrian    bp = mbuf_Alloc(count + 6, MB_IPOUT);
51646686Sbrian    bp->offset += 4;
51746686Sbrian    bp->cnt -= 6;
51838557Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
51938557Sbrian    mbuf_Enqueue(&ipcp->Queue[pri], bp);
52038557Sbrian  }
5216059Samurai}
5226059Samurai
52338544Sbrianvoid
52438557Sbrianip_DeleteQueue(struct ipcp *ipcp)
52538544Sbrian{
52638544Sbrian  struct mqueue *queue;
52738544Sbrian
52838557Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
52938544Sbrian    while (queue->top)
53038544Sbrian      mbuf_Free(mbuf_Dequeue(queue));
53138544Sbrian}
53238544Sbrian
5338857Srgrimesint
53438557Sbrianip_QueueLen(struct ipcp *ipcp)
5357001Samurai{
5367001Samurai  struct mqueue *queue;
53736285Sbrian  int result = 0;
53828679Sbrian
53938557Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
54036285Sbrian    result += queue->qlen;
54136285Sbrian
54236285Sbrian  return result;
5437001Samurai}
5447001Samurai
54536285Sbrianint
54646686Sbrianip_PushPacket(struct link *l, struct bundle *bundle)
5476059Samurai{
54838557Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
5496059Samurai  struct mqueue *queue;
5506059Samurai  struct mbuf *bp;
55146686Sbrian  struct ip *pip;
55225630Sbrian  int cnt;
5536059Samurai
55438557Sbrian  if (ipcp->fsm.state != ST_OPENED)
55536285Sbrian    return 0;
55636285Sbrian
55738557Sbrian  for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--)
5586059Samurai    if (queue->top) {
55945103Sbrian      bp = mbuf_Contiguous(mbuf_Dequeue(queue));
56046686Sbrian      cnt = mbuf_Length(bp);
56146686Sbrian      pip = (struct ip *)MBUF_CTOP(bp);
56249140Sbrian      if (!FilterCheck(pip, &bundle->filter.alive))
56346686Sbrian        bundle_StartIdleTimer(bundle);
56446686Sbrian      link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP);
56546686Sbrian      ipcp_AddOutOctets(ipcp, cnt);
56646686Sbrian      return 1;
5676059Samurai    }
56836285Sbrian
56936285Sbrian  return 0;
5706059Samurai}
571