ip.c revision 36961
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 *
2036961Sbrian * $Id: ip.c,v 1.41 1998/05/21 21:45:37 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>
2731195Sbrian#include <sys/socket.h>
2830715Sbrian#include <netinet/in.h>
296059Samurai#include <netinet/in_systm.h>
306059Samurai#include <netinet/ip.h>
316059Samurai#include <netinet/ip_icmp.h>
326059Samurai#include <netinet/udp.h>
336059Samurai#include <netinet/tcp.h>
3413389Sphk#include <arpa/inet.h>
3536285Sbrian#include <net/if_tun.h>
3636285Sbrian#include <sys/un.h>
3730715Sbrian
3831343Sbrian#ifndef NOALIAS
3926031Sbrian#include <alias.h>
4031343Sbrian#endif
4130092Sbrian#include <errno.h>
4230715Sbrian#include <stdio.h>
4330715Sbrian#include <stdlib.h>
4430715Sbrian#include <string.h>
4530715Sbrian#include <unistd.h>
4630715Sbrian
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"
5426142Sbrian#include "loadalias.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;
25526692Sbrian  static 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,
33828679Sbrian	       "  seq:%x  ack:%x (%d/%d)",
33928679Sbrian	       ntohl(th->th_seq), 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;
38436961Sbrian  struct ip *piip = (struct ip *)((char *)pip + (pip->ip_hl << 2));
3856059Samurai
38631195Sbrian  tun_fill_header(tun, AF_INET);
38731195Sbrian  cp = tun.data;
3886059Samurai  nb = 0;
38928679Sbrian  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
39032247Sbrian    if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
39136285Sbrian      log_Printf(LogERROR, "ip_Input: Packet too large (%d) - dropped\n",
39236285Sbrian                mbuf_Length(bp));
39336285Sbrian      mbuf_Free(bp);
39432247Sbrian      return;
39532247Sbrian    }
39630715Sbrian    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
3976059Samurai    cp += wp->cnt;
3986059Samurai    nb += wp->cnt;
3996059Samurai  }
4006059Samurai
40131343Sbrian#ifndef NOALIAS
40236961Sbrian  if (alias_IsEnabled() && pip->ip_p != IPPROTO_IGMP &&
40336961Sbrian      (pip->ip_p != IPPROTO_IPIP || !IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) {
40431343Sbrian    struct tun_data *frag;
40526031Sbrian    int iresult;
40626031Sbrian    char *fptr;
40726031Sbrian
40836285Sbrian    iresult = (*PacketAlias.In)(tun.data, sizeof tun.data);
40931195Sbrian    nb = ntohs(((struct ip *) tun.data)->ip_len);
41026031Sbrian
41126031Sbrian    if (nb > MAX_MRU) {
41236285Sbrian      log_Printf(LogERROR, "ip_Input: Problem with IP header length\n");
41336285Sbrian      mbuf_Free(bp);
41426031Sbrian      return;
41526031Sbrian    }
41626031Sbrian    if (iresult == PKT_ALIAS_OK
41728679Sbrian	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
41836285Sbrian      if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
41936285Sbrian	mbuf_Free(bp);
42028679Sbrian	return;
42126031Sbrian      }
42226031Sbrian
42336285Sbrian      if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
42436285Sbrian        bundle_StartIdleTimer(bundle);
42536285Sbrian
42636285Sbrian      ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
42736285Sbrian
42831195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
42931962Sbrian      nb += sizeof tun - sizeof tun.data;
43036285Sbrian      nw = write(bundle->dev.fd, &tun, nb);
43135449Sbrian      if (nw != nb) {
43230092Sbrian        if (nw == -1)
43336285Sbrian	  log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
43430092Sbrian                    strerror(errno));
43530092Sbrian        else
43636285Sbrian	  log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
43735449Sbrian      }
43826031Sbrian
43926031Sbrian      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
44036285Sbrian	while ((fptr = (*PacketAlias.GetFragment)(tun.data)) != NULL) {
44136285Sbrian	  (*PacketAlias.FragmentIn)(tun.data, fptr);
44228679Sbrian	  nb = ntohs(((struct ip *) fptr)->ip_len);
44331962Sbrian          frag = (struct tun_data *)
44431962Sbrian	    ((char *)fptr - sizeof tun + sizeof tun.data);
44531962Sbrian          nb += sizeof tun - sizeof tun.data;
44636285Sbrian	  nw = write(bundle->dev.fd, frag, nb);
44735449Sbrian	  if (nw != nb) {
44830092Sbrian            if (nw == -1)
44936285Sbrian	      log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
45030092Sbrian                        strerror(errno));
45130092Sbrian            else
45236285Sbrian	      log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
45335449Sbrian          }
45431195Sbrian	  free(frag);
45528679Sbrian	}
45626031Sbrian      }
45728679Sbrian    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
45831195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
45931962Sbrian      nb += sizeof tun - sizeof tun.data;
46031195Sbrian      frag = (struct tun_data *)malloc(nb);
46131195Sbrian      if (frag == NULL)
46236285Sbrian	log_Printf(LogALERT, "ip_Input: Cannot allocate memory for fragment\n");
46326031Sbrian      else {
46431195Sbrian        tun_fill_header(*frag, AF_INET);
46531962Sbrian	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
46636285Sbrian	(*PacketAlias.SaveFragment)(frag->data);
46726031Sbrian      }
46826031Sbrian    }
46931343Sbrian  } else
47031343Sbrian#endif /* #ifndef NOALIAS */
47131343Sbrian  {			/* no aliasing */
47236285Sbrian    if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
47336285Sbrian      mbuf_Free(bp);
47426031Sbrian      return;
47526031Sbrian    }
47636285Sbrian
47736285Sbrian    if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
47836285Sbrian      bundle_StartIdleTimer(bundle);
47936285Sbrian
48036285Sbrian    ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
48136285Sbrian
48231962Sbrian    nb += sizeof tun - sizeof tun.data;
48336285Sbrian    nw = write(bundle->dev.fd, &tun, nb);
48434536Sbrian    if (nw != nb) {
48530092Sbrian      if (nw == -1)
48636285Sbrian	log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno));
48730092Sbrian      else
48836285Sbrian        log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
48934536Sbrian    }
4906059Samurai  }
49136285Sbrian  mbuf_Free(bp);
4926059Samurai}
4936059Samurai
49428679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1];
4956059Samurai
4966059Samuraivoid
49736285Sbrianip_Enqueue(int pri, char *ptr, int count)
4986059Samurai{
4996059Samurai  struct mbuf *bp;
5006059Samurai
50136285Sbrian  bp = mbuf_Alloc(count, MB_IPQ);
50230715Sbrian  memcpy(MBUF_CTOP(bp), ptr, count);
50336285Sbrian  mbuf_Enqueue(&IpOutputQueues[pri], bp);
5046059Samurai}
5056059Samurai
5068857Srgrimesint
50736285Sbrianip_QueueLen()
5087001Samurai{
5097001Samurai  struct mqueue *queue;
51036285Sbrian  int result = 0;
51128679Sbrian
51236285Sbrian  for (queue = &IpOutputQueues[PRI_MAX]; queue >= IpOutputQueues; queue--)
51336285Sbrian    result += queue->qlen;
51436285Sbrian
51536285Sbrian  return result;
5167001Samurai}
5177001Samurai
51836285Sbrianint
51936285Sbrianip_FlushPacket(struct link *l, struct bundle *bundle)
5206059Samurai{
5216059Samurai  struct mqueue *queue;
5226059Samurai  struct mbuf *bp;
52325630Sbrian  int cnt;
5246059Samurai
52536285Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED)
52636285Sbrian    return 0;
52736285Sbrian
52836285Sbrian  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--)
5296059Samurai    if (queue->top) {
53036285Sbrian      bp = mbuf_Dequeue(queue);
5316059Samurai      if (bp) {
53236285Sbrian        struct ip *pip = (struct ip *)MBUF_CTOP(bp);
53336285Sbrian
53436285Sbrian	cnt = mbuf_Length(bp);
53536285Sbrian	vj_SendFrame(l, bp, bundle);
53636285Sbrian        if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
53736285Sbrian          bundle_StartIdleTimer(bundle);
53836285Sbrian        ipcp_AddOutOctets(&bundle->ncp.ipcp, cnt);
53936285Sbrian	return 1;
54028679Sbrian      }
5416059Samurai    }
54236285Sbrian
54336285Sbrian  return 0;
5446059Samurai}
545