ip.c revision 37192
169783Smsmith/*
2281887Sjhb *		PPP IP Protocol Interface
3223520Sjhb *
469783Smsmith *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
569783Smsmith *
669783Smsmith *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
769783Smsmith *
869783Smsmith * Redistribution and use in source and binary forms are permitted
969783Smsmith * provided that the above copyright notice and this paragraph are
1069783Smsmith * duplicated in all such forms and that any documentation,
1169783Smsmith * advertising materials, and other materials related to such
1269783Smsmith * distribution and use acknowledge that the software was developed
1369783Smsmith * by the Internet Initiative Japan.  The name of the
1469783Smsmith * IIJ may not be used to endorse or promote products derived
1569783Smsmith * from this software without specific prior written permission.
1669783Smsmith * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1769783Smsmith * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1869783Smsmith * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1969783Smsmith *
2069783Smsmith * $Id: ip.c,v 1.46 1998/06/27 14:17:26 brian Exp $
2169783Smsmith *
2269783Smsmith *	TODO:
2369783Smsmith *		o Return ICMP message for filterd packet
2469783Smsmith *		  and optionaly record it into log.
2569783Smsmith */
2669783Smsmith#include <sys/types.h>
2769783Smsmith#include <sys/socket.h>
28119418Sobrien#include <netinet/in.h>
29119418Sobrien#include <netinet/in_systm.h>
30119418Sobrien#include <netinet/ip.h>
3169783Smsmith#include <netinet/ip_icmp.h>
32223520Sjhb#include <netinet/udp.h>
33223520Sjhb#include <netinet/tcp.h>
3469783Smsmith#include <arpa/inet.h>
3569783Smsmith#include <sys/un.h>
36224069Sjhb
37221393Sjhb#ifndef NOALIAS
38261790Sjhb#include <alias.h>
39107546Simp#endif
40224069Sjhb#include <errno.h>
4169783Smsmith#include <stdio.h>
42223520Sjhb#include <stdlib.h>
43119285Simp#include <string.h>
44119285Simp#include <unistd.h>
4569783Smsmith
4669783Smsmith#include "mbuf.h"
47107172Sjhb#include "log.h"
48107172Sjhb#include "defs.h"
49107172Sjhb#include "timer.h"
50107172Sjhb#include "fsm.h"
51107172Sjhb#include "lqr.h"
52119266Simp#include "hdlc.h"
53107172Sjhb#include "throughput.h"
54119266Simp#include "iplist.h"
55107172Sjhb#include "slcompress.h"
56107172Sjhb#include "ipcp.h"
57107248Sjhb#include "filter.h"
58107172Sjhb#include "descriptor.h"
59107172Sjhb#include "lcp.h"
60107172Sjhb#include "ccp.h"
61107172Sjhb#include "link.h"
62107172Sjhb#include "mp.h"
63107172Sjhb#include "bundle.h"
64107172Sjhb#include "vjcomp.h"
65107172Sjhb#include "tun.h"
66107172Sjhb#include "ip.h"
67107172Sjhb
68107172Sjhbstatic const u_short interactive_ports[32] = {
69107172Sjhb  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70107172Sjhb  0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
71107172Sjhb};
72107172Sjhb
73107172Sjhb#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
74107172Sjhb
75107172Sjhbstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
76107172Sjhb
77107172Sjhbstatic int
78107172SjhbPortMatch(int op, u_short pport, u_short rport)
79107172Sjhb{
80107172Sjhb  switch (op) {
81107172Sjhb    case OP_EQ:
82107172Sjhb    return (pport == rport);
83107172Sjhb  case OP_GT:
84107172Sjhb    return (pport > rport);
85107172Sjhb  case OP_LT:
86107172Sjhb    return (pport < rport);
87107172Sjhb  default:
88107248Sjhb    return (0);
89107172Sjhb  }
90107172Sjhb}
91107172Sjhb
92107248Sjhb/*
93107172Sjhb *  Check a packet against with defined filters
94107172Sjhb */
95107172Sjhbstatic int
96107248SjhbFilterCheck(struct ip *pip, struct filter *filter)
97107172Sjhb{
98107172Sjhb  int gotinfo, cproto, estab, syn, finrst, n, len, didname;
99107172Sjhb  struct tcphdr *th;
100107248Sjhb  struct udphdr *uh;
101107172Sjhb  struct icmp *ih;
102107172Sjhb  char *ptop;
103107172Sjhb  u_short sport, dport;
104107172Sjhb  struct filterent *fp = filter->rule;
105107172Sjhb  char dbuff[100];
106107172Sjhb
107107172Sjhb  if (fp->action) {
108107172Sjhb    cproto = gotinfo = estab = syn = finrst = didname = 0;
109107172Sjhb    sport = dport = 0;
110107172Sjhb    for (n = 0; n < MAXFILTERS; n++) {
111107172Sjhb      if (fp->action) {
112107172Sjhb	/* permit fragments on in and out filter */
113107172Sjhb        if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0)
114107172Sjhb	  return (A_PERMIT);
115215820Sjhb
116107172Sjhb        if (!didname)
117215820Sjhb          log_Printf(LogDEBUG, "%s filter:\n", filter->name);
118107172Sjhb        didname = 1;
119107172Sjhb
120107172Sjhb	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
121144110Sjhb	    (fp->saddr.s_addr & fp->smask.s_addr) &&
122144110Sjhb	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
123144110Sjhb	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
124144110Sjhb	  if (fp->proto) {
125144110Sjhb	    if (!gotinfo) {
126107172Sjhb	      ptop = (char *) pip + (pip->ip_hl << 2);
127107172Sjhb
128107172Sjhb	      switch (pip->ip_p) {
129107172Sjhb	      case IPPROTO_ICMP:
130107172Sjhb		cproto = P_ICMP;
131107172Sjhb		ih = (struct icmp *) ptop;
132107172Sjhb		sport = ih->icmp_type;
133224069Sjhb		estab = syn = finrst = -1;
134224069Sjhb                if (log_IsKept(LogDEBUG))
135224069Sjhb		  snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
136224069Sjhb		break;
137224069Sjhb	      case IPPROTO_UDP:
138224069Sjhb	      case IPPROTO_IGMP:
139224069Sjhb	      case IPPROTO_IPIP:
140224069Sjhb		cproto = P_UDP;
141224069Sjhb		uh = (struct udphdr *) ptop;
142224069Sjhb		sport = ntohs(uh->uh_sport);
143224069Sjhb		dport = ntohs(uh->uh_dport);
144224069Sjhb		estab = syn = finrst = -1;
145224069Sjhb                if (log_IsKept(LogDEBUG))
146224069Sjhb		  snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
147224069Sjhb                           sport, dport);
148224069Sjhb		break;
149224069Sjhb	      case IPPROTO_TCP:
150224069Sjhb		cproto = P_TCP;
151224069Sjhb		th = (struct tcphdr *) ptop;
152224069Sjhb		sport = ntohs(th->th_sport);
153224069Sjhb		dport = ntohs(th->th_dport);
154224069Sjhb		estab = (th->th_flags & TH_ACK);
155261523Sjhb		syn = (th->th_flags & TH_SYN);
156224069Sjhb		finrst = (th->th_flags & (TH_FIN|TH_RST));
157224069Sjhb                if (log_IsKept(LogDEBUG) && !estab)
158224069Sjhb		  snprintf(dbuff, sizeof dbuff,
159224069Sjhb                           "flags = %02x, sport = %d, dport = %d",
160224069Sjhb                           th->th_flags, sport, dport);
161224069Sjhb		break;
162224069Sjhb	      default:
163224069Sjhb		return (A_DENY);       /* We'll block unknown type of packet */
164224069Sjhb	      }
165224069Sjhb              if (log_IsKept(LogDEBUG)) {
166224069Sjhb                if (estab != -1) {
167224069Sjhb                  len = strlen(dbuff);
168224069Sjhb                  snprintf(dbuff + len, sizeof dbuff - len,
169224069Sjhb                           ", estab = %d, syn = %d, finrst = %d",
170224069Sjhb                           estab, syn, finrst);
171224069Sjhb                }
172224069Sjhb	        log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
173224069Sjhb                          filter_Proto2Nam(cproto), dbuff);
174224069Sjhb              }
175224069Sjhb	      gotinfo = 1;
176224069Sjhb	    }
177224069Sjhb            if (log_IsKept(LogDEBUG)) {
178224069Sjhb	      if (fp->opt.srcop != OP_NONE) {
179224069Sjhb                snprintf(dbuff, sizeof dbuff, ", src %s %d",
180224069Sjhb                         filter_Op2Nam(fp->opt.srcop), fp->opt.srcport);
181224069Sjhb                len = strlen(dbuff);
182224069Sjhb              } else
183224069Sjhb                len = 0;
184224069Sjhb	      if (fp->opt.dstop != OP_NONE) {
185224069Sjhb                snprintf(dbuff + len, sizeof dbuff - len,
186224069Sjhb                         ", dst %s %d", filter_Op2Nam(fp->opt.dstop),
187224069Sjhb                         fp->opt.dstport);
188224069Sjhb              } else if (!len)
189224069Sjhb                *dbuff = '\0';
190224069Sjhb
191224069Sjhb	      log_Printf(LogDEBUG, "  rule = %d: Address match, "
192224069Sjhb                        "check against proto %s%s, action = %s\n",
193224069Sjhb                        n, filter_Proto2Nam(fp->proto),
194224069Sjhb                        dbuff, filter_Action2Nam(fp->action));
195224069Sjhb            }
196224069Sjhb
197224069Sjhb	    if (cproto == fp->proto) {
198224069Sjhb	      if ((fp->opt.srcop == OP_NONE ||
199224069Sjhb		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) &&
200224069Sjhb		  (fp->opt.dstop == OP_NONE ||
201224069Sjhb		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) &&
202224069Sjhb		  (fp->opt.estab == 0 || estab) &&
203224069Sjhb		  (fp->opt.syn == 0 || syn) &&
204224069Sjhb		  (fp->opt.finrst == 0 || finrst)) {
205224069Sjhb		return (fp->action);
206224069Sjhb	      }
207224069Sjhb	    }
208224069Sjhb	  } else {
209224069Sjhb	    /* Address is mached. Make a decision. */
210224069Sjhb	    log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
211224069Sjhb                      filter_Action2Nam(fp->action));
212224069Sjhb	    return (fp->action);
213224069Sjhb	  }
214224069Sjhb	} else
215224069Sjhb	  log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
216224069Sjhb      }
217224069Sjhb      fp++;
218224069Sjhb    }
219224069Sjhb    return (A_DENY);		/* No rule is mached. Deny this packet */
220224069Sjhb  }
221224069Sjhb  return (A_PERMIT);		/* No rule is given. Permit this packet */
222224069Sjhb}
223224069Sjhb
224224069Sjhb#ifdef notdef
225224069Sjhbstatic void
226224069SjhbIcmpError(struct ip * pip, int code)
227224069Sjhb{
228224069Sjhb  struct mbuf *bp;
229224069Sjhb
230224069Sjhb  if (pip->ip_p != IPPROTO_ICMP) {
231224069Sjhb    bp = mbuf_Alloc(cnt, MB_IPIN);
232224069Sjhb    memcpy(MBUF_CTOP(bp), ptr, cnt);
233224069Sjhb    vj_SendFrame(bp);
234224069Sjhb    ipcp_AddOutOctets(cnt);
235224069Sjhb  }
236224069Sjhb}
237224069Sjhb#endif
238224069Sjhb
239224069Sjhb/*
240224069Sjhb *  For debugging aid.
241224069Sjhb */
242224069Sjhbint
243224069SjhbPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
244224069Sjhb{
245224069Sjhb  struct ip *pip;
246224069Sjhb  struct tcphdr *th;
247224069Sjhb  struct udphdr *uh;
248224069Sjhb  struct icmp *icmph;
249224069Sjhb  char *ptop;
250224069Sjhb  int mask, len, n;
251224069Sjhb  int pri = PRI_NORMAL;
252224069Sjhb  int logit, loglen;
253224069Sjhb  char logbuf[200];
254224069Sjhb
255224069Sjhb  logit = log_IsKept(LogTCPIP) && filter->logok;
256224069Sjhb  loglen = 0;
257224069Sjhb
258224069Sjhb  pip = (struct ip *) cp;
259224069Sjhb
260224069Sjhb  if (logit && loglen < sizeof logbuf) {
261224069Sjhb    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
262224069Sjhb    loglen += strlen(logbuf + loglen);
263224069Sjhb  }
264224069Sjhb  ptop = (cp + (pip->ip_hl << 2));
265224069Sjhb
266224069Sjhb  switch (pip->ip_p) {
267224069Sjhb  case IPPROTO_ICMP:
268224069Sjhb    if (logit && loglen < sizeof logbuf) {
269224069Sjhb      icmph = (struct icmp *) ptop;
270224069Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
271224069Sjhb	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
272224069Sjhb      loglen += strlen(logbuf + loglen);
273224069Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
274224069Sjhb	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
275224069Sjhb      loglen += strlen(logbuf + loglen);
276224069Sjhb    }
277224069Sjhb    break;
278224069Sjhb  case IPPROTO_UDP:
279224069Sjhb    if (logit && loglen < sizeof logbuf) {
280224069Sjhb      uh = (struct udphdr *) ptop;
281224069Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
282224069Sjhb	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
283224069Sjhb      loglen += strlen(logbuf + loglen);
284224069Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
285224069Sjhb	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
286261790Sjhb      loglen += strlen(logbuf + loglen);
287261790Sjhb    }
288261790Sjhb    break;
289261790Sjhb  case IPPROTO_IPIP:
290261790Sjhb    if (logit && loglen < sizeof logbuf) {
291261790Sjhb      uh = (struct udphdr *) ptop;
292261790Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
293261790Sjhb	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
294261790Sjhb      loglen += strlen(logbuf + loglen);
295261790Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
296261790Sjhb	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
297261790Sjhb      loglen += strlen(logbuf + loglen);
298261790Sjhb    }
299261790Sjhb    break;
300261790Sjhb  case IPPROTO_IGMP:
301261790Sjhb    if (logit && loglen < sizeof logbuf) {
302261790Sjhb      uh = (struct udphdr *) ptop;
303261790Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
304261790Sjhb	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
305261790Sjhb      loglen += strlen(logbuf + loglen);
306261790Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
307261790Sjhb	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
308261790Sjhb      loglen += strlen(logbuf + loglen);
309261790Sjhb    }
310261790Sjhb    break;
311261790Sjhb  case IPPROTO_TCP:
312261790Sjhb    th = (struct tcphdr *) ptop;
313261790Sjhb    if (pip->ip_tos == IPTOS_LOWDELAY)
314261790Sjhb      pri = PRI_FAST;
315261790Sjhb    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
316261790Sjhb      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
317261790Sjhb	pri = PRI_FAST;
318261790Sjhb    }
319261790Sjhb    if (logit && loglen < sizeof logbuf) {
320261790Sjhb      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
321261790Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
322261790Sjhb	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
323261790Sjhb      loglen += strlen(logbuf + loglen);
324261790Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
325261790Sjhb	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
326261790Sjhb      loglen += strlen(logbuf + loglen);
327261790Sjhb      n = 0;
328261790Sjhb      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
329261790Sjhb	if (th->th_flags & mask) {
330261790Sjhb	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
331261790Sjhb	  loglen += strlen(logbuf + loglen);
332261790Sjhb	}
333261790Sjhb	n++;
334261790Sjhb      }
335261790Sjhb      snprintf(logbuf + loglen, sizeof logbuf - loglen,
336261790Sjhb	       "  seq:%x  ack:%x (%d/%d)",
337261790Sjhb	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
338261790Sjhb      loglen += strlen(logbuf + loglen);
339261790Sjhb      if ((th->th_flags & TH_SYN) && nb > 40) {
340261790Sjhb	u_short *sp;
341261790Sjhb
342261790Sjhb	ptop += 20;
343261790Sjhb	sp = (u_short *) ptop;
344261790Sjhb	if (ntohs(sp[0]) == 0x0204) {
345261790Sjhb	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
346261790Sjhb		   " MSS = %d", ntohs(sp[1]));
347261790Sjhb	  loglen += strlen(logbuf + loglen);
348261790Sjhb	}
349261790Sjhb      }
350261790Sjhb    }
351261790Sjhb    break;
352261790Sjhb  }
353261790Sjhb
354261790Sjhb  if ((FilterCheck(pip, filter) & A_DENY)) {
355261790Sjhb    if (logit)
356261790Sjhb      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
357261790Sjhb#ifdef notdef
358261790Sjhb    if (direction == 0)
359261790Sjhb      IcmpError(pip, pri);
360261790Sjhb#endif
361261790Sjhb    return (-1);
362261790Sjhb  } else {
363261790Sjhb    /* Check Keep Alive filter */
364261790Sjhb    if (logit) {
365261790Sjhb      if (FilterCheck(pip, &bundle->filter.alive) & A_DENY)
366261790Sjhb        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
367261790Sjhb      else
368261790Sjhb        log_Printf(LogTCPIP, "%s\n", logbuf);
369261790Sjhb    }
370261790Sjhb    return (pri);
371261790Sjhb  }
372261790Sjhb}
373261790Sjhb
374261790Sjhbvoid
375261790Sjhbip_Input(struct bundle *bundle, struct mbuf * bp)
376261790Sjhb{
377261790Sjhb  u_char *cp;
378261790Sjhb  struct mbuf *wp;
379261790Sjhb  int nb, nw;
380261790Sjhb  struct tun_data tun;
381261790Sjhb  struct ip *pip = (struct ip *)tun.data;
382261790Sjhb  struct ip *piip = (struct ip *)((char *)pip + (pip->ip_hl << 2));
383261790Sjhb
384224069Sjhb  tun_fill_header(tun, AF_INET);
385  cp = tun.data;
386  nb = 0;
387  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
388    if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
389      log_Printf(LogWARN, "ip_Input: Packet too large (%d) - dropped\n",
390                mbuf_Length(bp));
391      mbuf_Free(bp);
392      return;
393    }
394    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
395    cp += wp->cnt;
396    nb += wp->cnt;
397  }
398
399#ifndef NOALIAS
400  if (bundle->AliasEnabled && pip->ip_p != IPPROTO_IGMP &&
401      (pip->ip_p != IPPROTO_IPIP || !IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) {
402    struct tun_data *frag;
403    int iresult;
404    char *fptr;
405
406    iresult = PacketAliasIn(tun.data, sizeof tun.data);
407    nb = ntohs(((struct ip *) tun.data)->ip_len);
408
409    if (nb > MAX_MRU) {
410      log_Printf(LogWARN, "ip_Input: Problem with IP header length\n");
411      mbuf_Free(bp);
412      return;
413    }
414    if (iresult == PKT_ALIAS_OK
415	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
416      if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
417	mbuf_Free(bp);
418	return;
419      }
420
421      if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
422        bundle_StartIdleTimer(bundle);
423
424      ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
425
426      nb = ntohs(((struct ip *) tun.data)->ip_len);
427      nb += sizeof tun - sizeof tun.data;
428      nw = write(bundle->dev.fd, &tun, nb);
429      if (nw != nb) {
430        if (nw == -1)
431	  log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
432                    strerror(errno));
433        else
434	  log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
435      }
436
437      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
438	while ((fptr = PacketAliasGetFragment(tun.data)) != NULL) {
439	  PacketAliasFragmentIn(tun.data, fptr);
440	  nb = ntohs(((struct ip *) fptr)->ip_len);
441          frag = (struct tun_data *)
442	    ((char *)fptr - sizeof tun + sizeof tun.data);
443          nb += sizeof tun - sizeof tun.data;
444	  nw = write(bundle->dev.fd, frag, nb);
445	  if (nw != nb) {
446            if (nw == -1)
447	      log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
448                        strerror(errno));
449            else
450	      log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
451          }
452	  free(frag);
453	}
454      }
455    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
456      nb = ntohs(((struct ip *) tun.data)->ip_len);
457      nb += sizeof tun - sizeof tun.data;
458      frag = (struct tun_data *)malloc(nb);
459      if (frag == NULL)
460	log_Printf(LogALERT, "ip_Input: Cannot allocate memory for fragment\n");
461      else {
462        tun_fill_header(*frag, AF_INET);
463	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
464	PacketAliasSaveFragment(frag->data);
465      }
466    }
467  } else
468#endif /* #ifndef NOALIAS */
469  {			/* no aliasing */
470    if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
471      mbuf_Free(bp);
472      return;
473    }
474
475    if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
476      bundle_StartIdleTimer(bundle);
477
478    ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
479
480    nb += sizeof tun - sizeof tun.data;
481    nw = write(bundle->dev.fd, &tun, nb);
482    if (nw != nb) {
483      if (nw == -1)
484	log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno));
485      else
486        log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
487    }
488  }
489  mbuf_Free(bp);
490}
491
492static struct mqueue IpOutputQueues[PRI_FAST + 1];
493
494void
495ip_Enqueue(int pri, char *ptr, int count)
496{
497  struct mbuf *bp;
498
499  bp = mbuf_Alloc(count, MB_IPQ);
500  memcpy(MBUF_CTOP(bp), ptr, count);
501  mbuf_Enqueue(&IpOutputQueues[pri], bp);
502}
503
504int
505ip_QueueLen()
506{
507  struct mqueue *queue;
508  int result = 0;
509
510  for (queue = &IpOutputQueues[PRI_MAX]; queue >= IpOutputQueues; queue--)
511    result += queue->qlen;
512
513  return result;
514}
515
516int
517ip_FlushPacket(struct link *l, struct bundle *bundle)
518{
519  struct mqueue *queue;
520  struct mbuf *bp;
521  int cnt;
522
523  if (bundle->ncp.ipcp.fsm.state != ST_OPENED)
524    return 0;
525
526  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--)
527    if (queue->top) {
528      bp = mbuf_Dequeue(queue);
529      if (bp) {
530        struct ip *pip = (struct ip *)MBUF_CTOP(bp);
531
532	cnt = mbuf_Length(bp);
533	vj_SendFrame(l, bp, bundle);
534        if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
535          bundle_StartIdleTimer(bundle);
536        ipcp_AddOutOctets(&bundle->ncp.ipcp, cnt);
537	return 1;
538      }
539    }
540
541  return 0;
542}
543