ip.c revision 49472
131567Ssef/*
231899Ssef *		PPP IP Protocol Interface
331899Ssef *
431899Ssef *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
531899Ssef *
631899Ssef *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
731899Ssef *
831899Ssef * Redistribution and use in source and binary forms are permitted
931899Ssef * provided that the above copyright notice and this paragraph are
1031899Ssef * duplicated in all such forms and that any documentation,
1131899Ssef * advertising materials, and other materials related to such
1231899Ssef * distribution and use acknowledge that the software was developed
1331899Ssef * by the Internet Initiative Japan.  The name of the
1431899Ssef * IIJ may not be used to endorse or promote products derived
1531899Ssef * from this software without specific prior written permission.
1631899Ssef * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1731899Ssef * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1831899Ssef * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1931899Ssef *
2031899Ssef * $Id: ip.c,v 1.67 1999/08/02 15:29:19 brian Exp $
2131899Ssef *
2231899Ssef *	TODO:
2331899Ssef *		o Return ICMP message for filterd packet
2431899Ssef *		  and optionaly record it into log.
2531899Ssef */
2631899Ssef#include <sys/param.h>
2731899Ssef#if defined(__OpenBSD__) || defined(__NetBSD__)
2831899Ssef#include <sys/socket.h>
2931899Ssef#endif
3031899Ssef#include <netinet/in.h>
3131899Ssef#include <netinet/in_systm.h>
3232275Scharnier#include <netinet/ip.h>
3332275Scharnier#include <netinet/ip_icmp.h>
3438897Ssef#include <netinet/udp.h>
3532275Scharnier#include <netinet/tcp.h>
3632275Scharnier#include <arpa/inet.h>
3731899Ssef#include <sys/un.h>
3831567Ssef
3931567Ssef#include <errno.h>
4031567Ssef#include <stdio.h>
4131567Ssef#include <string.h>
4231567Ssef#include <termios.h>
4332275Scharnier#include <unistd.h>
4432275Scharnier
4532275Scharnier#include "layer.h"
4632275Scharnier#include "proto.h"
4731567Ssef#include "mbuf.h"
4831567Ssef#include "log.h"
4931567Ssef#include "defs.h"
5031579Speter#include "timer.h"
5131567Ssef#include "fsm.h"
5231567Ssef#include "lqr.h"
5331567Ssef#include "hdlc.h"
5431567Ssef#include "throughput.h"
5531567Ssef#include "iplist.h"
5631567Ssef#include "slcompress.h"
5731567Ssef#include "ipcp.h"
5831567Ssef#include "filter.h"
5931567Ssef#include "descriptor.h"
6031567Ssef#include "lcp.h"
6131567Ssef#include "ccp.h"
6231567Ssef#include "link.h"
6331567Ssef#include "mp.h"
6431567Ssef#ifndef NORADIUS
6531567Ssef#include "radius.h"
6631567Ssef#endif
6731567Ssef#include "bundle.h"
6831567Ssef#include "tun.h"
6931567Ssef#include "ip.h"
7031567Ssef
7131567Ssefstatic const u_short interactive_ports[32] = {
7231567Ssef  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7332275Scharnier  80, 81, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
7432275Scharnier};
7532275Scharnier
7632275Scharnier#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
7732275Scharnier
7831567Ssefstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
7931567Ssef
8031567Ssefstatic __inline int
8138897SsefPortMatch(int op, u_short pport, u_short rport)
8238897Ssef{
8338897Ssef  switch (op) {
8438897Ssef  case OP_EQ:
8531567Ssef    return (pport == rport);
8631567Ssef  case OP_GT:
8731567Ssef    return (pport > rport);
8831567Ssef  case OP_LT:
8931567Ssef    return (pport < rport);
9031567Ssef  default:
9131580Speter    return (0);
9231567Ssef  }
9331567Ssef}
9431567Ssef
9531567Ssef/*
9631567Ssef *  Check a packet against a defined filter
9731567Ssef *  Returns 0 to accept the packet, non-zero to drop the packet
9831567Ssef *
9931567Ssef *  If filtering is enabled, the initial fragment of a datagram must
10031567Ssef *  contain the complete protocol header, and subsequent fragments
10131567Ssef *  must not attempt to over-write it.
10231567Ssef */
10331567Ssefstatic int
10431567SsefFilterCheck(const struct ip *pip, const struct filter *filter)
10531567Ssef{
10631567Ssef  int gotinfo;			/* true if IP payload decoded */
10731567Ssef  int cproto;			/* P_* protocol type if (gotinfo) */
10831567Ssef  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
10931567Ssef  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
11031567Ssef  int n;			/* filter rule to process */
11131567Ssef  int len;			/* bytes used in dbuff */
11231567Ssef  int didname;			/* true if filter header printed */
11331567Ssef  int match;			/* true if condition matched */
11431567Ssef  const struct filterent *fp = filter->rule;
11531580Speter  char dbuff[100];
11631567Ssef
11731567Ssef  if (fp->f_action == A_NONE)
11831567Ssef    return (0);		/* No rule is given. Permit this packet */
11931567Ssef
12031567Ssef  /* Deny any packet fragment that tries to over-write the header.
12131567Ssef   * Since we no longer have the real header available, punt on the
12238897Ssef   * largest normal header - 20 bytes for TCP without options, rounded
12338897Ssef   * up to the next possible fragment boundary.  Since the smallest
12438897Ssef   * `legal' MTU is 576, and the smallest recommended MTU is 296, any
12538897Ssef   * fragmentation within this range is dubious at best */
12638897Ssef  len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
12731567Ssef  if (len > 0) {		/* Not first fragment within datagram */
12831567Ssef    if (len < (24 >> 3))	/* don't allow fragment to over-write header */
12931567Ssef      return (1);
13032275Scharnier    /* permit fragments on in and out filter */
13131567Ssef    return (filter->fragok);
13231567Ssef  }
13331567Ssef
13431567Ssef  cproto = gotinfo = estab = syn = finrst = didname = 0;
13531567Ssef  sport = dport = 0;
13631567Ssef  for (n = 0; n < MAXFILTERS; ) {
13731567Ssef    if (fp->f_action == A_NONE) {
13832275Scharnier      n++;
13938520Scracauer      fp++;
14031567Ssef      continue;
14132306Sjmg    }
14231567Ssef
14331567Ssef    if (!didname) {
14431567Ssef      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
14531567Ssef      didname = 1;
14631567Ssef    }
14732275Scharnier
14831567Ssef    match = 0;
14931567Ssef    if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
15031567Ssef	  fp->f_src.mask.s_addr) &&
15131567Ssef	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
15231567Ssef	  fp->f_dst.mask.s_addr)) {
15331567Ssef      if (fp->f_proto != P_NONE) {
15431567Ssef	if (!gotinfo) {
15531567Ssef	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
15631567Ssef	  const struct tcphdr *th;
15731567Ssef	  const struct udphdr *uh;
15831582Ssef	  const struct icmp *ih;
15931567Ssef	  int datalen;	/* IP datagram length */
16031567Ssef
16132275Scharnier	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
16232275Scharnier	  switch (pip->ip_p) {
16332275Scharnier	  case IPPROTO_ICMP:
16432275Scharnier	    cproto = P_ICMP;
16532275Scharnier	    if (datalen < 8)	/* ICMP must be at least 8 octets */
16631567Ssef	      return (1);
16731567Ssef	    ih = (const struct icmp *) ptop;
16831567Ssef	    sport = ih->icmp_type;
16931567Ssef	    estab = syn = finrst = -1;
17031567Ssef	    if (log_IsKept(LogDEBUG))
17131567Ssef	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
17231567Ssef	    break;
17331567Ssef	  case IPPROTO_IGMP:
17431567Ssef	    cproto = P_IGMP;
17531567Ssef	    if (datalen < 8)	/* IGMP uses 8-octet messages */
17631567Ssef	      return (1);
17731567Ssef	    estab = syn = finrst = -1;
17831567Ssef	    sport = ntohs(0);
17931567Ssef	    break;
18031567Ssef#ifdef IPPROTO_OSPFIGP
18131567Ssef	  case IPPROTO_OSPFIGP:
18231567Ssef	    cproto = P_OSPF;
18331567Ssef	    if (datalen < 8)	/* IGMP uses 8-octet messages */
18431567Ssef	      return (1);
18531567Ssef	    estab = syn = finrst = -1;
18631567Ssef	    sport = ntohs(0);
18731567Ssef	    break;
18831567Ssef#endif
18931567Ssef	  case IPPROTO_UDP:
19031567Ssef	  case IPPROTO_IPIP:
19131567Ssef	    cproto = P_UDP;
19231567Ssef	    if (datalen < 8)	/* UDP header is 8 octets */
19331567Ssef	      return (1);
19431567Ssef	    uh = (const struct udphdr *) ptop;
19531567Ssef	    sport = ntohs(uh->uh_sport);
19631567Ssef	    dport = ntohs(uh->uh_dport);
19731567Ssef	    estab = syn = finrst = -1;
19831567Ssef	    if (log_IsKept(LogDEBUG))
19931567Ssef	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
20031567Ssef		       sport, dport);
20131567Ssef	    break;
20231567Ssef	  case IPPROTO_TCP:
20331567Ssef	    cproto = P_TCP;
20431567Ssef	    th = (const struct tcphdr *) ptop;
20531567Ssef	    /* TCP headers are variable length.  The following code
20631567Ssef	     * ensures that the TCP header length isn't de-referenced if
20732275Scharnier	     * the datagram is too short
20831567Ssef	     */
20931567Ssef	    if (datalen < 20 || datalen < (th->th_off << 2))
21031567Ssef	      return (1);
21131567Ssef	    sport = ntohs(th->th_sport);
21231567Ssef	    dport = ntohs(th->th_dport);
21331567Ssef	    estab = (th->th_flags & TH_ACK);
21431567Ssef	    syn = (th->th_flags & TH_SYN);
21531567Ssef	    finrst = (th->th_flags & (TH_FIN|TH_RST));
21631567Ssef	    if (log_IsKept(LogDEBUG)) {
21731567Ssef	      if (!estab)
21831567Ssef		snprintf(dbuff, sizeof dbuff,
21931567Ssef			 "flags = %02x, sport = %d, dport = %d",
22031567Ssef			 th->th_flags, sport, dport);
22131567Ssef	      else
22231567Ssef		*dbuff = '\0';
22331567Ssef	    }
22431567Ssef	    break;
22531567Ssef	  default:
22631567Ssef	    return (1);	/* We'll block unknown type of packet */
22731567Ssef	  }
22837453Sbde
22938520Scracauer	  if (log_IsKept(LogDEBUG)) {
23031567Ssef	    if (estab != -1) {
23131567Ssef	      len = strlen(dbuff);
23237453Sbde	      snprintf(dbuff + len, sizeof dbuff - len,
23331567Ssef		       ", estab = %d, syn = %d, finrst = %d",
23431567Ssef		       estab, syn, finrst);
23531567Ssef	    }
23631567Ssef	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
23731567Ssef		       filter_Proto2Nam(cproto), dbuff);
23831567Ssef	  }
23931567Ssef	  gotinfo = 1;
24031567Ssef	}
24131567Ssef	if (log_IsKept(LogDEBUG)) {
24231567Ssef	  if (fp->f_srcop != OP_NONE) {
24331691Ssef	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
24432275Scharnier		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
24531567Ssef	    len = strlen(dbuff);
24638520Scracauer	  } else
24738520Scracauer	    len = 0;
24838520Scracauer	  if (fp->f_dstop != OP_NONE) {
24938520Scracauer	    snprintf(dbuff + len, sizeof dbuff - len,
25038520Scracauer		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
25138520Scracauer		     fp->f_dstport);
25231567Ssef	  } else if (!len)
25331567Ssef	    *dbuff = '\0';
254
255	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
256		     "check against proto %s%s, action = %s\n",
257		     n, filter_Proto2Nam(fp->f_proto),
258		     dbuff, filter_Action2Nam(fp->f_action));
259	}
260
261	if (cproto == fp->f_proto) {
262	  if ((fp->f_srcop == OP_NONE ||
263	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
264	      (fp->f_dstop == OP_NONE ||
265	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
266	      (fp->f_estab == 0 || estab) &&
267	      (fp->f_syn == 0 || syn) &&
268	      (fp->f_finrst == 0 || finrst)) {
269	    match = 1;
270	  }
271	}
272      } else {
273	/* Address is matched and no protocol specified. Make a decision. */
274	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
275		   filter_Action2Nam(fp->f_action));
276	match = 1;
277      }
278    } else
279      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
280
281    if (match != fp->f_invert) {
282      /* Take specified action */
283      if (fp->f_action < A_NONE)
284	fp = &filter->rule[n = fp->f_action];
285      else
286	return (fp->f_action != A_PERMIT);
287    } else {
288      n++;
289      fp++;
290    }
291  }
292  return (1);		/* No rule is mached. Deny this packet */
293}
294
295#ifdef notdef
296static void
297IcmpError(struct ip *pip, int code)
298{
299  struct mbuf *bp;
300
301  if (pip->ip_p != IPPROTO_ICMP) {
302    bp = mbuf_Alloc(cnt, MB_IPIN);
303    memcpy(MBUF_CTOP(bp), ptr, cnt);
304    vj_SendFrame(bp);
305    ipcp_AddOutOctets(cnt);
306  }
307}
308#endif
309
310/*
311 *  For debugging aid.
312 */
313int
314PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
315{
316  struct ip *pip;
317  struct tcphdr *th;
318  struct udphdr *uh;
319  struct icmp *icmph;
320  char *ptop;
321  int mask, len, n;
322  int pri = PRI_NORMAL;
323  int logit, loglen;
324  char logbuf[200];
325
326  logit = log_IsKept(LogTCPIP) && filter->logok;
327  loglen = 0;
328
329  pip = (struct ip *) cp;
330
331  if (logit && loglen < sizeof logbuf) {
332    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
333    loglen += strlen(logbuf + loglen);
334  }
335  ptop = (cp + (pip->ip_hl << 2));
336
337  switch (pip->ip_p) {
338  case IPPROTO_ICMP:
339    if (logit && loglen < sizeof logbuf) {
340      icmph = (struct icmp *) ptop;
341      snprintf(logbuf + loglen, sizeof logbuf - loglen,
342	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
343      loglen += strlen(logbuf + loglen);
344      snprintf(logbuf + loglen, sizeof logbuf - loglen,
345	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
346      loglen += strlen(logbuf + loglen);
347    }
348    break;
349  case IPPROTO_UDP:
350    if (logit && loglen < sizeof logbuf) {
351      uh = (struct udphdr *) ptop;
352      snprintf(logbuf + loglen, sizeof logbuf - loglen,
353	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
354      loglen += strlen(logbuf + loglen);
355      snprintf(logbuf + loglen, sizeof logbuf - loglen,
356	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
357      loglen += strlen(logbuf + loglen);
358    }
359    break;
360#ifdef IPPROTO_OSPFIGP
361  case IPPROTO_OSPFIGP:
362    if (logit && loglen < sizeof logbuf) {
363      snprintf(logbuf + loglen, sizeof logbuf - loglen,
364	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
365      loglen += strlen(logbuf + loglen);
366      snprintf(logbuf + loglen, sizeof logbuf - loglen,
367	       "%s", inet_ntoa(pip->ip_dst));
368      loglen += strlen(logbuf + loglen);
369    }
370    break;
371#endif
372  case IPPROTO_IPIP:
373    if (logit && loglen < sizeof logbuf) {
374      uh = (struct udphdr *) ptop;
375      snprintf(logbuf + loglen, sizeof logbuf - loglen,
376	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
377      loglen += strlen(logbuf + loglen);
378      snprintf(logbuf + loglen, sizeof logbuf - loglen,
379	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
380      loglen += strlen(logbuf + loglen);
381    }
382    break;
383  case IPPROTO_IGMP:
384    if (logit && loglen < sizeof logbuf) {
385      uh = (struct udphdr *) ptop;
386      snprintf(logbuf + loglen, sizeof logbuf - loglen,
387	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
388      loglen += strlen(logbuf + loglen);
389      snprintf(logbuf + loglen, sizeof logbuf - loglen,
390	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
391      loglen += strlen(logbuf + loglen);
392    }
393    break;
394  case IPPROTO_TCP:
395    th = (struct tcphdr *) ptop;
396    if (pip->ip_tos == IPTOS_LOWDELAY)
397      pri = PRI_FAST;
398    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
399      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
400	pri = PRI_FAST;
401    }
402    if (logit && loglen < sizeof logbuf) {
403      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
404      snprintf(logbuf + loglen, sizeof logbuf - loglen,
405	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
406      loglen += strlen(logbuf + loglen);
407      snprintf(logbuf + loglen, sizeof logbuf - loglen,
408	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
409      loglen += strlen(logbuf + loglen);
410      n = 0;
411      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
412	if (th->th_flags & mask) {
413	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
414	  loglen += strlen(logbuf + loglen);
415	}
416	n++;
417      }
418      snprintf(logbuf + loglen, sizeof logbuf - loglen,
419	       "  seq:%lx  ack:%lx (%d/%d)",
420	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
421      loglen += strlen(logbuf + loglen);
422      if ((th->th_flags & TH_SYN) && nb > 40) {
423	u_short *sp;
424
425	ptop += 20;
426	sp = (u_short *) ptop;
427	if (ntohs(sp[0]) == 0x0204) {
428	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
429		   " MSS = %d", ntohs(sp[1]));
430	  loglen += strlen(logbuf + loglen);
431	}
432      }
433    }
434    break;
435  }
436
437  if (FilterCheck(pip, filter)) {
438    if (logit)
439      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
440#ifdef notdef
441    if (direction == 0)
442      IcmpError(pip, pri);
443#endif
444    return (-1);
445  } else {
446    /* Check Keep Alive filter */
447    if (logit) {
448      if (FilterCheck(pip, &bundle->filter.alive))
449        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
450      else
451        log_Printf(LogTCPIP, "%s\n", logbuf);
452    }
453    return (pri);
454  }
455}
456
457struct mbuf *
458ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
459{
460  int nb, nw;
461  struct tun_data tun;
462  struct ip *pip;
463
464  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
465    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
466    mbuf_Free(bp);
467    return NULL;
468  }
469
470  mbuf_SetType(bp, MB_IPIN);
471  tun_fill_header(tun, AF_INET);
472  nb = mbuf_Length(bp);
473  if (nb > sizeof tun.data) {
474    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
475               l->name, nb, (int)(sizeof tun.data));
476    mbuf_Free(bp);
477    return NULL;
478  }
479  mbuf_Read(bp, tun.data, nb);
480
481  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
482    return NULL;
483
484  pip = (struct ip *)tun.data;
485  if (!FilterCheck(pip, &bundle->filter.alive))
486    bundle_StartIdleTimer(bundle);
487
488  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
489
490  nb += sizeof tun - sizeof tun.data;
491  nw = write(bundle->dev.fd, &tun, nb);
492  if (nw != nb) {
493    if (nw == -1)
494      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
495                 l->name, nb, strerror(errno));
496    else
497      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
498  }
499
500  return NULL;
501}
502
503void
504ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
505{
506  struct mbuf *bp;
507
508  if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0])
509    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
510  else {
511    /*
512     * We allocate an extra 6 bytes, four at the front and two at the end.
513     * This is an optimisation so that we need to do less work in
514     * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and
515     * appending in hdlc_LayerPush().
516     */
517    bp = mbuf_Alloc(count + 6, MB_IPOUT);
518    bp->offset += 4;
519    bp->cnt -= 6;
520    memcpy(MBUF_CTOP(bp), ptr, count);
521    mbuf_Enqueue(&ipcp->Queue[pri], bp);
522  }
523}
524
525void
526ip_DeleteQueue(struct ipcp *ipcp)
527{
528  struct mqueue *queue;
529
530  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
531    while (queue->top)
532      mbuf_Free(mbuf_Dequeue(queue));
533}
534
535int
536ip_QueueLen(struct ipcp *ipcp)
537{
538  struct mqueue *queue;
539  int result = 0;
540
541  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
542    result += queue->qlen;
543
544  return result;
545}
546
547int
548ip_PushPacket(struct link *l, struct bundle *bundle)
549{
550  struct ipcp *ipcp = &bundle->ncp.ipcp;
551  struct mqueue *queue;
552  struct mbuf *bp;
553  struct ip *pip;
554  int cnt;
555
556  if (ipcp->fsm.state != ST_OPENED)
557    return 0;
558
559  for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--)
560    if (queue->top) {
561      bp = mbuf_Contiguous(mbuf_Dequeue(queue));
562      cnt = mbuf_Length(bp);
563      pip = (struct ip *)MBUF_CTOP(bp);
564      if (!FilterCheck(pip, &bundle->filter.alive))
565        bundle_StartIdleTimer(bundle);
566      link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP);
567      ipcp_AddOutOctets(ipcp, cnt);
568      return 1;
569    }
570
571  return 0;
572}
573