ip.c revision 36285
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 *
2036285Sbrian * $Id: ip.c,v 1.38.2.26 1998/05/06 23:50:11 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:
14028679Sbrian		cproto = P_UDP;
14128679Sbrian		uh = (struct udphdr *) ptop;
14228679Sbrian		sport = ntohs(uh->uh_sport);
14328679Sbrian		dport = ntohs(uh->uh_dport);
14436285Sbrian		estab = syn = finrst = -1;
14536285Sbrian                if (log_IsKept(LogDEBUG))
14636285Sbrian		  snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
14736285Sbrian                           sport, dport);
1486059Samurai		break;
1496059Samurai	      case IPPROTO_TCP:
15028679Sbrian		cproto = P_TCP;
15128679Sbrian		th = (struct tcphdr *) ptop;
15228679Sbrian		sport = ntohs(th->th_sport);
15328679Sbrian		dport = ntohs(th->th_dport);
1546059Samurai		estab = (th->th_flags & TH_ACK);
15536285Sbrian		syn = (th->th_flags & TH_SYN);
15636285Sbrian		finrst = (th->th_flags & (TH_FIN|TH_RST));
15736285Sbrian                if (log_IsKept(LogDEBUG) && !estab)
15836285Sbrian		  snprintf(dbuff, sizeof dbuff,
15936285Sbrian                           "flags = %02x, sport = %d, dport = %d",
16036285Sbrian                           th->th_flags, sport, dport);
1616059Samurai		break;
1626059Samurai	      default:
16336285Sbrian		return (A_DENY);       /* We'll block unknown type of packet */
1646059Samurai	      }
16536285Sbrian              if (log_IsKept(LogDEBUG)) {
16636285Sbrian                if (estab != -1) {
16736285Sbrian                  len = strlen(dbuff);
16836285Sbrian                  snprintf(dbuff + len, sizeof dbuff - len,
16936285Sbrian                           ", estab = %d, syn = %d, finrst = %d",
17036285Sbrian                           estab, syn, finrst);
17136285Sbrian                }
17236285Sbrian	        log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
17336285Sbrian                          filter_Proto2Nam(cproto), dbuff);
17436285Sbrian              }
1756059Samurai	      gotinfo = 1;
1766059Samurai	    }
17736285Sbrian            if (log_IsKept(LogDEBUG)) {
17836285Sbrian	      if (fp->opt.srcop != OP_NONE) {
17936285Sbrian                snprintf(dbuff, sizeof dbuff, ", src %s %d",
18036285Sbrian                         filter_Op2Nam(fp->opt.srcop), fp->opt.srcport);
18136285Sbrian                len = strlen(dbuff);
18236285Sbrian              } else
18336285Sbrian                len = 0;
18436285Sbrian	      if (fp->opt.dstop != OP_NONE) {
18536285Sbrian                snprintf(dbuff + len, sizeof dbuff - len,
18636285Sbrian                         ", dst %s %d", filter_Op2Nam(fp->opt.dstop),
18736285Sbrian                         fp->opt.dstport);
18836285Sbrian              } else if (!len)
18936285Sbrian                *dbuff = '\0';
19026516Sbrian
19136285Sbrian	      log_Printf(LogDEBUG, "  rule = %d: Address match, "
19236285Sbrian                        "check against proto %s%s, action = %s\n",
19336285Sbrian                        n, filter_Proto2Nam(fp->proto),
19436285Sbrian                        dbuff, filter_Action2Nam(fp->action));
19536285Sbrian            }
19636285Sbrian
1976059Samurai	    if (cproto == fp->proto) {
1986059Samurai	      if ((fp->opt.srcop == OP_NONE ||
19936285Sbrian		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) &&
2006059Samurai		  (fp->opt.dstop == OP_NONE ||
20136285Sbrian		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) &&
20236285Sbrian		  (fp->opt.estab == 0 || estab) &&
20336285Sbrian		  (fp->opt.syn == 0 || syn) &&
20436285Sbrian		  (fp->opt.finrst == 0 || finrst)) {
20528679Sbrian		return (fp->action);
2066059Samurai	      }
2076059Samurai	    }
2086059Samurai	  } else {
2096059Samurai	    /* Address is mached. Make a decision. */
21036285Sbrian	    log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
21136285Sbrian                      filter_Action2Nam(fp->action));
21228679Sbrian	    return (fp->action);
2136059Samurai	  }
21436285Sbrian	} else
21536285Sbrian	  log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
2166059Samurai      }
2176059Samurai      fp++;
2186059Samurai    }
21928679Sbrian    return (A_DENY);		/* No rule is mached. Deny this packet */
2206059Samurai  }
22128679Sbrian  return (A_PERMIT);		/* No rule is given. Permit this packet */
2226059Samurai}
2236059Samurai
22436285Sbrian#ifdef notdef
2256059Samuraistatic void
22628679SbrianIcmpError(struct ip * pip, int code)
2276059Samurai{
2286059Samurai  struct mbuf *bp;
2296059Samurai
2306059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
23136285Sbrian    bp = mbuf_Alloc(cnt, MB_IPIN);
23230715Sbrian    memcpy(MBUF_CTOP(bp), ptr, cnt);
23336285Sbrian    vj_SendFrame(bp);
23436285Sbrian    ipcp_AddOutOctets(cnt);
2356059Samurai  }
23636285Sbrian}
2376059Samurai#endif
2386059Samurai
2396059Samurai/*
2406059Samurai *  For debugging aid.
2416059Samurai */
2426059Samuraiint
24336285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
2446059Samurai{
2456059Samurai  struct ip *pip;
2466059Samurai  struct tcphdr *th;
2476059Samurai  struct udphdr *uh;
2486059Samurai  struct icmp *icmph;
2496059Samurai  char *ptop;
2506059Samurai  int mask, len, n;
2516059Samurai  int pri = PRI_NORMAL;
25226692Sbrian  int logit, loglen;
25326692Sbrian  static char logbuf[200];
2546059Samurai
25536285Sbrian  logit = log_IsKept(LogTCPIP) && filter->logok;
25626692Sbrian  loglen = 0;
2576059Samurai
25828679Sbrian  pip = (struct ip *) cp;
2598857Srgrimes
26026692Sbrian  if (logit && loglen < sizeof logbuf) {
26136285Sbrian    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
26228679Sbrian    loglen += strlen(logbuf + loglen);
26326692Sbrian  }
2646059Samurai  ptop = (cp + (pip->ip_hl << 2));
2656059Samurai
2666059Samurai  switch (pip->ip_p) {
2676059Samurai  case IPPROTO_ICMP:
26826692Sbrian    if (logit && loglen < sizeof logbuf) {
26928679Sbrian      icmph = (struct icmp *) ptop;
27028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
27128679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
27228679Sbrian      loglen += strlen(logbuf + loglen);
27328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
27428679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
27528679Sbrian      loglen += strlen(logbuf + loglen);
2766059Samurai    }
2776059Samurai    break;
2786059Samurai  case IPPROTO_UDP:
27926692Sbrian    if (logit && loglen < sizeof logbuf) {
28028679Sbrian      uh = (struct udphdr *) ptop;
28128679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
28228679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
28328679Sbrian      loglen += strlen(logbuf + loglen);
28428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
28528679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
28628679Sbrian      loglen += strlen(logbuf + loglen);
2876059Samurai    }
2886059Samurai    break;
2896059Samurai  case IPPROTO_TCP:
29028679Sbrian    th = (struct tcphdr *) ptop;
2916059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
2926059Samurai      pri = PRI_FAST;
29313733Sdfr    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
2946059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
29528679Sbrian	pri = PRI_FAST;
2966059Samurai    }
29726692Sbrian    if (logit && loglen < sizeof logbuf) {
2986059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
29928679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
30028679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
30128679Sbrian      loglen += strlen(logbuf + loglen);
30228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
30328679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
30428679Sbrian      loglen += strlen(logbuf + loglen);
3056059Samurai      n = 0;
3066059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
30726692Sbrian	if (th->th_flags & mask) {
30828679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
30928679Sbrian	  loglen += strlen(logbuf + loglen);
31028679Sbrian	}
3116059Samurai	n++;
3126059Samurai      }
31328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
31428679Sbrian	       "  seq:%x  ack:%x (%d/%d)",
31528679Sbrian	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
31628679Sbrian      loglen += strlen(logbuf + loglen);
3176059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
31828679Sbrian	u_short *sp;
3196059Samurai
3206059Samurai	ptop += 20;
32128679Sbrian	sp = (u_short *) ptop;
32226692Sbrian	if (ntohs(sp[0]) == 0x0204) {
32328679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
32428679Sbrian		   " MSS = %d", ntohs(sp[1]));
32528679Sbrian	  loglen += strlen(logbuf + loglen);
32628679Sbrian	}
3276059Samurai      }
3286059Samurai    }
3296059Samurai    break;
3306059Samurai  }
33126692Sbrian
33236285Sbrian  if ((FilterCheck(pip, filter) & A_DENY)) {
33331142Sbrian    if (logit)
33436285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
33536285Sbrian#ifdef notdef
33628679Sbrian    if (direction == 0)
33728679Sbrian      IcmpError(pip, pri);
33836285Sbrian#endif
33928679Sbrian    return (-1);
3406059Samurai  } else {
34136285Sbrian    /* Check Keep Alive filter */
34236285Sbrian    if (logit) {
34336285Sbrian      if (FilterCheck(pip, &bundle->filter.alive) & A_DENY)
34436285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
34536285Sbrian      else
34636285Sbrian        log_Printf(LogTCPIP, "%s\n", logbuf);
3476735Samurai    }
34828679Sbrian    return (pri);
3496059Samurai  }
3506059Samurai}
3516059Samurai
3526059Samuraivoid
35336285Sbrianip_Input(struct bundle *bundle, struct mbuf * bp)
35436285Sbrian{
3556059Samurai  u_char *cp;
3566059Samurai  struct mbuf *wp;
3576059Samurai  int nb, nw;
35831343Sbrian  struct tun_data tun;
35936285Sbrian  struct ip *pip = (struct ip *)tun.data;
3606059Samurai
36131195Sbrian  tun_fill_header(tun, AF_INET);
36231195Sbrian  cp = tun.data;
3636059Samurai  nb = 0;
36428679Sbrian  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
36532247Sbrian    if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
36636285Sbrian      log_Printf(LogERROR, "ip_Input: Packet too large (%d) - dropped\n",
36736285Sbrian                mbuf_Length(bp));
36836285Sbrian      mbuf_Free(bp);
36932247Sbrian      return;
37032247Sbrian    }
37130715Sbrian    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
3726059Samurai    cp += wp->cnt;
3736059Samurai    nb += wp->cnt;
3746059Samurai  }
3756059Samurai
37631343Sbrian#ifndef NOALIAS
37736285Sbrian  if (alias_IsEnabled()) {
37831343Sbrian    struct tun_data *frag;
37926031Sbrian    int iresult;
38026031Sbrian    char *fptr;
38126031Sbrian
38236285Sbrian    iresult = (*PacketAlias.In)(tun.data, sizeof tun.data);
38331195Sbrian    nb = ntohs(((struct ip *) tun.data)->ip_len);
38426031Sbrian
38526031Sbrian    if (nb > MAX_MRU) {
38636285Sbrian      log_Printf(LogERROR, "ip_Input: Problem with IP header length\n");
38736285Sbrian      mbuf_Free(bp);
38826031Sbrian      return;
38926031Sbrian    }
39026031Sbrian    if (iresult == PKT_ALIAS_OK
39128679Sbrian	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
39236285Sbrian      if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
39336285Sbrian	mbuf_Free(bp);
39428679Sbrian	return;
39526031Sbrian      }
39626031Sbrian
39736285Sbrian      if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
39836285Sbrian        bundle_StartIdleTimer(bundle);
39936285Sbrian
40036285Sbrian      ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
40136285Sbrian
40231195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
40331962Sbrian      nb += sizeof tun - sizeof tun.data;
40436285Sbrian      nw = write(bundle->dev.fd, &tun, nb);
40535449Sbrian      if (nw != nb) {
40630092Sbrian        if (nw == -1)
40736285Sbrian	  log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
40830092Sbrian                    strerror(errno));
40930092Sbrian        else
41036285Sbrian	  log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
41135449Sbrian      }
41226031Sbrian
41326031Sbrian      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
41436285Sbrian	while ((fptr = (*PacketAlias.GetFragment)(tun.data)) != NULL) {
41536285Sbrian	  (*PacketAlias.FragmentIn)(tun.data, fptr);
41628679Sbrian	  nb = ntohs(((struct ip *) fptr)->ip_len);
41731962Sbrian          frag = (struct tun_data *)
41831962Sbrian	    ((char *)fptr - sizeof tun + sizeof tun.data);
41931962Sbrian          nb += sizeof tun - sizeof tun.data;
42036285Sbrian	  nw = write(bundle->dev.fd, frag, nb);
42135449Sbrian	  if (nw != nb) {
42230092Sbrian            if (nw == -1)
42336285Sbrian	      log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
42430092Sbrian                        strerror(errno));
42530092Sbrian            else
42636285Sbrian	      log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
42735449Sbrian          }
42831195Sbrian	  free(frag);
42928679Sbrian	}
43026031Sbrian      }
43128679Sbrian    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
43231195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
43331962Sbrian      nb += sizeof tun - sizeof tun.data;
43431195Sbrian      frag = (struct tun_data *)malloc(nb);
43531195Sbrian      if (frag == NULL)
43636285Sbrian	log_Printf(LogALERT, "ip_Input: Cannot allocate memory for fragment\n");
43726031Sbrian      else {
43831195Sbrian        tun_fill_header(*frag, AF_INET);
43931962Sbrian	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
44036285Sbrian	(*PacketAlias.SaveFragment)(frag->data);
44126031Sbrian      }
44226031Sbrian    }
44331343Sbrian  } else
44431343Sbrian#endif /* #ifndef NOALIAS */
44531343Sbrian  {			/* no aliasing */
44636285Sbrian    if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
44736285Sbrian      mbuf_Free(bp);
44826031Sbrian      return;
44926031Sbrian    }
45036285Sbrian
45136285Sbrian    if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
45236285Sbrian      bundle_StartIdleTimer(bundle);
45336285Sbrian
45436285Sbrian    ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
45536285Sbrian
45631962Sbrian    nb += sizeof tun - sizeof tun.data;
45736285Sbrian    nw = write(bundle->dev.fd, &tun, nb);
45834536Sbrian    if (nw != nb) {
45930092Sbrian      if (nw == -1)
46036285Sbrian	log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno));
46130092Sbrian      else
46236285Sbrian        log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
46334536Sbrian    }
4646059Samurai  }
46536285Sbrian  mbuf_Free(bp);
4666059Samurai}
4676059Samurai
46828679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1];
4696059Samurai
4706059Samuraivoid
47136285Sbrianip_Enqueue(int pri, char *ptr, int count)
4726059Samurai{
4736059Samurai  struct mbuf *bp;
4746059Samurai
47536285Sbrian  bp = mbuf_Alloc(count, MB_IPQ);
47630715Sbrian  memcpy(MBUF_CTOP(bp), ptr, count);
47736285Sbrian  mbuf_Enqueue(&IpOutputQueues[pri], bp);
4786059Samurai}
4796059Samurai
4808857Srgrimesint
48136285Sbrianip_QueueLen()
4827001Samurai{
4837001Samurai  struct mqueue *queue;
48436285Sbrian  int result = 0;
48528679Sbrian
48636285Sbrian  for (queue = &IpOutputQueues[PRI_MAX]; queue >= IpOutputQueues; queue--)
48736285Sbrian    result += queue->qlen;
48836285Sbrian
48936285Sbrian  return result;
4907001Samurai}
4917001Samurai
49236285Sbrianint
49336285Sbrianip_FlushPacket(struct link *l, struct bundle *bundle)
4946059Samurai{
4956059Samurai  struct mqueue *queue;
4966059Samurai  struct mbuf *bp;
49725630Sbrian  int cnt;
4986059Samurai
49936285Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED)
50036285Sbrian    return 0;
50136285Sbrian
50236285Sbrian  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--)
5036059Samurai    if (queue->top) {
50436285Sbrian      bp = mbuf_Dequeue(queue);
5056059Samurai      if (bp) {
50636285Sbrian        struct ip *pip = (struct ip *)MBUF_CTOP(bp);
50736285Sbrian
50836285Sbrian	cnt = mbuf_Length(bp);
50936285Sbrian	vj_SendFrame(l, bp, bundle);
51036285Sbrian        if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
51136285Sbrian          bundle_StartIdleTimer(bundle);
51236285Sbrian        ipcp_AddOutOctets(&bundle->ncp.ipcp, cnt);
51336285Sbrian	return 1;
51428679Sbrian      }
5156059Samurai    }
51636285Sbrian
51736285Sbrian  return 0;
5186059Samurai}
519