ip.c revision 31195
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 *
2031195Sbrian * $Id: ip.c,v 1.29 1997/11/12 21:04:21 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>
3831195Sbrian#include <net/if_var.h>
3931195Sbrian#include <net/if_tun.h>
4030715Sbrian
4126031Sbrian#include <alias.h>
4230092Sbrian#include <errno.h>
4330715Sbrian#include <stdio.h>
4430715Sbrian#include <stdlib.h>
4530715Sbrian#include <string.h>
4630733Sbrian#include <termios.h>
4730715Sbrian#include <unistd.h>
4830715Sbrian
4930715Sbrian#include "mbuf.h"
5030715Sbrian#include "log.h"
5130715Sbrian#include "defs.h"
5230715Sbrian#include "timer.h"
5330715Sbrian#include "fsm.h"
5430715Sbrian#include "lcpproto.h"
5530715Sbrian#include "hdlc.h"
5626142Sbrian#include "loadalias.h"
5730715Sbrian#include "command.h"
586059Samurai#include "vars.h"
596059Samurai#include "filter.h"
6026516Sbrian#include "log.h"
6129043Sbrian#include "os.h"
6230715Sbrian#include "ipcp.h"
6330715Sbrian#include "vjcomp.h"
6430715Sbrian#include "lcp.h"
6530733Sbrian#include "modem.h"
6631195Sbrian#include "tun.h"
6730715Sbrian#include "ip.h"
686059Samurai
696059Samuraistatic struct pppTimer IdleTimer;
706059Samurai
7128679Sbrianstatic void
7228679SbrianIdleTimeout()
736059Samurai{
7426516Sbrian  LogPrintf(LogPHASE, "Idle timer expired.\n");
7526098Sbrian  reconnect(RECON_FALSE);
766059Samurai  LcpClose();
776059Samurai}
786059Samurai
796059Samurai/*
806059Samurai *  Start Idle timer. If timeout is reached, we call LcpClose() to
816059Samurai *  close LCP and link.
826059Samurai */
836059Samuraivoid
846059SamuraiStartIdleTimer()
856059Samurai{
8628679Sbrian  if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) {
876059Samurai    StopTimer(&IdleTimer);
886059Samurai    IdleTimer.func = IdleTimeout;
896059Samurai    IdleTimer.load = VarIdleTimeout * SECTICKS;
906059Samurai    IdleTimer.state = TIMER_STOPPED;
916059Samurai    StartTimer(&IdleTimer);
926059Samurai  }
936059Samurai}
946059Samurai
956059Samuraivoid
9626516SbrianUpdateIdleTimer()
9726516Sbrian{
9829043Sbrian  if (OsLinkIsUp())
9926516Sbrian    StartIdleTimer();
10026516Sbrian}
10126516Sbrian
10226516Sbrianvoid
1036059SamuraiStopIdleTimer()
1046059Samurai{
1056059Samurai  StopTimer(&IdleTimer);
1066059Samurai}
1076059Samurai
1086059Samurai/*
1096059Samurai *  If any IP layer traffic is detected, refresh IdleTimer.
1106059Samurai */
1116059Samuraistatic void
1126059SamuraiRestartIdleTimer()
1136059Samurai{
11428679Sbrian  if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) {
1156059Samurai    StartTimer(&IdleTimer);
1166059Samurai    ipIdleSecs = 0;
1176059Samurai  }
1186059Samurai}
1196059Samurai
12013733Sdfrstatic u_short interactive_ports[32] = {
12128679Sbrian  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
12228679Sbrian  0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
1236059Samurai};
1246059Samurai
12513733Sdfr#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
1266059Samurai
1276059Samuraistatic char *TcpFlags[] = {
1286059Samurai  "FIN", "SYN", "RST", "PSH", "ACK", "URG",
1296059Samurai};
1306059Samurai
13128679Sbrianstatic char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"};
13228679Sbrianstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters};
1336059Samurai
1346059Samuraistatic int
13528679SbrianPortMatch(int op, u_short pport, u_short rport)
1366059Samurai{
1376059Samurai  switch (op) {
13828679Sbrian    case OP_EQ:
13928679Sbrian    return (pport == rport);
1406059Samurai  case OP_GT:
14128679Sbrian    return (pport > rport);
1426059Samurai  case OP_LT:
14328679Sbrian    return (pport < rport);
1446059Samurai  default:
14528679Sbrian    return (0);
1466059Samurai  }
1476059Samurai}
1486059Samurai
1496059Samurai/*
1506059Samurai *  Check a packet against with defined filters
1516059Samurai */
1526059Samuraistatic int
15328679SbrianFilterCheck(struct ip * pip, int direction)
1546059Samurai{
1556059Samurai  struct filterent *fp = Filters[direction];
1566059Samurai  int gotinfo, cproto, estab, n;
1576059Samurai  struct tcphdr *th;
1586059Samurai  struct udphdr *uh;
1596059Samurai  struct icmp *ih;
1606059Samurai  char *ptop;
1616059Samurai  u_short sport, dport;
1626059Samurai
1636059Samurai  if (fp->action) {
1646059Samurai    cproto = gotinfo = estab = 0;
1656059Samurai    sport = dport = 0;
1666059Samurai    for (n = 0; n < MAXFILTERS; n++) {
1676059Samurai      if (fp->action) {
16828679Sbrian	/* permit fragments on in and out filter */
16928679Sbrian	if ((direction == FL_IN || direction == FL_OUT) &&
17028679Sbrian	    (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
17128679Sbrian	  return (A_PERMIT);
17228679Sbrian	}
17328679Sbrian	LogPrintf(LogDEBUG, "rule = %d\n", n);
17431143Sbrian	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
17531143Sbrian	    (fp->saddr.s_addr & fp->smask.s_addr) &&
17631143Sbrian	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
17731143Sbrian	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
1786059Samurai	  if (fp->proto) {
1796059Samurai	    if (!gotinfo) {
18028679Sbrian	      ptop = (char *) pip + (pip->ip_hl << 2);
1816059Samurai
1826059Samurai	      switch (pip->ip_p) {
1836059Samurai	      case IPPROTO_ICMP:
18428679Sbrian		cproto = P_ICMP;
18528679Sbrian		ih = (struct icmp *) ptop;
18628679Sbrian		sport = ih->icmp_type;
18728679Sbrian		estab = 1;
1886059Samurai		break;
1896059Samurai	      case IPPROTO_UDP:
19028679Sbrian		cproto = P_UDP;
19128679Sbrian		uh = (struct udphdr *) ptop;
19228679Sbrian		sport = ntohs(uh->uh_sport);
19328679Sbrian		dport = ntohs(uh->uh_dport);
1946059Samurai		estab = 1;
1956059Samurai		break;
1966059Samurai	      case IPPROTO_TCP:
19728679Sbrian		cproto = P_TCP;
19828679Sbrian		th = (struct tcphdr *) ptop;
19928679Sbrian		sport = ntohs(th->th_sport);
20028679Sbrian		dport = ntohs(th->th_dport);
2016059Samurai		estab = (th->th_flags & TH_ACK);
20228679Sbrian		if (estab == 0)
20328679Sbrian		  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
20428679Sbrian			    th->th_flags, sport, dport);
2056059Samurai		break;
2066059Samurai	      default:
20728679Sbrian		return (A_DENY);/* We'll block unknown type of packet */
2086059Samurai	      }
2096059Samurai	      gotinfo = 1;
21028679Sbrian	      LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
21128679Sbrian			" dstop = %d, estab = %d\n", direction, cproto,
21228679Sbrian			fp->opt.srcop, fp->opt.dstop, estab);
2136059Samurai	    }
21426516Sbrian	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
21528679Sbrian		      " dport = %d\n", n, cproto, sport, dport);
21626516Sbrian	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
21726516Sbrian
2186059Samurai	    if (cproto == fp->proto) {
2196059Samurai	      if ((fp->opt.srcop == OP_NONE ||
22028679Sbrian		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
22128679Sbrian		  &&
2226059Samurai		  (fp->opt.dstop == OP_NONE ||
22328679Sbrian		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
22428679Sbrian		  &&
2256059Samurai		  (fp->opt.estab == 0 || estab)) {
22628679Sbrian		return (fp->action);
2276059Samurai	      }
2286059Samurai	    }
2296059Samurai	  } else {
2306059Samurai	    /* Address is mached. Make a decision. */
23126516Sbrian	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
23228679Sbrian	    return (fp->action);
2336059Samurai	  }
2346059Samurai	}
2356059Samurai      }
2366059Samurai      fp++;
2376059Samurai    }
23828679Sbrian    return (A_DENY);		/* No rule is mached. Deny this packet */
2396059Samurai  }
24028679Sbrian  return (A_PERMIT);		/* No rule is given. Permit this packet */
2416059Samurai}
2426059Samurai
2436059Samuraistatic void
24428679SbrianIcmpError(struct ip * pip, int code)
2456059Samurai{
2466059Samurai#ifdef notdef
2476059Samurai  struct mbuf *bp;
2486059Samurai
2496059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
2506059Samurai    bp = mballoc(cnt, MB_IPIN);
25130715Sbrian    memcpy(MBUF_CTOP(bp), ptr, cnt);
25213733Sdfr    SendPppFrame(bp);
2536059Samurai    RestartIdleTimer();
2546059Samurai    ipOutOctets += cnt;
2556059Samurai  }
2566059Samurai#endif
2576059Samurai}
2586059Samurai
2596059Samurai/*
2606059Samurai *  For debugging aid.
2616059Samurai */
2626059Samuraiint
26328679SbrianPacketCheck(char *cp, int nb, int direction)
2646059Samurai{
2656059Samurai  struct ip *pip;
2666059Samurai  struct tcphdr *th;
2676059Samurai  struct udphdr *uh;
2686059Samurai  struct icmp *icmph;
2696059Samurai  char *ptop;
2706059Samurai  int mask, len, n;
2716059Samurai  int pri = PRI_NORMAL;
27226692Sbrian  int logit, loglen;
27326692Sbrian  static char logbuf[200];
2746059Samurai
27526516Sbrian  logit = LogIsKept(LogTCPIP);
27626692Sbrian  loglen = 0;
2776059Samurai
27828679Sbrian  pip = (struct ip *) cp;
2798857Srgrimes
28026692Sbrian  if (logit && loglen < sizeof logbuf) {
28128679Sbrian    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ",
28228679Sbrian	     Direction[direction]);
28328679Sbrian    loglen += strlen(logbuf + loglen);
28426692Sbrian  }
2856059Samurai  ptop = (cp + (pip->ip_hl << 2));
2866059Samurai
2876059Samurai  switch (pip->ip_p) {
2886059Samurai  case IPPROTO_ICMP:
28926692Sbrian    if (logit && loglen < sizeof logbuf) {
29028679Sbrian      icmph = (struct icmp *) ptop;
29128679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
29228679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
29328679Sbrian      loglen += strlen(logbuf + loglen);
29428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
29528679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
29628679Sbrian      loglen += strlen(logbuf + loglen);
2976059Samurai    }
2986059Samurai    break;
2996059Samurai  case IPPROTO_UDP:
30026692Sbrian    if (logit && loglen < sizeof logbuf) {
30128679Sbrian      uh = (struct udphdr *) ptop;
30228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
30328679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
30428679Sbrian      loglen += strlen(logbuf + loglen);
30528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
30628679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
30728679Sbrian      loglen += strlen(logbuf + loglen);
3086059Samurai    }
3096059Samurai    break;
3106059Samurai  case IPPROTO_TCP:
31128679Sbrian    th = (struct tcphdr *) ptop;
3126059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
3136059Samurai      pri = PRI_FAST;
31413733Sdfr    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
3156059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
31628679Sbrian	pri = PRI_FAST;
3176059Samurai    }
31826692Sbrian    if (logit && loglen < sizeof logbuf) {
3196059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
32028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
32128679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
32228679Sbrian      loglen += strlen(logbuf + loglen);
32328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
32428679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
32528679Sbrian      loglen += strlen(logbuf + loglen);
3266059Samurai      n = 0;
3276059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
32826692Sbrian	if (th->th_flags & mask) {
32928679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
33028679Sbrian	  loglen += strlen(logbuf + loglen);
33128679Sbrian	}
3326059Samurai	n++;
3336059Samurai      }
33428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
33528679Sbrian	       "  seq:%x  ack:%x (%d/%d)",
33628679Sbrian	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
33728679Sbrian      loglen += strlen(logbuf + loglen);
3386059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
33928679Sbrian	u_short *sp;
3406059Samurai
3416059Samurai	ptop += 20;
34228679Sbrian	sp = (u_short *) ptop;
34326692Sbrian	if (ntohs(sp[0]) == 0x0204) {
34428679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
34528679Sbrian		   " MSS = %d", ntohs(sp[1]));
34628679Sbrian	  loglen += strlen(logbuf + loglen);
34728679Sbrian	}
3486059Samurai      }
3496059Samurai    }
3506059Samurai    break;
3516059Samurai  }
35226692Sbrian
35313733Sdfr  if ((FilterCheck(pip, direction) & A_DENY)) {
35431142Sbrian    if (logit)
35531142Sbrian      LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
35628679Sbrian    if (direction == 0)
35728679Sbrian      IcmpError(pip, pri);
35828679Sbrian    return (-1);
3596059Samurai  } else {
36028679Sbrian    if (FilterCheck(pip, FL_KEEP) & A_DENY) {	/* Check Keep Alive filter */
36131142Sbrian      if (logit)
36231142Sbrian        LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
36330715Sbrian      ipKeepAlive = 0;
3646735Samurai    } else {
36531142Sbrian      if (logit)
36631142Sbrian        LogPrintf(LogTCPIP, "%s\n", logbuf);
36730715Sbrian      ipKeepAlive = 1;
3686735Samurai    }
36928679Sbrian    return (pri);
3706059Samurai  }
3716059Samurai}
3726059Samurai
3736059Samuraivoid
37428679SbrianIpInput(struct mbuf * bp)
37528679Sbrian{				/* IN: Pointer to IP pakcet */
3766059Samurai  u_char *cp;
3776059Samurai  struct mbuf *wp;
3786059Samurai  int nb, nw;
37931195Sbrian  struct tun_data tun, *frag;
3806059Samurai
38131195Sbrian  tun_fill_header(tun, AF_INET);
38231195Sbrian  cp = tun.data;
3836059Samurai  nb = 0;
38428679Sbrian  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
38530715Sbrian    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
3866059Samurai    cp += wp->cnt;
3876059Samurai    nb += wp->cnt;
3886059Samurai  }
3896059Samurai
39020365Sjkh  if (mode & MODE_ALIAS) {
39126031Sbrian    int iresult;
39226031Sbrian    char *fptr;
39326031Sbrian
39431195Sbrian    iresult = VarPacketAliasIn(tun.data, sizeof tun.data);
39531195Sbrian    nb = ntohs(((struct ip *) tun.data)->ip_len);
39626031Sbrian
39726031Sbrian    if (nb > MAX_MRU) {
39826516Sbrian      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
39926031Sbrian      pfree(bp);
40026031Sbrian      return;
40126031Sbrian    }
40226031Sbrian    if (iresult == PKT_ALIAS_OK
40328679Sbrian	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
40431195Sbrian      if (PacketCheck(tun.data, nb, FL_IN) < 0) {
40528679Sbrian	pfree(bp);
40628679Sbrian	return;
40726031Sbrian      }
40826031Sbrian      ipInOctets += nb;
40926031Sbrian
41031195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
41131195Sbrian      nb += sizeof(tun)-sizeof(tun.data);
41231195Sbrian      nw = write(tun_out, &tun, nb);
41326031Sbrian      if (nw != nb)
41430092Sbrian        if (nw == -1)
41530092Sbrian	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
41630092Sbrian                    strerror(errno));
41730092Sbrian        else
41830092Sbrian	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
41926031Sbrian
42026031Sbrian      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
42131195Sbrian	while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) {
42231195Sbrian	  VarPacketAliasFragmentIn(tun.data, fptr);
42328679Sbrian	  nb = ntohs(((struct ip *) fptr)->ip_len);
42431195Sbrian          frag = (struct tun_data *)((char *)fptr-sizeof(tun)+sizeof(tun.data));
42531195Sbrian          nb += sizeof(tun)-sizeof(tun.data);
42631195Sbrian	  nw = write(tun_out, frag, nb);
42728679Sbrian	  if (nw != nb)
42830092Sbrian            if (nw == -1)
42930092Sbrian	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
43030092Sbrian                        strerror(errno));
43130092Sbrian            else
43230092Sbrian	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
43331195Sbrian	  free(frag);
43428679Sbrian	}
43526031Sbrian      }
43628679Sbrian    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
43731195Sbrian      nb = ntohs(((struct ip *) tun.data)->ip_len);
43831195Sbrian      nb += sizeof(tun)-sizeof(tun.data);
43931195Sbrian      frag = (struct tun_data *)malloc(nb);
44031195Sbrian      if (frag == NULL)
44128679Sbrian	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
44226031Sbrian      else {
44331195Sbrian        tun_fill_header(*frag, AF_INET);
44431195Sbrian	memcpy(frag->data, tun.data, nb-sizeof(tun)+sizeof(tun.data));
44531195Sbrian	VarPacketAliasSaveFragment(frag->data);
44626031Sbrian      }
44726031Sbrian    }
44828679Sbrian  } else {			/* no aliasing */
44931195Sbrian    if (PacketCheck(tun.data, nb, FL_IN) < 0) {
45026031Sbrian      pfree(bp);
45126031Sbrian      return;
45226031Sbrian    }
45326031Sbrian    ipInOctets += nb;
45431195Sbrian    nb += sizeof(tun)-sizeof(tun.data);
45531195Sbrian    nw = write(tun_out, &tun, nb);
45626031Sbrian    if (nw != nb)
45730092Sbrian      if (nw == -1)
45830092Sbrian	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
45930092Sbrian      else
46030092Sbrian        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4616059Samurai  }
4626059Samurai  pfree(bp);
4636059Samurai
4646059Samurai  RestartIdleTimer();
4656059Samurai}
4666059Samurai
46728679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1];
4686059Samurai
4696059Samuraivoid
47028679SbrianIpEnqueue(int pri, char *ptr, int count)
4716059Samurai{
4726059Samurai  struct mbuf *bp;
4736059Samurai
4746059Samurai  bp = mballoc(count, MB_IPQ);
47530715Sbrian  memcpy(MBUF_CTOP(bp), ptr, count);
4766059Samurai  Enqueue(&IpOutputQueues[pri], bp);
4776059Samurai}
4786059Samurai
47930715Sbrian#if 0
4808857Srgrimesint
4817001SamuraiIsIpEnqueued()
4827001Samurai{
4837001Samurai  struct mqueue *queue;
48430715Sbrian  int exist = 0;
48528679Sbrian
48613733Sdfr  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
48728679Sbrian    if (queue->qlen > 0) {
48830715Sbrian      exist = 1;
48928679Sbrian      break;
49028679Sbrian    }
4917001Samurai  }
49228679Sbrian  return (exist);
4937001Samurai}
49430715Sbrian#endif
4957001Samurai
4966059Samuraivoid
4976059SamuraiIpStartOutput()
4986059Samurai{
4996059Samurai  struct mqueue *queue;
5006059Samurai  struct mbuf *bp;
50125630Sbrian  int cnt;
5026059Samurai
5036059Samurai  if (IpcpFsm.state != ST_OPENED)
5046059Samurai    return;
50513733Sdfr  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
5066059Samurai    if (queue->top) {
5076059Samurai      bp = Dequeue(queue);
5086059Samurai      if (bp) {
5096059Samurai	cnt = plength(bp);
51013733Sdfr	SendPppFrame(bp);
5116059Samurai	RestartIdleTimer();
5126059Samurai	ipOutOctets += cnt;
51313733Sdfr	break;
51428679Sbrian      }
5156059Samurai    }
5166059Samurai  }
5176059Samurai}
518