ip.c revision 31142
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 *
2031142Sbrian * $Id: ip.c,v 1.27 1997/10/26 12:42:10 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>
2730715Sbrian#include <netinet/in.h>
286059Samurai#include <netinet/in_systm.h>
296059Samurai#include <netinet/ip.h>
306059Samurai#include <netinet/ip_icmp.h>
316059Samurai#include <netinet/udp.h>
326059Samurai#include <netinet/tcp.h>
3313389Sphk#include <arpa/inet.h>
3430715Sbrian
3526031Sbrian#include <alias.h>
3630092Sbrian#include <errno.h>
3730715Sbrian#include <stdio.h>
3830715Sbrian#include <stdlib.h>
3930715Sbrian#include <string.h>
4030733Sbrian#include <termios.h>
4130715Sbrian#include <unistd.h>
4230715Sbrian
4330715Sbrian#include "mbuf.h"
4430715Sbrian#include "log.h"
4530715Sbrian#include "defs.h"
4630715Sbrian#include "timer.h"
4730715Sbrian#include "fsm.h"
4830715Sbrian#include "lcpproto.h"
4930715Sbrian#include "hdlc.h"
5026142Sbrian#include "loadalias.h"
5130715Sbrian#include "command.h"
526059Samurai#include "vars.h"
536059Samurai#include "filter.h"
5426516Sbrian#include "log.h"
5529043Sbrian#include "os.h"
5630715Sbrian#include "ipcp.h"
5730715Sbrian#include "vjcomp.h"
5830715Sbrian#include "lcp.h"
5930733Sbrian#include "modem.h"
6030715Sbrian#include "ip.h"
616059Samurai
626059Samuraistatic struct pppTimer IdleTimer;
636059Samurai
6428679Sbrianstatic void
6528679SbrianIdleTimeout()
666059Samurai{
6726516Sbrian  LogPrintf(LogPHASE, "Idle timer expired.\n");
6826098Sbrian  reconnect(RECON_FALSE);
696059Samurai  LcpClose();
706059Samurai}
716059Samurai
726059Samurai/*
736059Samurai *  Start Idle timer. If timeout is reached, we call LcpClose() to
746059Samurai *  close LCP and link.
756059Samurai */
766059Samuraivoid
776059SamuraiStartIdleTimer()
786059Samurai{
7928679Sbrian  if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) {
806059Samurai    StopTimer(&IdleTimer);
816059Samurai    IdleTimer.func = IdleTimeout;
826059Samurai    IdleTimer.load = VarIdleTimeout * SECTICKS;
836059Samurai    IdleTimer.state = TIMER_STOPPED;
846059Samurai    StartTimer(&IdleTimer);
856059Samurai  }
866059Samurai}
876059Samurai
886059Samuraivoid
8926516SbrianUpdateIdleTimer()
9026516Sbrian{
9129043Sbrian  if (OsLinkIsUp())
9226516Sbrian    StartIdleTimer();
9326516Sbrian}
9426516Sbrian
9526516Sbrianvoid
966059SamuraiStopIdleTimer()
976059Samurai{
986059Samurai  StopTimer(&IdleTimer);
996059Samurai}
1006059Samurai
1016059Samurai/*
1026059Samurai *  If any IP layer traffic is detected, refresh IdleTimer.
1036059Samurai */
1046059Samuraistatic void
1056059SamuraiRestartIdleTimer()
1066059Samurai{
10728679Sbrian  if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) {
1086059Samurai    StartTimer(&IdleTimer);
1096059Samurai    ipIdleSecs = 0;
1106059Samurai  }
1116059Samurai}
1126059Samurai
11313733Sdfrstatic u_short interactive_ports[32] = {
11428679Sbrian  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11528679Sbrian  0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
1166059Samurai};
1176059Samurai
11813733Sdfr#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
1196059Samurai
1206059Samuraistatic char *TcpFlags[] = {
1216059Samurai  "FIN", "SYN", "RST", "PSH", "ACK", "URG",
1226059Samurai};
1236059Samurai
12428679Sbrianstatic char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"};
12528679Sbrianstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters};
1266059Samurai
1276059Samuraistatic int
12828679SbrianPortMatch(int op, u_short pport, u_short rport)
1296059Samurai{
1306059Samurai  switch (op) {
13128679Sbrian    case OP_EQ:
13228679Sbrian    return (pport == rport);
1336059Samurai  case OP_GT:
13428679Sbrian    return (pport > rport);
1356059Samurai  case OP_LT:
13628679Sbrian    return (pport < rport);
1376059Samurai  default:
13828679Sbrian    return (0);
1396059Samurai  }
1406059Samurai}
1416059Samurai
1426059Samurai/*
1436059Samurai *  Check a packet against with defined filters
1446059Samurai */
1456059Samuraistatic int
14628679SbrianFilterCheck(struct ip * pip, int direction)
1476059Samurai{
1486059Samurai  struct filterent *fp = Filters[direction];
1496059Samurai  int gotinfo, cproto, estab, n;
1506059Samurai  struct tcphdr *th;
1516059Samurai  struct udphdr *uh;
1526059Samurai  struct icmp *ih;
1536059Samurai  char *ptop;
1546059Samurai  u_short sport, dport;
1556059Samurai
1566059Samurai  if (fp->action) {
1576059Samurai    cproto = gotinfo = estab = 0;
1586059Samurai    sport = dport = 0;
1596059Samurai    for (n = 0; n < MAXFILTERS; n++) {
1606059Samurai      if (fp->action) {
16128679Sbrian	/* permit fragments on in and out filter */
16228679Sbrian	if ((direction == FL_IN || direction == FL_OUT) &&
16328679Sbrian	    (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
16428679Sbrian	  return (A_PERMIT);
16528679Sbrian	}
16628679Sbrian	LogPrintf(LogDEBUG, "rule = %d\n", n);
1676059Samurai	if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
1686059Samurai	    && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
1696059Samurai	  if (fp->proto) {
1706059Samurai	    if (!gotinfo) {
17128679Sbrian	      ptop = (char *) pip + (pip->ip_hl << 2);
1726059Samurai
1736059Samurai	      switch (pip->ip_p) {
1746059Samurai	      case IPPROTO_ICMP:
17528679Sbrian		cproto = P_ICMP;
17628679Sbrian		ih = (struct icmp *) ptop;
17728679Sbrian		sport = ih->icmp_type;
17828679Sbrian		estab = 1;
1796059Samurai		break;
1806059Samurai	      case IPPROTO_UDP:
18128679Sbrian		cproto = P_UDP;
18228679Sbrian		uh = (struct udphdr *) ptop;
18328679Sbrian		sport = ntohs(uh->uh_sport);
18428679Sbrian		dport = ntohs(uh->uh_dport);
1856059Samurai		estab = 1;
1866059Samurai		break;
1876059Samurai	      case IPPROTO_TCP:
18828679Sbrian		cproto = P_TCP;
18928679Sbrian		th = (struct tcphdr *) ptop;
19028679Sbrian		sport = ntohs(th->th_sport);
19128679Sbrian		dport = ntohs(th->th_dport);
1926059Samurai		estab = (th->th_flags & TH_ACK);
19328679Sbrian		if (estab == 0)
19428679Sbrian		  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
19528679Sbrian			    th->th_flags, sport, dport);
1966059Samurai		break;
1976059Samurai	      default:
19828679Sbrian		return (A_DENY);/* We'll block unknown type of packet */
1996059Samurai	      }
2006059Samurai	      gotinfo = 1;
20128679Sbrian	      LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
20228679Sbrian			" dstop = %d, estab = %d\n", direction, cproto,
20328679Sbrian			fp->opt.srcop, fp->opt.dstop, estab);
2046059Samurai	    }
20526516Sbrian	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
20628679Sbrian		      " dport = %d\n", n, cproto, sport, dport);
20726516Sbrian	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
20826516Sbrian
2096059Samurai	    if (cproto == fp->proto) {
2106059Samurai	      if ((fp->opt.srcop == OP_NONE ||
21128679Sbrian		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
21228679Sbrian		  &&
2136059Samurai		  (fp->opt.dstop == OP_NONE ||
21428679Sbrian		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
21528679Sbrian		  &&
2166059Samurai		  (fp->opt.estab == 0 || estab)) {
21728679Sbrian		return (fp->action);
2186059Samurai	      }
2196059Samurai	    }
2206059Samurai	  } else {
2216059Samurai	    /* Address is mached. Make a decision. */
22226516Sbrian	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
22328679Sbrian	    return (fp->action);
2246059Samurai	  }
2256059Samurai	}
2266059Samurai      }
2276059Samurai      fp++;
2286059Samurai    }
22928679Sbrian    return (A_DENY);		/* No rule is mached. Deny this packet */
2306059Samurai  }
23128679Sbrian  return (A_PERMIT);		/* No rule is given. Permit this packet */
2326059Samurai}
2336059Samurai
2346059Samuraistatic void
23528679SbrianIcmpError(struct ip * pip, int code)
2366059Samurai{
2376059Samurai#ifdef notdef
2386059Samurai  struct mbuf *bp;
2396059Samurai
2406059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
2416059Samurai    bp = mballoc(cnt, MB_IPIN);
24230715Sbrian    memcpy(MBUF_CTOP(bp), ptr, cnt);
24313733Sdfr    SendPppFrame(bp);
2446059Samurai    RestartIdleTimer();
2456059Samurai    ipOutOctets += cnt;
2466059Samurai  }
2476059Samurai#endif
2486059Samurai}
2496059Samurai
2506059Samurai/*
2516059Samurai *  For debugging aid.
2526059Samurai */
2536059Samuraiint
25428679SbrianPacketCheck(char *cp, int nb, int direction)
2556059Samurai{
2566059Samurai  struct ip *pip;
2576059Samurai  struct tcphdr *th;
2586059Samurai  struct udphdr *uh;
2596059Samurai  struct icmp *icmph;
2606059Samurai  char *ptop;
2616059Samurai  int mask, len, n;
2626059Samurai  int pri = PRI_NORMAL;
26326692Sbrian  int logit, loglen;
26426692Sbrian  static char logbuf[200];
2656059Samurai
26626516Sbrian  logit = LogIsKept(LogTCPIP);
26726692Sbrian  loglen = 0;
2686059Samurai
26928679Sbrian  pip = (struct ip *) cp;
2708857Srgrimes
27126692Sbrian  if (logit && loglen < sizeof logbuf) {
27228679Sbrian    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ",
27328679Sbrian	     Direction[direction]);
27428679Sbrian    loglen += strlen(logbuf + loglen);
27526692Sbrian  }
2766059Samurai  ptop = (cp + (pip->ip_hl << 2));
2776059Samurai
2786059Samurai  switch (pip->ip_p) {
2796059Samurai  case IPPROTO_ICMP:
28026692Sbrian    if (logit && loglen < sizeof logbuf) {
28128679Sbrian      icmph = (struct icmp *) ptop;
28228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
28328679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
28428679Sbrian      loglen += strlen(logbuf + loglen);
28528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
28628679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
28728679Sbrian      loglen += strlen(logbuf + loglen);
2886059Samurai    }
2896059Samurai    break;
2906059Samurai  case IPPROTO_UDP:
29126692Sbrian    if (logit && loglen < sizeof logbuf) {
29228679Sbrian      uh = (struct udphdr *) ptop;
29328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
29428679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
29528679Sbrian      loglen += strlen(logbuf + loglen);
29628679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
29728679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
29828679Sbrian      loglen += strlen(logbuf + loglen);
2996059Samurai    }
3006059Samurai    break;
3016059Samurai  case IPPROTO_TCP:
30228679Sbrian    th = (struct tcphdr *) ptop;
3036059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
3046059Samurai      pri = PRI_FAST;
30513733Sdfr    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
3066059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
30728679Sbrian	pri = PRI_FAST;
3086059Samurai    }
30926692Sbrian    if (logit && loglen < sizeof logbuf) {
3106059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
31128679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
31228679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
31328679Sbrian      loglen += strlen(logbuf + loglen);
31428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
31528679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
31628679Sbrian      loglen += strlen(logbuf + loglen);
3176059Samurai      n = 0;
3186059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
31926692Sbrian	if (th->th_flags & mask) {
32028679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
32128679Sbrian	  loglen += strlen(logbuf + loglen);
32228679Sbrian	}
3236059Samurai	n++;
3246059Samurai      }
32528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
32628679Sbrian	       "  seq:%x  ack:%x (%d/%d)",
32728679Sbrian	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
32828679Sbrian      loglen += strlen(logbuf + loglen);
3296059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
33028679Sbrian	u_short *sp;
3316059Samurai
3326059Samurai	ptop += 20;
33328679Sbrian	sp = (u_short *) ptop;
33426692Sbrian	if (ntohs(sp[0]) == 0x0204) {
33528679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
33628679Sbrian		   " MSS = %d", ntohs(sp[1]));
33728679Sbrian	  loglen += strlen(logbuf + loglen);
33828679Sbrian	}
3396059Samurai      }
3406059Samurai    }
3416059Samurai    break;
3426059Samurai  }
34326692Sbrian
34413733Sdfr  if ((FilterCheck(pip, direction) & A_DENY)) {
34531142Sbrian    if (logit)
34631142Sbrian      LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
34728679Sbrian    if (direction == 0)
34828679Sbrian      IcmpError(pip, pri);
34928679Sbrian    return (-1);
3506059Samurai  } else {
35128679Sbrian    if (FilterCheck(pip, FL_KEEP) & A_DENY) {	/* Check Keep Alive filter */
35231142Sbrian      if (logit)
35331142Sbrian        LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
35430715Sbrian      ipKeepAlive = 0;
3556735Samurai    } else {
35631142Sbrian      if (logit)
35731142Sbrian        LogPrintf(LogTCPIP, "%s\n", logbuf);
35830715Sbrian      ipKeepAlive = 1;
3596735Samurai    }
36028679Sbrian    return (pri);
3616059Samurai  }
3626059Samurai}
3636059Samurai
3646059Samuraivoid
36528679SbrianIpInput(struct mbuf * bp)
36628679Sbrian{				/* IN: Pointer to IP pakcet */
3676059Samurai  u_char *cp;
3686059Samurai  struct mbuf *wp;
3696059Samurai  int nb, nw;
3706059Samurai  u_char tunbuff[MAX_MRU];
3716059Samurai
3726059Samurai  cp = tunbuff;
3736059Samurai  nb = 0;
37428679Sbrian  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
37530715Sbrian    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
3766059Samurai    cp += wp->cnt;
3776059Samurai    nb += wp->cnt;
3786059Samurai  }
3796059Samurai
38020365Sjkh  if (mode & MODE_ALIAS) {
38126031Sbrian    int iresult;
38226031Sbrian    char *fptr;
38326031Sbrian
38426142Sbrian    iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff);
38526031Sbrian    nb = ntohs(((struct ip *) tunbuff)->ip_len);
38626031Sbrian
38726031Sbrian    if (nb > MAX_MRU) {
38826516Sbrian      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
38926031Sbrian      pfree(bp);
39026031Sbrian      return;
39126031Sbrian    }
39226031Sbrian    if (iresult == PKT_ALIAS_OK
39328679Sbrian	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
39428679Sbrian      if (PacketCheck(tunbuff, nb, FL_IN) < 0) {
39528679Sbrian	pfree(bp);
39628679Sbrian	return;
39726031Sbrian      }
39826031Sbrian      ipInOctets += nb;
39926031Sbrian
40026031Sbrian      nb = ntohs(((struct ip *) tunbuff)->ip_len);
40126031Sbrian      nw = write(tun_out, tunbuff, nb);
40226031Sbrian      if (nw != nb)
40330092Sbrian        if (nw == -1)
40430092Sbrian	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
40530092Sbrian                    strerror(errno));
40630092Sbrian        else
40730092Sbrian	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
40826031Sbrian
40926031Sbrian      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
41028679Sbrian	while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) {
41128679Sbrian	  VarPacketAliasFragmentIn(tunbuff, fptr);
41228679Sbrian	  nb = ntohs(((struct ip *) fptr)->ip_len);
41328679Sbrian	  nw = write(tun_out, fptr, nb);
41428679Sbrian	  if (nw != nb)
41530092Sbrian            if (nw == -1)
41630092Sbrian	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
41730092Sbrian                        strerror(errno));
41830092Sbrian            else
41930092Sbrian	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
42028679Sbrian	  free(fptr);
42128679Sbrian	}
42226031Sbrian      }
42328679Sbrian    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
42426031Sbrian      nb = ntohs(((struct ip *) tunbuff)->ip_len);
42526031Sbrian      fptr = malloc(nb);
42626516Sbrian      if (fptr == NULL)
42728679Sbrian	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
42826031Sbrian      else {
42928679Sbrian	memcpy(fptr, tunbuff, nb);
43028679Sbrian	VarPacketAliasSaveFragment(fptr);
43126031Sbrian      }
43226031Sbrian    }
43328679Sbrian  } else {			/* no aliasing */
43428679Sbrian    if (PacketCheck(tunbuff, nb, FL_IN) < 0) {
43526031Sbrian      pfree(bp);
43626031Sbrian      return;
43726031Sbrian    }
43826031Sbrian    ipInOctets += nb;
43926031Sbrian    nw = write(tun_out, tunbuff, nb);
44026031Sbrian    if (nw != nb)
44130092Sbrian      if (nw == -1)
44230092Sbrian	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
44330092Sbrian      else
44430092Sbrian        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4456059Samurai  }
4466059Samurai  pfree(bp);
4476059Samurai
4486059Samurai  RestartIdleTimer();
4496059Samurai}
4506059Samurai
45128679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1];
4526059Samurai
4536059Samuraivoid
45428679SbrianIpEnqueue(int pri, char *ptr, int count)
4556059Samurai{
4566059Samurai  struct mbuf *bp;
4576059Samurai
4586059Samurai  bp = mballoc(count, MB_IPQ);
45930715Sbrian  memcpy(MBUF_CTOP(bp), ptr, count);
4606059Samurai  Enqueue(&IpOutputQueues[pri], bp);
4616059Samurai}
4626059Samurai
46330715Sbrian#if 0
4648857Srgrimesint
4657001SamuraiIsIpEnqueued()
4667001Samurai{
4677001Samurai  struct mqueue *queue;
46830715Sbrian  int exist = 0;
46928679Sbrian
47013733Sdfr  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
47128679Sbrian    if (queue->qlen > 0) {
47230715Sbrian      exist = 1;
47328679Sbrian      break;
47428679Sbrian    }
4757001Samurai  }
47628679Sbrian  return (exist);
4777001Samurai}
47830715Sbrian#endif
4797001Samurai
4806059Samuraivoid
4816059SamuraiIpStartOutput()
4826059Samurai{
4836059Samurai  struct mqueue *queue;
4846059Samurai  struct mbuf *bp;
48525630Sbrian  int cnt;
4866059Samurai
4876059Samurai  if (IpcpFsm.state != ST_OPENED)
4886059Samurai    return;
48913733Sdfr  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
4906059Samurai    if (queue->top) {
4916059Samurai      bp = Dequeue(queue);
4926059Samurai      if (bp) {
4936059Samurai	cnt = plength(bp);
49413733Sdfr	SendPppFrame(bp);
4956059Samurai	RestartIdleTimer();
4966059Samurai	ipOutOctets += cnt;
49713733Sdfr	break;
49828679Sbrian      }
4996059Samurai    }
5006059Samurai  }
5016059Samurai}
502