ip.c revision 38557
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 *
2038557Sbrian * $Id: ip.c,v 1.51 1998/08/25 17:48:42 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Return ICMP message for filterd packet
246059Samurai *		  and optionaly record it into log.
256059Samurai */
2636285Sbrian#include <sys/types.h>
2738174Sbrian#ifdef __OpenBSD__
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
3931343Sbrian#ifndef NOALIAS
4026031Sbrian#include <alias.h>
4131343Sbrian#endif
4230092Sbrian#include <errno.h>
4330715Sbrian#include <stdio.h>
4430715Sbrian#include <stdlib.h>
4530715Sbrian#include <string.h>
4630715Sbrian#include <unistd.h>
4730715Sbrian
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"
6536285Sbrian#include "bundle.h"
6630715Sbrian#include "vjcomp.h"
6731195Sbrian#include "tun.h"
6830715Sbrian#include "ip.h"
696059Samurai
7031343Sbrianstatic const u_short interactive_ports[32] = {
7128679Sbrian  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7228679Sbrian  0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
736059Samurai};
746059Samurai
7513733Sdfr#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
766059Samurai
7731343Sbrianstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
786059Samurai
796059Samuraistatic int
8028679SbrianPortMatch(int op, u_short pport, u_short rport)
816059Samurai{
826059Samurai  switch (op) {
8328679Sbrian    case OP_EQ:
8428679Sbrian    return (pport == rport);
856059Samurai  case OP_GT:
8628679Sbrian    return (pport > rport);
876059Samurai  case OP_LT:
8828679Sbrian    return (pport < rport);
896059Samurai  default:
9028679Sbrian    return (0);
916059Samurai  }
926059Samurai}
936059Samurai
946059Samurai/*
956059Samurai *  Check a packet against with defined filters
966059Samurai */
976059Samuraistatic int
9836285SbrianFilterCheck(struct ip *pip, struct filter *filter)
996059Samurai{
10036285Sbrian  int gotinfo, cproto, estab, syn, finrst, n, len, didname;
1016059Samurai  struct tcphdr *th;
1026059Samurai  struct udphdr *uh;
1036059Samurai  struct icmp *ih;
1046059Samurai  char *ptop;
1056059Samurai  u_short sport, dport;
10636285Sbrian  struct filterent *fp = filter->rule;
10736285Sbrian  char dbuff[100];
1086059Samurai
1096059Samurai  if (fp->action) {
11036285Sbrian    cproto = gotinfo = estab = syn = finrst = didname = 0;
1116059Samurai    sport = dport = 0;
1126059Samurai    for (n = 0; n < MAXFILTERS; n++) {
1136059Samurai      if (fp->action) {
11428679Sbrian	/* permit fragments on in and out filter */
11536285Sbrian        if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0)
11628679Sbrian	  return (A_PERMIT);
11736285Sbrian
11836285Sbrian        if (!didname)
11936285Sbrian          log_Printf(LogDEBUG, "%s filter:\n", filter->name);
12036285Sbrian        didname = 1;
12136285Sbrian
12231143Sbrian	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
12331143Sbrian	    (fp->saddr.s_addr & fp->smask.s_addr) &&
12431143Sbrian	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
12531143Sbrian	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
1266059Samurai	  if (fp->proto) {
1276059Samurai	    if (!gotinfo) {
12828679Sbrian	      ptop = (char *) pip + (pip->ip_hl << 2);
1296059Samurai
1306059Samurai	      switch (pip->ip_p) {
1316059Samurai	      case IPPROTO_ICMP:
13228679Sbrian		cproto = P_ICMP;
13328679Sbrian		ih = (struct icmp *) ptop;
13428679Sbrian		sport = ih->icmp_type;
13536285Sbrian		estab = syn = finrst = -1;
13636285Sbrian                if (log_IsKept(LogDEBUG))
13736285Sbrian		  snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
1386059Samurai		break;
1396059Samurai	      case IPPROTO_UDP:
14036961Sbrian	      case IPPROTO_IGMP:
14136961Sbrian	      case IPPROTO_IPIP:
14228679Sbrian		cproto = P_UDP;
14328679Sbrian		uh = (struct udphdr *) ptop;
14428679Sbrian		sport = ntohs(uh->uh_sport);
14528679Sbrian		dport = ntohs(uh->uh_dport);
14636285Sbrian		estab = syn = finrst = -1;
14736285Sbrian                if (log_IsKept(LogDEBUG))
14836285Sbrian		  snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
14936285Sbrian                           sport, dport);
1506059Samurai		break;
1516059Samurai	      case IPPROTO_TCP:
15228679Sbrian		cproto = P_TCP;
15328679Sbrian		th = (struct tcphdr *) ptop;
15428679Sbrian		sport = ntohs(th->th_sport);
15528679Sbrian		dport = ntohs(th->th_dport);
1566059Samurai		estab = (th->th_flags & TH_ACK);
15736285Sbrian		syn = (th->th_flags & TH_SYN);
15836285Sbrian		finrst = (th->th_flags & (TH_FIN|TH_RST));
15936285Sbrian                if (log_IsKept(LogDEBUG) && !estab)
16036285Sbrian		  snprintf(dbuff, sizeof dbuff,
16136285Sbrian                           "flags = %02x, sport = %d, dport = %d",
16236285Sbrian                           th->th_flags, sport, dport);
1636059Samurai		break;
1646059Samurai	      default:
16536285Sbrian		return (A_DENY);       /* We'll block unknown type of packet */
1666059Samurai	      }
16736285Sbrian              if (log_IsKept(LogDEBUG)) {
16836285Sbrian                if (estab != -1) {
16936285Sbrian                  len = strlen(dbuff);
17036285Sbrian                  snprintf(dbuff + len, sizeof dbuff - len,
17136285Sbrian                           ", estab = %d, syn = %d, finrst = %d",
17236285Sbrian                           estab, syn, finrst);
17336285Sbrian                }
17436285Sbrian	        log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
17536285Sbrian                          filter_Proto2Nam(cproto), dbuff);
17636285Sbrian              }
1776059Samurai	      gotinfo = 1;
1786059Samurai	    }
17936285Sbrian            if (log_IsKept(LogDEBUG)) {
18036285Sbrian	      if (fp->opt.srcop != OP_NONE) {
18136285Sbrian                snprintf(dbuff, sizeof dbuff, ", src %s %d",
18236285Sbrian                         filter_Op2Nam(fp->opt.srcop), fp->opt.srcport);
18336285Sbrian                len = strlen(dbuff);
18436285Sbrian              } else
18536285Sbrian                len = 0;
18636285Sbrian	      if (fp->opt.dstop != OP_NONE) {
18736285Sbrian                snprintf(dbuff + len, sizeof dbuff - len,
18836285Sbrian                         ", dst %s %d", filter_Op2Nam(fp->opt.dstop),
18936285Sbrian                         fp->opt.dstport);
19036285Sbrian              } else if (!len)
19136285Sbrian                *dbuff = '\0';
19226516Sbrian
19336285Sbrian	      log_Printf(LogDEBUG, "  rule = %d: Address match, "
19436285Sbrian                        "check against proto %s%s, action = %s\n",
19536285Sbrian                        n, filter_Proto2Nam(fp->proto),
19636285Sbrian                        dbuff, filter_Action2Nam(fp->action));
19736285Sbrian            }
19836285Sbrian
1996059Samurai	    if (cproto == fp->proto) {
2006059Samurai	      if ((fp->opt.srcop == OP_NONE ||
20136285Sbrian		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) &&
2026059Samurai		  (fp->opt.dstop == OP_NONE ||
20336285Sbrian		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) &&
20436285Sbrian		  (fp->opt.estab == 0 || estab) &&
20536285Sbrian		  (fp->opt.syn == 0 || syn) &&
20636285Sbrian		  (fp->opt.finrst == 0 || finrst)) {
20728679Sbrian		return (fp->action);
2086059Samurai	      }
2096059Samurai	    }
2106059Samurai	  } else {
2116059Samurai	    /* Address is mached. Make a decision. */
21236285Sbrian	    log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
21336285Sbrian                      filter_Action2Nam(fp->action));
21428679Sbrian	    return (fp->action);
2156059Samurai	  }
21636285Sbrian	} else
21736285Sbrian	  log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
2186059Samurai      }
2196059Samurai      fp++;
2206059Samurai    }
22128679Sbrian    return (A_DENY);		/* No rule is mached. Deny this packet */
2226059Samurai  }
22328679Sbrian  return (A_PERMIT);		/* No rule is given. Permit this packet */
2246059Samurai}
2256059Samurai
22636285Sbrian#ifdef notdef
2276059Samuraistatic void
22828679SbrianIcmpError(struct ip * pip, int code)
2296059Samurai{
2306059Samurai  struct mbuf *bp;
2316059Samurai
2326059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
23336285Sbrian    bp = mbuf_Alloc(cnt, MB_IPIN);
23430715Sbrian    memcpy(MBUF_CTOP(bp), ptr, cnt);
23536285Sbrian    vj_SendFrame(bp);
23636285Sbrian    ipcp_AddOutOctets(cnt);
2376059Samurai  }
23836285Sbrian}
2396059Samurai#endif
2406059Samurai
2416059Samurai/*
2426059Samurai *  For debugging aid.
2436059Samurai */
2446059Samuraiint
24536285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
2466059Samurai{
2476059Samurai  struct ip *pip;
2486059Samurai  struct tcphdr *th;
2496059Samurai  struct udphdr *uh;
2506059Samurai  struct icmp *icmph;
2516059Samurai  char *ptop;
2526059Samurai  int mask, len, n;
2536059Samurai  int pri = PRI_NORMAL;
25426692Sbrian  int logit, loglen;
25537010Sbrian  char logbuf[200];
2566059Samurai
25736285Sbrian  logit = log_IsKept(LogTCPIP) && filter->logok;
25826692Sbrian  loglen = 0;
2596059Samurai
26028679Sbrian  pip = (struct ip *) cp;
2618857Srgrimes
26226692Sbrian  if (logit && loglen < sizeof logbuf) {
26336285Sbrian    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
26428679Sbrian    loglen += strlen(logbuf + loglen);
26526692Sbrian  }
2666059Samurai  ptop = (cp + (pip->ip_hl << 2));
2676059Samurai
2686059Samurai  switch (pip->ip_p) {
2696059Samurai  case IPPROTO_ICMP:
27026692Sbrian    if (logit && loglen < sizeof logbuf) {
27128679Sbrian      icmph = (struct icmp *) ptop;
27228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
27328679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
27428679Sbrian      loglen += strlen(logbuf + loglen);
27528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
27628679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
27728679Sbrian      loglen += strlen(logbuf + loglen);
2786059Samurai    }
2796059Samurai    break;
2806059Samurai  case IPPROTO_UDP:
28126692Sbrian    if (logit && loglen < sizeof logbuf) {
28228679Sbrian      uh = (struct udphdr *) ptop;
28328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
28428679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
28528679Sbrian      loglen += strlen(logbuf + loglen);
28628679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
28728679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
28828679Sbrian      loglen += strlen(logbuf + loglen);
2896059Samurai    }
2906059Samurai    break;
29136961Sbrian  case IPPROTO_IPIP:
29236961Sbrian    if (logit && loglen < sizeof logbuf) {
29336961Sbrian      uh = (struct udphdr *) ptop;
29436961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
29536961Sbrian	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
29636961Sbrian      loglen += strlen(logbuf + loglen);
29736961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
29836961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
29936961Sbrian      loglen += strlen(logbuf + loglen);
30036961Sbrian    }
30136961Sbrian    break;
30236961Sbrian  case IPPROTO_IGMP:
30336961Sbrian    if (logit && loglen < sizeof logbuf) {
30436961Sbrian      uh = (struct udphdr *) ptop;
30536961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
30636961Sbrian	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
30736961Sbrian      loglen += strlen(logbuf + loglen);
30836961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
30936961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
31036961Sbrian      loglen += strlen(logbuf + loglen);
31136961Sbrian    }
31236961Sbrian    break;
3136059Samurai  case IPPROTO_TCP:
31428679Sbrian    th = (struct tcphdr *) ptop;
3156059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
3166059Samurai      pri = PRI_FAST;
31713733Sdfr    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
3186059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
31928679Sbrian	pri = PRI_FAST;
3206059Samurai    }
32126692Sbrian    if (logit && loglen < sizeof logbuf) {
3226059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
32328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
32428679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
32528679Sbrian      loglen += strlen(logbuf + loglen);
32628679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
32728679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
32828679Sbrian      loglen += strlen(logbuf + loglen);
3296059Samurai      n = 0;
3306059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
33126692Sbrian	if (th->th_flags & mask) {
33228679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
33328679Sbrian	  loglen += strlen(logbuf + loglen);
33428679Sbrian	}
3356059Samurai	n++;
3366059Samurai      }
33728679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
33837210Sbrian	       "  seq:%lx  ack:%lx (%d/%d)",
33937210Sbrian	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
34028679Sbrian      loglen += strlen(logbuf + loglen);
3416059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
34228679Sbrian	u_short *sp;
3436059Samurai
3446059Samurai	ptop += 20;
34528679Sbrian	sp = (u_short *) ptop;
34626692Sbrian	if (ntohs(sp[0]) == 0x0204) {
34728679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
34828679Sbrian		   " MSS = %d", ntohs(sp[1]));
34928679Sbrian	  loglen += strlen(logbuf + loglen);
35028679Sbrian	}
3516059Samurai      }
3526059Samurai    }
3536059Samurai    break;
3546059Samurai  }
35526692Sbrian
35636285Sbrian  if ((FilterCheck(pip, filter) & A_DENY)) {
35731142Sbrian    if (logit)
35836285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
35936285Sbrian#ifdef notdef
36028679Sbrian    if (direction == 0)
36128679Sbrian      IcmpError(pip, pri);
36236285Sbrian#endif
36328679Sbrian    return (-1);
3646059Samurai  } else {
36536285Sbrian    /* Check Keep Alive filter */
36636285Sbrian    if (logit) {
36736285Sbrian      if (FilterCheck(pip, &bundle->filter.alive) & A_DENY)
36836285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
36936285Sbrian      else
37036285Sbrian        log_Printf(LogTCPIP, "%s\n", logbuf);
3716735Samurai    }
37228679Sbrian    return (pri);
3736059Samurai  }
3746059Samurai}
3756059Samurai
3766059Samuraivoid
37736285Sbrianip_Input(struct bundle *bundle, struct mbuf * bp)
37836285Sbrian{
3796059Samurai  u_char *cp;
3806059Samurai  struct mbuf *wp;
3816059Samurai  int nb, nw;
38231343Sbrian  struct tun_data tun;
38336285Sbrian  struct ip *pip = (struct ip *)tun.data;
38437210Sbrian#ifndef NOALIAS
38536961Sbrian  struct ip *piip = (struct ip *)((char *)pip + (pip->ip_hl << 2));
38637210Sbrian#endif
3876059Samurai
38831195Sbrian  tun_fill_header(tun, AF_INET);
38931195Sbrian  cp = tun.data;
3906059Samurai  nb = 0;
39128679Sbrian  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
39232247Sbrian    if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
39337019Sbrian      log_Printf(LogWARN, "ip_Input: Packet too large (%d) - dropped\n",
39436285Sbrian                mbuf_Length(bp));
39536285Sbrian      mbuf_Free(bp);
39632247Sbrian      return;
39732247Sbrian    }
39830715Sbrian    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
3996059Samurai    cp += wp->cnt;
4006059Samurai    nb += wp->cnt;
4016059Samurai  }
4026059Samurai
40331343Sbrian#ifndef NOALIAS
40437191Sbrian  if (bundle->AliasEnabled && pip->ip_p != IPPROTO_IGMP &&
40536961Sbrian      (pip->ip_p != IPPROTO_IPIP || !IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) {
40631343Sbrian    struct tun_data *frag;
40726031Sbrian    int iresult;
40826031Sbrian    char *fptr;
40926031Sbrian
41037191Sbrian    iresult = PacketAliasIn(tun.data, sizeof tun.data);
41131195Sbrian    nb = ntohs(((struct ip *) tun.data)->ip_len);
41226031Sbrian
41326031Sbrian    if (nb > MAX_MRU) {
41437019Sbrian      log_Printf(LogWARN, "ip_Input: Problem with IP header length\n");
41536285Sbrian      mbuf_Free(bp);
41626031Sbrian      return;
41726031Sbrian    }
41826031Sbrian    if (iresult == PKT_ALIAS_OK
41928679Sbrian	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
42036285Sbrian      if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
42136285Sbrian	mbuf_Free(bp);
42228679Sbrian	return;
42326031Sbrian      }
42426031Sbrian
42536285Sbrian      if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
42636285Sbrian        bundle_StartIdleTimer(bundle);
42736285Sbrian
42836285Sbrian      ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
42936285Sbrian
43031195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
43131962Sbrian      nb += sizeof tun - sizeof tun.data;
43236285Sbrian      nw = write(bundle->dev.fd, &tun, nb);
43335449Sbrian      if (nw != nb) {
43430092Sbrian        if (nw == -1)
43536285Sbrian	  log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
43630092Sbrian                    strerror(errno));
43730092Sbrian        else
43836285Sbrian	  log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
43935449Sbrian      }
44026031Sbrian
44126031Sbrian      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
44237191Sbrian	while ((fptr = PacketAliasGetFragment(tun.data)) != NULL) {
44337191Sbrian	  PacketAliasFragmentIn(tun.data, fptr);
44428679Sbrian	  nb = ntohs(((struct ip *) fptr)->ip_len);
44531962Sbrian          frag = (struct tun_data *)
44631962Sbrian	    ((char *)fptr - sizeof tun + sizeof tun.data);
44731962Sbrian          nb += sizeof tun - sizeof tun.data;
44836285Sbrian	  nw = write(bundle->dev.fd, frag, nb);
44935449Sbrian	  if (nw != nb) {
45030092Sbrian            if (nw == -1)
45136285Sbrian	      log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
45230092Sbrian                        strerror(errno));
45330092Sbrian            else
45436285Sbrian	      log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
45535449Sbrian          }
45631195Sbrian	  free(frag);
45728679Sbrian	}
45826031Sbrian      }
45928679Sbrian    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
46031195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
46131962Sbrian      nb += sizeof tun - sizeof tun.data;
46231195Sbrian      frag = (struct tun_data *)malloc(nb);
46331195Sbrian      if (frag == NULL)
46436285Sbrian	log_Printf(LogALERT, "ip_Input: Cannot allocate memory for fragment\n");
46526031Sbrian      else {
46631195Sbrian        tun_fill_header(*frag, AF_INET);
46731962Sbrian	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
46837191Sbrian	PacketAliasSaveFragment(frag->data);
46926031Sbrian      }
47026031Sbrian    }
47131343Sbrian  } else
47231343Sbrian#endif /* #ifndef NOALIAS */
47331343Sbrian  {			/* no aliasing */
47436285Sbrian    if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
47536285Sbrian      mbuf_Free(bp);
47626031Sbrian      return;
47726031Sbrian    }
47836285Sbrian
47936285Sbrian    if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
48036285Sbrian      bundle_StartIdleTimer(bundle);
48136285Sbrian
48236285Sbrian    ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
48336285Sbrian
48431962Sbrian    nb += sizeof tun - sizeof tun.data;
48536285Sbrian    nw = write(bundle->dev.fd, &tun, nb);
48634536Sbrian    if (nw != nb) {
48730092Sbrian      if (nw == -1)
48836285Sbrian	log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno));
48930092Sbrian      else
49036285Sbrian        log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
49134536Sbrian    }
4926059Samurai  }
49336285Sbrian  mbuf_Free(bp);
4946059Samurai}
4956059Samurai
4966059Samuraivoid
49738557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
4986059Samurai{
4996059Samurai  struct mbuf *bp;
5006059Samurai
50138557Sbrian  if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0])
50238557Sbrian    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
50338557Sbrian  else {
50438557Sbrian    bp = mbuf_Alloc(count, MB_IPQ);
50538557Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
50638557Sbrian    mbuf_Enqueue(&ipcp->Queue[pri], bp);
50738557Sbrian  }
5086059Samurai}
5096059Samurai
51038544Sbrianvoid
51138557Sbrianip_DeleteQueue(struct ipcp *ipcp)
51238544Sbrian{
51338544Sbrian  struct mqueue *queue;
51438544Sbrian
51538557Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
51638544Sbrian    while (queue->top)
51738544Sbrian      mbuf_Free(mbuf_Dequeue(queue));
51838544Sbrian}
51938544Sbrian
5208857Srgrimesint
52138557Sbrianip_QueueLen(struct ipcp *ipcp)
5227001Samurai{
5237001Samurai  struct mqueue *queue;
52436285Sbrian  int result = 0;
52528679Sbrian
52638557Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
52736285Sbrian    result += queue->qlen;
52836285Sbrian
52936285Sbrian  return result;
5307001Samurai}
5317001Samurai
53236285Sbrianint
53336285Sbrianip_FlushPacket(struct link *l, struct bundle *bundle)
5346059Samurai{
53538557Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
5366059Samurai  struct mqueue *queue;
5376059Samurai  struct mbuf *bp;
53825630Sbrian  int cnt;
5396059Samurai
54038557Sbrian  if (ipcp->fsm.state != ST_OPENED)
54136285Sbrian    return 0;
54236285Sbrian
54338557Sbrian  for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--)
5446059Samurai    if (queue->top) {
54536285Sbrian      bp = mbuf_Dequeue(queue);
5466059Samurai      if (bp) {
54736285Sbrian        struct ip *pip = (struct ip *)MBUF_CTOP(bp);
54836285Sbrian
54936285Sbrian	cnt = mbuf_Length(bp);
55036285Sbrian        if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
55136285Sbrian          bundle_StartIdleTimer(bundle);
55237572Sbrian	vj_SendFrame(l, bp, bundle);
55338557Sbrian        ipcp_AddOutOctets(ipcp, cnt);
55436285Sbrian	return 1;
55528679Sbrian      }
5566059Samurai    }
55736285Sbrian
55836285Sbrian  return 0;
5596059Samurai}
560