ip.c revision 55146
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 *
2050479Speter * $FreeBSD: head/usr.sbin/ppp/ip.c 55146 1999-12-27 11:54:57Z brian $
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 <string.h>
4246686Sbrian#include <termios.h>
4330715Sbrian#include <unistd.h>
4430715Sbrian
4546686Sbrian#include "layer.h"
4646686Sbrian#include "proto.h"
4730715Sbrian#include "mbuf.h"
4830715Sbrian#include "log.h"
4930715Sbrian#include "defs.h"
5030715Sbrian#include "timer.h"
5130715Sbrian#include "fsm.h"
5236285Sbrian#include "lqr.h"
5330715Sbrian#include "hdlc.h"
5436285Sbrian#include "throughput.h"
5536285Sbrian#include "iplist.h"
5636285Sbrian#include "slcompress.h"
5736285Sbrian#include "ipcp.h"
586059Samurai#include "filter.h"
5936285Sbrian#include "descriptor.h"
6036285Sbrian#include "lcp.h"
6136285Sbrian#include "ccp.h"
6236285Sbrian#include "link.h"
6336285Sbrian#include "mp.h"
6443313Sbrian#ifndef NORADIUS
6543313Sbrian#include "radius.h"
6643313Sbrian#endif
6736285Sbrian#include "bundle.h"
6831195Sbrian#include "tun.h"
6930715Sbrian#include "ip.h"
706059Samurai
7155146Sbrianstatic const char * const TcpFlags[] = {
7255146Sbrian  "FIN", "SYN", "RST", "PSH", "ACK", "URG"
7355146Sbrian};
746059Samurai
7549140Sbrianstatic __inline int
7628679SbrianPortMatch(int op, u_short pport, u_short rport)
776059Samurai{
786059Samurai  switch (op) {
7949140Sbrian  case OP_EQ:
8028679Sbrian    return (pport == rport);
816059Samurai  case OP_GT:
8228679Sbrian    return (pport > rport);
836059Samurai  case OP_LT:
8428679Sbrian    return (pport < rport);
856059Samurai  default:
8628679Sbrian    return (0);
876059Samurai  }
886059Samurai}
896059Samurai
906059Samurai/*
9146686Sbrian *  Check a packet against a defined filter
9249140Sbrian *  Returns 0 to accept the packet, non-zero to drop the packet
9349140Sbrian *
9449140Sbrian *  If filtering is enabled, the initial fragment of a datagram must
9549140Sbrian *  contain the complete protocol header, and subsequent fragments
9649140Sbrian *  must not attempt to over-write it.
976059Samurai */
986059Samuraistatic int
9949140SbrianFilterCheck(const struct ip *pip, const struct filter *filter)
1006059Samurai{
10149140Sbrian  int gotinfo;			/* true if IP payload decoded */
10249140Sbrian  int cproto;			/* P_* protocol type if (gotinfo) */
10349140Sbrian  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
10449140Sbrian  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
10549140Sbrian  int n;			/* filter rule to process */
10649140Sbrian  int len;			/* bytes used in dbuff */
10749140Sbrian  int didname;			/* true if filter header printed */
10849140Sbrian  int match;			/* true if condition matched */
10949140Sbrian  const struct filterent *fp = filter->rule;
11036285Sbrian  char dbuff[100];
1116059Samurai
11249140Sbrian  if (fp->f_action == A_NONE)
11349140Sbrian    return (0);		/* No rule is given. Permit this packet */
11436285Sbrian
11549140Sbrian  /* Deny any packet fragment that tries to over-write the header.
11649140Sbrian   * Since we no longer have the real header available, punt on the
11749140Sbrian   * largest normal header - 20 bytes for TCP without options, rounded
11849140Sbrian   * up to the next possible fragment boundary.  Since the smallest
11949140Sbrian   * `legal' MTU is 576, and the smallest recommended MTU is 296, any
12049140Sbrian   * fragmentation within this range is dubious at best */
12149140Sbrian  len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
12249140Sbrian  if (len > 0) {		/* Not first fragment within datagram */
12349140Sbrian    if (len < (24 >> 3))	/* don't allow fragment to over-write header */
12449140Sbrian      return (1);
12549140Sbrian    /* permit fragments on in and out filter */
12651333Sbrian    return (!filter->fragok);
12749140Sbrian  }
12849140Sbrian
12949140Sbrian  cproto = gotinfo = estab = syn = finrst = didname = 0;
13049140Sbrian  sport = dport = 0;
13149140Sbrian  for (n = 0; n < MAXFILTERS; ) {
13249140Sbrian    if (fp->f_action == A_NONE) {
13349140Sbrian      n++;
13449140Sbrian      fp++;
13549140Sbrian      continue;
13649140Sbrian    }
13736285Sbrian
13849140Sbrian    if (!didname) {
13949140Sbrian      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
14049140Sbrian      didname = 1;
14149140Sbrian    }
1426059Samurai
14349140Sbrian    match = 0;
14449140Sbrian    if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
14549140Sbrian	  fp->f_src.mask.s_addr) &&
14649140Sbrian	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
14749140Sbrian	  fp->f_dst.mask.s_addr)) {
14849140Sbrian      if (fp->f_proto != P_NONE) {
14949140Sbrian	if (!gotinfo) {
15049140Sbrian	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
15149140Sbrian	  const struct tcphdr *th;
15249140Sbrian	  const struct udphdr *uh;
15349140Sbrian	  const struct icmp *ih;
15449140Sbrian	  int datalen;	/* IP datagram length */
15549140Sbrian
15649140Sbrian	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
15749140Sbrian	  switch (pip->ip_p) {
15849140Sbrian	  case IPPROTO_ICMP:
15949140Sbrian	    cproto = P_ICMP;
16049140Sbrian	    if (datalen < 8)	/* ICMP must be at least 8 octets */
16149140Sbrian	      return (1);
16249140Sbrian	    ih = (const struct icmp *) ptop;
16349140Sbrian	    sport = ih->icmp_type;
16449140Sbrian	    estab = syn = finrst = -1;
16549140Sbrian	    if (log_IsKept(LogDEBUG))
16649140Sbrian	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
16749140Sbrian	    break;
16849140Sbrian	  case IPPROTO_IGMP:
16949140Sbrian	    cproto = P_IGMP;
17049140Sbrian	    if (datalen < 8)	/* IGMP uses 8-octet messages */
17149140Sbrian	      return (1);
17249140Sbrian	    estab = syn = finrst = -1;
17349140Sbrian	    sport = ntohs(0);
17449140Sbrian	    break;
17551809Sbrian#ifdef IPPROTO_GRE
17651809Sbrian          case IPPROTO_GRE:
17751809Sbrian            cproto = P_GRE;
17851809Sbrian            if (datalen < 2)    /* GRE uses 2-octet+ messages */
17951809Sbrian              return (1);
18051809Sbrian            estab = syn = finrst = -1;
18151809Sbrian            sport = ntohs(0);
18251809Sbrian            break;
18351809Sbrian#endif
18449374Sbrian#ifdef IPPROTO_OSPFIGP
18549372Sbrian	  case IPPROTO_OSPFIGP:
18649372Sbrian	    cproto = P_OSPF;
18749372Sbrian	    if (datalen < 8)	/* IGMP uses 8-octet messages */
18849372Sbrian	      return (1);
18949372Sbrian	    estab = syn = finrst = -1;
19049372Sbrian	    sport = ntohs(0);
19149372Sbrian	    break;
19249374Sbrian#endif
19349140Sbrian	  case IPPROTO_UDP:
19449140Sbrian	  case IPPROTO_IPIP:
19549140Sbrian	    cproto = P_UDP;
19649140Sbrian	    if (datalen < 8)	/* UDP header is 8 octets */
19749140Sbrian	      return (1);
19849140Sbrian	    uh = (const struct udphdr *) ptop;
19949140Sbrian	    sport = ntohs(uh->uh_sport);
20049140Sbrian	    dport = ntohs(uh->uh_dport);
20149140Sbrian	    estab = syn = finrst = -1;
20249140Sbrian	    if (log_IsKept(LogDEBUG))
20349140Sbrian	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
20449140Sbrian		       sport, dport);
20549140Sbrian	    break;
20649140Sbrian	  case IPPROTO_TCP:
20749140Sbrian	    cproto = P_TCP;
20849140Sbrian	    th = (const struct tcphdr *) ptop;
20949140Sbrian	    /* TCP headers are variable length.  The following code
21049140Sbrian	     * ensures that the TCP header length isn't de-referenced if
21149140Sbrian	     * the datagram is too short
21249140Sbrian	     */
21349140Sbrian	    if (datalen < 20 || datalen < (th->th_off << 2))
21449140Sbrian	      return (1);
21549140Sbrian	    sport = ntohs(th->th_sport);
21649140Sbrian	    dport = ntohs(th->th_dport);
21749140Sbrian	    estab = (th->th_flags & TH_ACK);
21849140Sbrian	    syn = (th->th_flags & TH_SYN);
21949140Sbrian	    finrst = (th->th_flags & (TH_FIN|TH_RST));
22049140Sbrian	    if (log_IsKept(LogDEBUG)) {
22149140Sbrian	      if (!estab)
22249140Sbrian		snprintf(dbuff, sizeof dbuff,
22349140Sbrian			 "flags = %02x, sport = %d, dport = %d",
22449140Sbrian			 th->th_flags, sport, dport);
22549140Sbrian	      else
22649140Sbrian		*dbuff = '\0';
2276059Samurai	    }
22849140Sbrian	    break;
22949140Sbrian	  default:
23049140Sbrian	    return (1);	/* We'll block unknown type of packet */
23149140Sbrian	  }
23226516Sbrian
23349140Sbrian	  if (log_IsKept(LogDEBUG)) {
23449140Sbrian	    if (estab != -1) {
23549140Sbrian	      len = strlen(dbuff);
23649140Sbrian	      snprintf(dbuff + len, sizeof dbuff - len,
23749140Sbrian		       ", estab = %d, syn = %d, finrst = %d",
23849140Sbrian		       estab, syn, finrst);
2396059Samurai	    }
24049140Sbrian	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
24149140Sbrian		       filter_Proto2Nam(cproto), dbuff);
2426059Samurai	  }
24349140Sbrian	  gotinfo = 1;
24449140Sbrian	}
24549140Sbrian	if (log_IsKept(LogDEBUG)) {
24649140Sbrian	  if (fp->f_srcop != OP_NONE) {
24749140Sbrian	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
24849140Sbrian		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
24949140Sbrian	    len = strlen(dbuff);
25049140Sbrian	  } else
25149140Sbrian	    len = 0;
25249140Sbrian	  if (fp->f_dstop != OP_NONE) {
25349140Sbrian	    snprintf(dbuff + len, sizeof dbuff - len,
25449140Sbrian		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
25549140Sbrian		     fp->f_dstport);
25649140Sbrian	  } else if (!len)
25749140Sbrian	    *dbuff = '\0';
25849140Sbrian
25949140Sbrian	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
26049140Sbrian		     "check against proto %s%s, action = %s\n",
26149140Sbrian		     n, filter_Proto2Nam(fp->f_proto),
26249140Sbrian		     dbuff, filter_Action2Nam(fp->f_action));
26349140Sbrian	}
26449140Sbrian
26549140Sbrian	if (cproto == fp->f_proto) {
26649140Sbrian	  if ((fp->f_srcop == OP_NONE ||
26749140Sbrian	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
26849140Sbrian	      (fp->f_dstop == OP_NONE ||
26949140Sbrian	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
27049140Sbrian	      (fp->f_estab == 0 || estab) &&
27149140Sbrian	      (fp->f_syn == 0 || syn) &&
27249140Sbrian	      (fp->f_finrst == 0 || finrst)) {
27349140Sbrian	    match = 1;
27449140Sbrian	  }
27549140Sbrian	}
27649140Sbrian      } else {
27749140Sbrian	/* Address is matched and no protocol specified. Make a decision. */
27849140Sbrian	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
27949140Sbrian		   filter_Action2Nam(fp->f_action));
28049140Sbrian	match = 1;
2816059Samurai      }
28249140Sbrian    } else
28349140Sbrian      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
28449140Sbrian
28549140Sbrian    if (match != fp->f_invert) {
28649140Sbrian      /* Take specified action */
28749140Sbrian      if (fp->f_action < A_NONE)
28849140Sbrian	fp = &filter->rule[n = fp->f_action];
28949140Sbrian      else
29049140Sbrian	return (fp->f_action != A_PERMIT);
29149140Sbrian    } else {
29249140Sbrian      n++;
2936059Samurai      fp++;
2946059Samurai    }
2956059Samurai  }
29649140Sbrian  return (1);		/* No rule is mached. Deny this packet */
2976059Samurai}
2986059Samurai
29936285Sbrian#ifdef notdef
3006059Samuraistatic void
30146828SbrianIcmpError(struct ip *pip, int code)
3026059Samurai{
3036059Samurai  struct mbuf *bp;
3046059Samurai
3056059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
30654912Sbrian    bp = m_get(m_len, MB_IPIN);
30754912Sbrian    memcpy(MBUF_CTOP(bp), ptr, m_len);
30836285Sbrian    vj_SendFrame(bp);
30954912Sbrian    ipcp_AddOutOctets(m_len);
3106059Samurai  }
31136285Sbrian}
3126059Samurai#endif
3136059Samurai
3146059Samurai/*
3156059Samurai *  For debugging aid.
3166059Samurai */
3176059Samuraiint
31836285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
3196059Samurai{
3206059Samurai  struct ip *pip;
3216059Samurai  struct tcphdr *th;
3226059Samurai  struct udphdr *uh;
3236059Samurai  struct icmp *icmph;
3246059Samurai  char *ptop;
3256059Samurai  int mask, len, n;
32650867Sbrian  int pri = 0;
32726692Sbrian  int logit, loglen;
32837010Sbrian  char logbuf[200];
3296059Samurai
33036285Sbrian  logit = log_IsKept(LogTCPIP) && filter->logok;
33126692Sbrian  loglen = 0;
3326059Samurai
33328679Sbrian  pip = (struct ip *) cp;
3348857Srgrimes
33526692Sbrian  if (logit && loglen < sizeof logbuf) {
33636285Sbrian    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
33728679Sbrian    loglen += strlen(logbuf + loglen);
33826692Sbrian  }
3396059Samurai  ptop = (cp + (pip->ip_hl << 2));
3406059Samurai
3416059Samurai  switch (pip->ip_p) {
3426059Samurai  case IPPROTO_ICMP:
34326692Sbrian    if (logit && loglen < sizeof logbuf) {
34428679Sbrian      icmph = (struct icmp *) ptop;
34528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
34628679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
34728679Sbrian      loglen += strlen(logbuf + loglen);
34828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
34928679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
35028679Sbrian      loglen += strlen(logbuf + loglen);
3516059Samurai    }
3526059Samurai    break;
35351048Sbrian
3546059Samurai  case IPPROTO_UDP:
35551048Sbrian    uh = (struct udphdr *) ptop;
35651048Sbrian    if (pip->ip_tos == IPTOS_LOWDELAY)
35751048Sbrian      pri++;
35851048Sbrian
35951048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
36051048Sbrian        ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
36151048Sbrian                          ntohs(uh->uh_dport)))
36251048Sbrian      pri++;
36351048Sbrian
36426692Sbrian    if (logit && loglen < sizeof logbuf) {
36528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
36628679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
36728679Sbrian      loglen += strlen(logbuf + loglen);
36828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
36928679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
37028679Sbrian      loglen += strlen(logbuf + loglen);
3716059Samurai    }
3726059Samurai    break;
37351048Sbrian
37451809Sbrian#ifdef IPPROTO_GRE
37551809Sbrian  case IPPROTO_GRE:
37651809Sbrian    if (logit && loglen < sizeof logbuf) {
37751809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
37851809Sbrian          "GRE: %s ---> ", inet_ntoa(pip->ip_src));
37951809Sbrian      loglen += strlen(logbuf + loglen);
38051809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
38151809Sbrian              "%s", inet_ntoa(pip->ip_dst));
38251809Sbrian      loglen += strlen(logbuf + loglen);
38351809Sbrian    }
38451809Sbrian    break;
38551809Sbrian#endif
38651809Sbrian
38749374Sbrian#ifdef IPPROTO_OSPFIGP
38849372Sbrian  case IPPROTO_OSPFIGP:
38949372Sbrian    if (logit && loglen < sizeof logbuf) {
39049372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
39149372Sbrian	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
39249372Sbrian      loglen += strlen(logbuf + loglen);
39349372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
39449372Sbrian	       "%s", inet_ntoa(pip->ip_dst));
39549372Sbrian      loglen += strlen(logbuf + loglen);
39649372Sbrian    }
39749372Sbrian    break;
39849374Sbrian#endif
39951048Sbrian
40036961Sbrian  case IPPROTO_IPIP:
40136961Sbrian    if (logit && loglen < sizeof logbuf) {
40236961Sbrian      uh = (struct udphdr *) ptop;
40336961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
40436961Sbrian	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
40536961Sbrian      loglen += strlen(logbuf + loglen);
40636961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
40736961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
40836961Sbrian      loglen += strlen(logbuf + loglen);
40936961Sbrian    }
41036961Sbrian    break;
41151048Sbrian
41236961Sbrian  case IPPROTO_IGMP:
41336961Sbrian    if (logit && loglen < sizeof logbuf) {
41436961Sbrian      uh = (struct udphdr *) ptop;
41536961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
41636961Sbrian	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
41736961Sbrian      loglen += strlen(logbuf + loglen);
41836961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
41936961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
42036961Sbrian      loglen += strlen(logbuf + loglen);
42136961Sbrian    }
42236961Sbrian    break;
42351048Sbrian
4246059Samurai  case IPPROTO_TCP:
42528679Sbrian    th = (struct tcphdr *) ptop;
4266059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
42750867Sbrian      pri++;
42851048Sbrian
42951048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
43051048Sbrian        ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
43151048Sbrian                          ntohs(th->th_dport)))
43250867Sbrian      pri++;
43350867Sbrian
43426692Sbrian    if (logit && loglen < sizeof logbuf) {
4356059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
43628679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
43728679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
43828679Sbrian      loglen += strlen(logbuf + loglen);
43928679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
44028679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
44128679Sbrian      loglen += strlen(logbuf + loglen);
4426059Samurai      n = 0;
4436059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
44426692Sbrian	if (th->th_flags & mask) {
44528679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
44628679Sbrian	  loglen += strlen(logbuf + loglen);
44728679Sbrian	}
4486059Samurai	n++;
4496059Samurai      }
45028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
45137210Sbrian	       "  seq:%lx  ack:%lx (%d/%d)",
45237210Sbrian	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
45328679Sbrian      loglen += strlen(logbuf + loglen);
4546059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
45528679Sbrian	u_short *sp;
4566059Samurai
4576059Samurai	ptop += 20;
45828679Sbrian	sp = (u_short *) ptop;
45926692Sbrian	if (ntohs(sp[0]) == 0x0204) {
46028679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
46128679Sbrian		   " MSS = %d", ntohs(sp[1]));
46228679Sbrian	  loglen += strlen(logbuf + loglen);
46328679Sbrian	}
4646059Samurai      }
4656059Samurai    }
4666059Samurai    break;
4676059Samurai  }
46826692Sbrian
46949140Sbrian  if (FilterCheck(pip, filter)) {
47031142Sbrian    if (logit)
47136285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
47236285Sbrian#ifdef notdef
47328679Sbrian    if (direction == 0)
47428679Sbrian      IcmpError(pip, pri);
47536285Sbrian#endif
47628679Sbrian    return (-1);
4776059Samurai  } else {
47836285Sbrian    /* Check Keep Alive filter */
47936285Sbrian    if (logit) {
48049140Sbrian      if (FilterCheck(pip, &bundle->filter.alive))
48136285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
48236285Sbrian      else
48336285Sbrian        log_Printf(LogTCPIP, "%s\n", logbuf);
4846735Samurai    }
48528679Sbrian    return (pri);
4866059Samurai  }
4876059Samurai}
4886059Samurai
48946686Sbrianstruct mbuf *
49046686Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
49136285Sbrian{
4926059Samurai  int nb, nw;
49331343Sbrian  struct tun_data tun;
49446686Sbrian  struct ip *pip;
4956059Samurai
49646686Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
49746686Sbrian    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
49854912Sbrian    m_freem(bp);
49946686Sbrian    return NULL;
5006059Samurai  }
5016059Samurai
50254912Sbrian  m_settype(bp, MB_IPIN);
50346686Sbrian  tun_fill_header(tun, AF_INET);
50454912Sbrian  nb = m_length(bp);
50547168Sbrian  if (nb > sizeof tun.data) {
50647168Sbrian    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
50747168Sbrian               l->name, nb, (int)(sizeof tun.data));
50854912Sbrian    m_freem(bp);
50947168Sbrian    return NULL;
51047168Sbrian  }
51146686Sbrian  mbuf_Read(bp, tun.data, nb);
51226031Sbrian
51346686Sbrian  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
51446686Sbrian    return NULL;
51526031Sbrian
51646686Sbrian  pip = (struct ip *)tun.data;
51749140Sbrian  if (!FilterCheck(pip, &bundle->filter.alive))
51846686Sbrian    bundle_StartIdleTimer(bundle);
51926031Sbrian
52046686Sbrian  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
52136285Sbrian
52246686Sbrian  nb += sizeof tun - sizeof tun.data;
52346686Sbrian  nw = write(bundle->dev.fd, &tun, nb);
52446686Sbrian  if (nw != nb) {
52546686Sbrian    if (nw == -1)
52647168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
52747168Sbrian                 l->name, nb, strerror(errno));
52846686Sbrian    else
52947168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
53046686Sbrian  }
53136285Sbrian
53246686Sbrian  return NULL;
5336059Samurai}
5346059Samurai
5356059Samuraivoid
53638557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
5376059Samurai{
5386059Samurai  struct mbuf *bp;
5396059Samurai
54050867Sbrian  if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
54138557Sbrian    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
54238557Sbrian  else {
54346686Sbrian    /*
54446686Sbrian     * We allocate an extra 6 bytes, four at the front and two at the end.
54546686Sbrian     * This is an optimisation so that we need to do less work in
54654912Sbrian     * m_prepend() in acf_LayerPush() and proto_LayerPush() and
54746686Sbrian     * appending in hdlc_LayerPush().
54846686Sbrian     */
54954912Sbrian    bp = m_get(count + 6, MB_IPOUT);
55054912Sbrian    bp->m_offset += 4;
55154912Sbrian    bp->m_len -= 6;
55238557Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
55354912Sbrian    m_enqueue(ipcp->Queue + pri, bp);
55438557Sbrian  }
5556059Samurai}
5566059Samurai
55738544Sbrianvoid
55838557Sbrianip_DeleteQueue(struct ipcp *ipcp)
55938544Sbrian{
56038544Sbrian  struct mqueue *queue;
56138544Sbrian
56250867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
56338544Sbrian    while (queue->top)
56454912Sbrian      m_freem(m_dequeue(queue));
56538544Sbrian}
56638544Sbrian
56754912Sbriansize_t
56838557Sbrianip_QueueLen(struct ipcp *ipcp)
5697001Samurai{
5707001Samurai  struct mqueue *queue;
57154912Sbrian  size_t result;
57228679Sbrian
57354912Sbrian  result = 0;
57450867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
57554912Sbrian    result += queue->len;
57636285Sbrian
57736285Sbrian  return result;
5787001Samurai}
5797001Samurai
58036285Sbrianint
58146686Sbrianip_PushPacket(struct link *l, struct bundle *bundle)
5826059Samurai{
58338557Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
5846059Samurai  struct mqueue *queue;
5856059Samurai  struct mbuf *bp;
58646686Sbrian  struct ip *pip;
58754912Sbrian  int m_len;
5886059Samurai
58938557Sbrian  if (ipcp->fsm.state != ST_OPENED)
59036285Sbrian    return 0;
59136285Sbrian
59250867Sbrian  queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
59350867Sbrian  do {
5946059Samurai    if (queue->top) {
59554912Sbrian      bp = m_pullup(m_dequeue(queue));
59654912Sbrian      m_len = m_length(bp);
59746686Sbrian      pip = (struct ip *)MBUF_CTOP(bp);
59849140Sbrian      if (!FilterCheck(pip, &bundle->filter.alive))
59946686Sbrian        bundle_StartIdleTimer(bundle);
60050867Sbrian      link_PushPacket(l, bp, bundle, 0, PROTO_IP);
60154912Sbrian      ipcp_AddOutOctets(ipcp, m_len);
60246686Sbrian      return 1;
6036059Samurai    }
60450867Sbrian  } while (queue-- != ipcp->Queue);
60536285Sbrian
60636285Sbrian  return 0;
6076059Samurai}
608