ip.c revision 31962
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 *
2031962Sbrian * $Id: ip.c,v 1.32 1997/11/22 03:37:33 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Return ICMP message for filterd packet
246059Samurai *		  and optionaly record it into log.
256059Samurai */
2630715Sbrian#include <sys/param.h>
2731195Sbrian#include <sys/time.h>
2831195Sbrian#include <sys/select.h>
2931195Sbrian#include <sys/socket.h>
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>
3731195Sbrian#include <net/if.h>
3831343Sbrian#ifdef __FreeBSD__
3931195Sbrian#include <net/if_var.h>
4031343Sbrian#endif
4131195Sbrian#include <net/if_tun.h>
4230715Sbrian
4331343Sbrian#ifndef NOALIAS
4426031Sbrian#include <alias.h>
4531343Sbrian#endif
4630092Sbrian#include <errno.h>
4730715Sbrian#include <stdio.h>
4830715Sbrian#include <stdlib.h>
4930715Sbrian#include <string.h>
5030733Sbrian#include <termios.h>
5130715Sbrian#include <unistd.h>
5230715Sbrian
5331343Sbrian#include "command.h"
5430715Sbrian#include "mbuf.h"
5530715Sbrian#include "log.h"
5630715Sbrian#include "defs.h"
5730715Sbrian#include "timer.h"
5830715Sbrian#include "fsm.h"
5930715Sbrian#include "lcpproto.h"
6030715Sbrian#include "hdlc.h"
6126142Sbrian#include "loadalias.h"
626059Samurai#include "vars.h"
636059Samurai#include "filter.h"
6429043Sbrian#include "os.h"
6530715Sbrian#include "ipcp.h"
6630715Sbrian#include "vjcomp.h"
6730715Sbrian#include "lcp.h"
6830733Sbrian#include "modem.h"
6931195Sbrian#include "tun.h"
7030715Sbrian#include "ip.h"
716059Samurai
726059Samuraistatic struct pppTimer IdleTimer;
736059Samurai
7428679Sbrianstatic void
7531343SbrianIdleTimeout(void *v)
766059Samurai{
7726516Sbrian  LogPrintf(LogPHASE, "Idle timer expired.\n");
7826098Sbrian  reconnect(RECON_FALSE);
796059Samurai  LcpClose();
806059Samurai}
816059Samurai
826059Samurai/*
836059Samurai *  Start Idle timer. If timeout is reached, we call LcpClose() to
846059Samurai *  close LCP and link.
856059Samurai */
866059Samuraivoid
876059SamuraiStartIdleTimer()
886059Samurai{
8928679Sbrian  if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) {
906059Samurai    StopTimer(&IdleTimer);
916059Samurai    IdleTimer.func = IdleTimeout;
926059Samurai    IdleTimer.load = VarIdleTimeout * SECTICKS;
936059Samurai    IdleTimer.state = TIMER_STOPPED;
946059Samurai    StartTimer(&IdleTimer);
956059Samurai  }
966059Samurai}
976059Samurai
986059Samuraivoid
9926516SbrianUpdateIdleTimer()
10026516Sbrian{
10129043Sbrian  if (OsLinkIsUp())
10226516Sbrian    StartIdleTimer();
10326516Sbrian}
10426516Sbrian
10526516Sbrianvoid
1066059SamuraiStopIdleTimer()
1076059Samurai{
1086059Samurai  StopTimer(&IdleTimer);
1096059Samurai}
1106059Samurai
1116059Samurai/*
1126059Samurai *  If any IP layer traffic is detected, refresh IdleTimer.
1136059Samurai */
1146059Samuraistatic void
11531343SbrianRestartIdleTimer(void)
1166059Samurai{
11728679Sbrian  if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) {
1186059Samurai    StartTimer(&IdleTimer);
1196059Samurai    ipIdleSecs = 0;
1206059Samurai  }
1216059Samurai}
1226059Samurai
12331343Sbrianstatic const u_short interactive_ports[32] = {
12428679Sbrian  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
12528679Sbrian  0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
1266059Samurai};
1276059Samurai
12813733Sdfr#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
1296059Samurai
13031343Sbrianstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
1316059Samurai
13231343Sbrianstatic const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"};
13328679Sbrianstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters};
1346059Samurai
1356059Samuraistatic int
13628679SbrianPortMatch(int op, u_short pport, u_short rport)
1376059Samurai{
1386059Samurai  switch (op) {
13928679Sbrian    case OP_EQ:
14028679Sbrian    return (pport == rport);
1416059Samurai  case OP_GT:
14228679Sbrian    return (pport > rport);
1436059Samurai  case OP_LT:
14428679Sbrian    return (pport < rport);
1456059Samurai  default:
14628679Sbrian    return (0);
1476059Samurai  }
1486059Samurai}
1496059Samurai
1506059Samurai/*
1516059Samurai *  Check a packet against with defined filters
1526059Samurai */
1536059Samuraistatic int
15428679SbrianFilterCheck(struct ip * pip, int direction)
1556059Samurai{
1566059Samurai  struct filterent *fp = Filters[direction];
1576059Samurai  int gotinfo, cproto, estab, n;
1586059Samurai  struct tcphdr *th;
1596059Samurai  struct udphdr *uh;
1606059Samurai  struct icmp *ih;
1616059Samurai  char *ptop;
1626059Samurai  u_short sport, dport;
1636059Samurai
1646059Samurai  if (fp->action) {
1656059Samurai    cproto = gotinfo = estab = 0;
1666059Samurai    sport = dport = 0;
1676059Samurai    for (n = 0; n < MAXFILTERS; n++) {
1686059Samurai      if (fp->action) {
16928679Sbrian	/* permit fragments on in and out filter */
17028679Sbrian	if ((direction == FL_IN || direction == FL_OUT) &&
17128679Sbrian	    (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
17228679Sbrian	  return (A_PERMIT);
17328679Sbrian	}
17428679Sbrian	LogPrintf(LogDEBUG, "rule = %d\n", n);
17531143Sbrian	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
17631143Sbrian	    (fp->saddr.s_addr & fp->smask.s_addr) &&
17731143Sbrian	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
17831143Sbrian	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
1796059Samurai	  if (fp->proto) {
1806059Samurai	    if (!gotinfo) {
18128679Sbrian	      ptop = (char *) pip + (pip->ip_hl << 2);
1826059Samurai
1836059Samurai	      switch (pip->ip_p) {
1846059Samurai	      case IPPROTO_ICMP:
18528679Sbrian		cproto = P_ICMP;
18628679Sbrian		ih = (struct icmp *) ptop;
18728679Sbrian		sport = ih->icmp_type;
18828679Sbrian		estab = 1;
1896059Samurai		break;
1906059Samurai	      case IPPROTO_UDP:
19128679Sbrian		cproto = P_UDP;
19228679Sbrian		uh = (struct udphdr *) ptop;
19328679Sbrian		sport = ntohs(uh->uh_sport);
19428679Sbrian		dport = ntohs(uh->uh_dport);
1956059Samurai		estab = 1;
1966059Samurai		break;
1976059Samurai	      case IPPROTO_TCP:
19828679Sbrian		cproto = P_TCP;
19928679Sbrian		th = (struct tcphdr *) ptop;
20028679Sbrian		sport = ntohs(th->th_sport);
20128679Sbrian		dport = ntohs(th->th_dport);
2026059Samurai		estab = (th->th_flags & TH_ACK);
20328679Sbrian		if (estab == 0)
20428679Sbrian		  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
20528679Sbrian			    th->th_flags, sport, dport);
2066059Samurai		break;
2076059Samurai	      default:
20828679Sbrian		return (A_DENY);/* We'll block unknown type of packet */
2096059Samurai	      }
2106059Samurai	      gotinfo = 1;
21128679Sbrian	      LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
21228679Sbrian			" dstop = %d, estab = %d\n", direction, cproto,
21328679Sbrian			fp->opt.srcop, fp->opt.dstop, estab);
2146059Samurai	    }
21526516Sbrian	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
21628679Sbrian		      " dport = %d\n", n, cproto, sport, dport);
21726516Sbrian	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
21826516Sbrian
2196059Samurai	    if (cproto == fp->proto) {
2206059Samurai	      if ((fp->opt.srcop == OP_NONE ||
22128679Sbrian		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
22228679Sbrian		  &&
2236059Samurai		  (fp->opt.dstop == OP_NONE ||
22428679Sbrian		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
22528679Sbrian		  &&
2266059Samurai		  (fp->opt.estab == 0 || estab)) {
22728679Sbrian		return (fp->action);
2286059Samurai	      }
2296059Samurai	    }
2306059Samurai	  } else {
2316059Samurai	    /* Address is mached. Make a decision. */
23226516Sbrian	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
23328679Sbrian	    return (fp->action);
2346059Samurai	  }
2356059Samurai	}
2366059Samurai      }
2376059Samurai      fp++;
2386059Samurai    }
23928679Sbrian    return (A_DENY);		/* No rule is mached. Deny this packet */
2406059Samurai  }
24128679Sbrian  return (A_PERMIT);		/* No rule is given. Permit this packet */
2426059Samurai}
2436059Samurai
2446059Samuraistatic void
24528679SbrianIcmpError(struct ip * pip, int code)
2466059Samurai{
2476059Samurai#ifdef notdef
2486059Samurai  struct mbuf *bp;
2496059Samurai
2506059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
2516059Samurai    bp = mballoc(cnt, MB_IPIN);
25230715Sbrian    memcpy(MBUF_CTOP(bp), ptr, cnt);
25313733Sdfr    SendPppFrame(bp);
2546059Samurai    RestartIdleTimer();
25531272Sbrian    IpcpAddOutOctets(cnt);
2566059Samurai  }
2576059Samurai#endif
2586059Samurai}
2596059Samurai
2606059Samurai/*
2616059Samurai *  For debugging aid.
2626059Samurai */
2636059Samuraiint
26428679SbrianPacketCheck(char *cp, int nb, int direction)
2656059Samurai{
2666059Samurai  struct ip *pip;
2676059Samurai  struct tcphdr *th;
2686059Samurai  struct udphdr *uh;
2696059Samurai  struct icmp *icmph;
2706059Samurai  char *ptop;
2716059Samurai  int mask, len, n;
2726059Samurai  int pri = PRI_NORMAL;
27326692Sbrian  int logit, loglen;
27426692Sbrian  static char logbuf[200];
2756059Samurai
27626516Sbrian  logit = LogIsKept(LogTCPIP);
27726692Sbrian  loglen = 0;
2786059Samurai
27928679Sbrian  pip = (struct ip *) cp;
2808857Srgrimes
28126692Sbrian  if (logit && loglen < sizeof logbuf) {
28228679Sbrian    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ",
28328679Sbrian	     Direction[direction]);
28428679Sbrian    loglen += strlen(logbuf + loglen);
28526692Sbrian  }
2866059Samurai  ptop = (cp + (pip->ip_hl << 2));
2876059Samurai
2886059Samurai  switch (pip->ip_p) {
2896059Samurai  case IPPROTO_ICMP:
29026692Sbrian    if (logit && loglen < sizeof logbuf) {
29128679Sbrian      icmph = (struct icmp *) ptop;
29228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
29328679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
29428679Sbrian      loglen += strlen(logbuf + loglen);
29528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
29628679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
29728679Sbrian      loglen += strlen(logbuf + loglen);
2986059Samurai    }
2996059Samurai    break;
3006059Samurai  case IPPROTO_UDP:
30126692Sbrian    if (logit && loglen < sizeof logbuf) {
30228679Sbrian      uh = (struct udphdr *) ptop;
30328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
30428679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
30528679Sbrian      loglen += strlen(logbuf + loglen);
30628679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
30728679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
30828679Sbrian      loglen += strlen(logbuf + loglen);
3096059Samurai    }
3106059Samurai    break;
3116059Samurai  case IPPROTO_TCP:
31228679Sbrian    th = (struct tcphdr *) ptop;
3136059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
3146059Samurai      pri = PRI_FAST;
31513733Sdfr    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
3166059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
31728679Sbrian	pri = PRI_FAST;
3186059Samurai    }
31926692Sbrian    if (logit && loglen < sizeof logbuf) {
3206059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
32128679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
32228679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
32328679Sbrian      loglen += strlen(logbuf + loglen);
32428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
32528679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
32628679Sbrian      loglen += strlen(logbuf + loglen);
3276059Samurai      n = 0;
3286059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
32926692Sbrian	if (th->th_flags & mask) {
33028679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
33128679Sbrian	  loglen += strlen(logbuf + loglen);
33228679Sbrian	}
3336059Samurai	n++;
3346059Samurai      }
33528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
33628679Sbrian	       "  seq:%x  ack:%x (%d/%d)",
33728679Sbrian	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
33828679Sbrian      loglen += strlen(logbuf + loglen);
3396059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
34028679Sbrian	u_short *sp;
3416059Samurai
3426059Samurai	ptop += 20;
34328679Sbrian	sp = (u_short *) ptop;
34426692Sbrian	if (ntohs(sp[0]) == 0x0204) {
34528679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
34628679Sbrian		   " MSS = %d", ntohs(sp[1]));
34728679Sbrian	  loglen += strlen(logbuf + loglen);
34828679Sbrian	}
3496059Samurai      }
3506059Samurai    }
3516059Samurai    break;
3526059Samurai  }
35326692Sbrian
35413733Sdfr  if ((FilterCheck(pip, direction) & A_DENY)) {
35531142Sbrian    if (logit)
35631142Sbrian      LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
35728679Sbrian    if (direction == 0)
35828679Sbrian      IcmpError(pip, pri);
35928679Sbrian    return (-1);
3606059Samurai  } else {
36128679Sbrian    if (FilterCheck(pip, FL_KEEP) & A_DENY) {	/* Check Keep Alive filter */
36231142Sbrian      if (logit)
36331142Sbrian        LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
36430715Sbrian      ipKeepAlive = 0;
3656735Samurai    } else {
36631142Sbrian      if (logit)
36731142Sbrian        LogPrintf(LogTCPIP, "%s\n", logbuf);
36830715Sbrian      ipKeepAlive = 1;
3696735Samurai    }
37028679Sbrian    return (pri);
3716059Samurai  }
3726059Samurai}
3736059Samurai
3746059Samuraivoid
37528679SbrianIpInput(struct mbuf * bp)
37628679Sbrian{				/* IN: Pointer to IP pakcet */
3776059Samurai  u_char *cp;
3786059Samurai  struct mbuf *wp;
3796059Samurai  int nb, nw;
38031343Sbrian  struct tun_data tun;
3816059Samurai
38231195Sbrian  tun_fill_header(tun, AF_INET);
38331195Sbrian  cp = tun.data;
3846059Samurai  nb = 0;
38528679Sbrian  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
38630715Sbrian    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
3876059Samurai    cp += wp->cnt;
3886059Samurai    nb += wp->cnt;
3896059Samurai  }
3906059Samurai
39131343Sbrian#ifndef NOALIAS
39220365Sjkh  if (mode & MODE_ALIAS) {
39331343Sbrian    struct tun_data *frag;
39426031Sbrian    int iresult;
39526031Sbrian    char *fptr;
39626031Sbrian
39731195Sbrian    iresult = VarPacketAliasIn(tun.data, sizeof tun.data);
39831195Sbrian    nb = ntohs(((struct ip *) tun.data)->ip_len);
39926031Sbrian
40026031Sbrian    if (nb > MAX_MRU) {
40126516Sbrian      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
40226031Sbrian      pfree(bp);
40326031Sbrian      return;
40426031Sbrian    }
40526031Sbrian    if (iresult == PKT_ALIAS_OK
40628679Sbrian	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
40731195Sbrian      if (PacketCheck(tun.data, nb, FL_IN) < 0) {
40828679Sbrian	pfree(bp);
40928679Sbrian	return;
41026031Sbrian      }
41131272Sbrian      IpcpAddInOctets(nb);
41226031Sbrian
41331195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
41431962Sbrian      nb += sizeof tun - sizeof tun.data;
41531195Sbrian      nw = write(tun_out, &tun, nb);
41626031Sbrian      if (nw != nb)
41730092Sbrian        if (nw == -1)
41830092Sbrian	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
41930092Sbrian                    strerror(errno));
42030092Sbrian        else
42130092Sbrian	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
42226031Sbrian
42326031Sbrian      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
42431195Sbrian	while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) {
42531195Sbrian	  VarPacketAliasFragmentIn(tun.data, fptr);
42628679Sbrian	  nb = ntohs(((struct ip *) fptr)->ip_len);
42731962Sbrian          frag = (struct tun_data *)
42831962Sbrian	    ((char *)fptr - sizeof tun + sizeof tun.data);
42931962Sbrian          nb += sizeof tun - sizeof tun.data;
43031195Sbrian	  nw = write(tun_out, frag, nb);
43128679Sbrian	  if (nw != nb)
43230092Sbrian            if (nw == -1)
43330092Sbrian	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
43430092Sbrian                        strerror(errno));
43530092Sbrian            else
43630092Sbrian	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
43731195Sbrian	  free(frag);
43828679Sbrian	}
43926031Sbrian      }
44028679Sbrian    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
44131195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
44231962Sbrian      nb += sizeof tun - sizeof tun.data;
44331195Sbrian      frag = (struct tun_data *)malloc(nb);
44431195Sbrian      if (frag == NULL)
44528679Sbrian	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
44626031Sbrian      else {
44731195Sbrian        tun_fill_header(*frag, AF_INET);
44831962Sbrian	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
44931195Sbrian	VarPacketAliasSaveFragment(frag->data);
45026031Sbrian      }
45126031Sbrian    }
45231343Sbrian  } else
45331343Sbrian#endif /* #ifndef NOALIAS */
45431343Sbrian  {			/* no aliasing */
45531195Sbrian    if (PacketCheck(tun.data, nb, FL_IN) < 0) {
45626031Sbrian      pfree(bp);
45726031Sbrian      return;
45826031Sbrian    }
45931272Sbrian    IpcpAddInOctets(nb);
46031962Sbrian    nb += sizeof tun - sizeof tun.data;
46131195Sbrian    nw = write(tun_out, &tun, nb);
46226031Sbrian    if (nw != nb)
46330092Sbrian      if (nw == -1)
46430092Sbrian	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
46530092Sbrian      else
46630092Sbrian        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4676059Samurai  }
4686059Samurai  pfree(bp);
4696059Samurai
4706059Samurai  RestartIdleTimer();
4716059Samurai}
4726059Samurai
47328679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1];
4746059Samurai
4756059Samuraivoid
47628679SbrianIpEnqueue(int pri, char *ptr, int count)
4776059Samurai{
4786059Samurai  struct mbuf *bp;
4796059Samurai
4806059Samurai  bp = mballoc(count, MB_IPQ);
48130715Sbrian  memcpy(MBUF_CTOP(bp), ptr, count);
4826059Samurai  Enqueue(&IpOutputQueues[pri], bp);
4836059Samurai}
4846059Samurai
48530715Sbrian#if 0
4868857Srgrimesint
4877001SamuraiIsIpEnqueued()
4887001Samurai{
4897001Samurai  struct mqueue *queue;
49030715Sbrian  int exist = 0;
49128679Sbrian
49213733Sdfr  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
49328679Sbrian    if (queue->qlen > 0) {
49430715Sbrian      exist = 1;
49528679Sbrian      break;
49628679Sbrian    }
4977001Samurai  }
49828679Sbrian  return (exist);
4997001Samurai}
50030715Sbrian#endif
5017001Samurai
5026059Samuraivoid
5036059SamuraiIpStartOutput()
5046059Samurai{
5056059Samurai  struct mqueue *queue;
5066059Samurai  struct mbuf *bp;
50725630Sbrian  int cnt;
5086059Samurai
5096059Samurai  if (IpcpFsm.state != ST_OPENED)
5106059Samurai    return;
51113733Sdfr  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
5126059Samurai    if (queue->top) {
5136059Samurai      bp = Dequeue(queue);
5146059Samurai      if (bp) {
5156059Samurai	cnt = plength(bp);
51613733Sdfr	SendPppFrame(bp);
5176059Samurai	RestartIdleTimer();
51831272Sbrian        IpcpAddOutOctets(cnt);
51913733Sdfr	break;
52028679Sbrian      }
5216059Samurai    }
5226059Samurai  }
5236059Samurai}
524