xref: /freebsd/usr.sbin/ppp/ip.c (revision 1e991daad5c5de62b52ba8d458104aca32e69c27)
11ae349f5Scvs2svn /*
21ae349f5Scvs2svn  *		PPP IP Protocol Interface
31ae349f5Scvs2svn  *
41ae349f5Scvs2svn  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
51ae349f5Scvs2svn  *
61ae349f5Scvs2svn  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
71ae349f5Scvs2svn  *
81ae349f5Scvs2svn  * Redistribution and use in source and binary forms are permitted
91ae349f5Scvs2svn  * provided that the above copyright notice and this paragraph are
101ae349f5Scvs2svn  * duplicated in all such forms and that any documentation,
111ae349f5Scvs2svn  * advertising materials, and other materials related to such
121ae349f5Scvs2svn  * distribution and use acknowledge that the software was developed
131ae349f5Scvs2svn  * by the Internet Initiative Japan.  The name of the
141ae349f5Scvs2svn  * IIJ may not be used to endorse or promote products derived
151ae349f5Scvs2svn  * from this software without specific prior written permission.
161ae349f5Scvs2svn  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171ae349f5Scvs2svn  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181ae349f5Scvs2svn  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191ae349f5Scvs2svn  *
201e991daaSBrian Somers  * $Id: ip.c,v 1.38.2.15 1998/03/20 19:48:02 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  *	TODO:
231ae349f5Scvs2svn  *		o Return ICMP message for filterd packet
241ae349f5Scvs2svn  *		  and optionaly record it into log.
251ae349f5Scvs2svn  */
261ae349f5Scvs2svn #include <sys/param.h>
271ae349f5Scvs2svn #include <sys/time.h>
281ae349f5Scvs2svn #include <sys/socket.h>
291ae349f5Scvs2svn #include <net/if.h>
30d2fd8d77SBrian Somers #include <sys/select.h>
311ae349f5Scvs2svn #include <net/if_tun.h>
321ae349f5Scvs2svn #include <netinet/in.h>
331ae349f5Scvs2svn #include <netinet/in_systm.h>
341ae349f5Scvs2svn #include <netinet/ip.h>
351ae349f5Scvs2svn #include <netinet/ip_icmp.h>
361ae349f5Scvs2svn #include <netinet/udp.h>
371ae349f5Scvs2svn #include <netinet/tcp.h>
381ae349f5Scvs2svn #include <arpa/inet.h>
391ae349f5Scvs2svn 
401ae349f5Scvs2svn #ifndef NOALIAS
411ae349f5Scvs2svn #include <alias.h>
421ae349f5Scvs2svn #endif
431ae349f5Scvs2svn #include <errno.h>
441ae349f5Scvs2svn #include <stdio.h>
451ae349f5Scvs2svn #include <stdlib.h>
461ae349f5Scvs2svn #include <string.h>
471ae349f5Scvs2svn #include <termios.h>
481ae349f5Scvs2svn #include <unistd.h>
491ae349f5Scvs2svn 
501ae349f5Scvs2svn #include "command.h"
511ae349f5Scvs2svn #include "mbuf.h"
521ae349f5Scvs2svn #include "log.h"
531ae349f5Scvs2svn #include "defs.h"
541ae349f5Scvs2svn #include "timer.h"
551ae349f5Scvs2svn #include "fsm.h"
56879ed6faSBrian Somers #include "lqr.h"
571ae349f5Scvs2svn #include "hdlc.h"
581ae349f5Scvs2svn #include "loadalias.h"
591ae349f5Scvs2svn #include "vars.h"
605828db6dSBrian Somers #include "throughput.h"
615828db6dSBrian Somers #include "iplist.h"
62eaa4df37SBrian Somers #include "slcompress.h"
635828db6dSBrian Somers #include "ipcp.h"
641ae349f5Scvs2svn #include "filter.h"
652f786681SBrian Somers #include "descriptor.h"
667a6f8720SBrian Somers #include "bundle.h"
671ae349f5Scvs2svn #include "vjcomp.h"
681ae349f5Scvs2svn #include "lcp.h"
691ae349f5Scvs2svn #include "modem.h"
701ae349f5Scvs2svn #include "tun.h"
711ae349f5Scvs2svn #include "ip.h"
721ae349f5Scvs2svn 
731ae349f5Scvs2svn static const u_short interactive_ports[32] = {
741ae349f5Scvs2svn   544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
751ae349f5Scvs2svn   0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
761ae349f5Scvs2svn };
771ae349f5Scvs2svn 
781ae349f5Scvs2svn #define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
791ae349f5Scvs2svn 
801ae349f5Scvs2svn static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
811ae349f5Scvs2svn 
821ae349f5Scvs2svn static int
831ae349f5Scvs2svn PortMatch(int op, u_short pport, u_short rport)
841ae349f5Scvs2svn {
851ae349f5Scvs2svn   switch (op) {
861ae349f5Scvs2svn     case OP_EQ:
871ae349f5Scvs2svn     return (pport == rport);
881ae349f5Scvs2svn   case OP_GT:
891ae349f5Scvs2svn     return (pport > rport);
901ae349f5Scvs2svn   case OP_LT:
911ae349f5Scvs2svn     return (pport < rport);
921ae349f5Scvs2svn   default:
931ae349f5Scvs2svn     return (0);
941ae349f5Scvs2svn   }
951ae349f5Scvs2svn }
961ae349f5Scvs2svn 
971ae349f5Scvs2svn /*
981ae349f5Scvs2svn  *  Check a packet against with defined filters
991ae349f5Scvs2svn  */
1001ae349f5Scvs2svn static int
1015ca5389aSBrian Somers FilterCheck(struct ip *pip, struct filter *filter)
1021ae349f5Scvs2svn {
1031ae349f5Scvs2svn   int gotinfo, cproto, estab, n;
1041ae349f5Scvs2svn   struct tcphdr *th;
1051ae349f5Scvs2svn   struct udphdr *uh;
1061ae349f5Scvs2svn   struct icmp *ih;
1071ae349f5Scvs2svn   char *ptop;
1081ae349f5Scvs2svn   u_short sport, dport;
1095ca5389aSBrian Somers   struct filterent *fp = filter->rule;
1101ae349f5Scvs2svn 
1111ae349f5Scvs2svn   if (fp->action) {
1121ae349f5Scvs2svn     cproto = gotinfo = estab = 0;
1131ae349f5Scvs2svn     sport = dport = 0;
1141ae349f5Scvs2svn     for (n = 0; n < MAXFILTERS; n++) {
1151ae349f5Scvs2svn       if (fp->action) {
1161ae349f5Scvs2svn 	/* permit fragments on in and out filter */
1175ca5389aSBrian Somers         if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0)
1181ae349f5Scvs2svn 	  return (A_PERMIT);
1195ca5389aSBrian Somers 
1201ae349f5Scvs2svn 	LogPrintf(LogDEBUG, "rule = %d\n", n);
1211ae349f5Scvs2svn 	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
1221ae349f5Scvs2svn 	    (fp->saddr.s_addr & fp->smask.s_addr) &&
1231ae349f5Scvs2svn 	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
1241ae349f5Scvs2svn 	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
1251ae349f5Scvs2svn 	  if (fp->proto) {
1261ae349f5Scvs2svn 	    if (!gotinfo) {
1271ae349f5Scvs2svn 	      ptop = (char *) pip + (pip->ip_hl << 2);
1281ae349f5Scvs2svn 
1291ae349f5Scvs2svn 	      switch (pip->ip_p) {
1301ae349f5Scvs2svn 	      case IPPROTO_ICMP:
1311ae349f5Scvs2svn 		cproto = P_ICMP;
1321ae349f5Scvs2svn 		ih = (struct icmp *) ptop;
1331ae349f5Scvs2svn 		sport = ih->icmp_type;
1341ae349f5Scvs2svn 		estab = 1;
1351ae349f5Scvs2svn 		break;
1361ae349f5Scvs2svn 	      case IPPROTO_UDP:
1371ae349f5Scvs2svn 		cproto = P_UDP;
1381ae349f5Scvs2svn 		uh = (struct udphdr *) ptop;
1391ae349f5Scvs2svn 		sport = ntohs(uh->uh_sport);
1401ae349f5Scvs2svn 		dport = ntohs(uh->uh_dport);
1411ae349f5Scvs2svn 		estab = 1;
1421ae349f5Scvs2svn 		break;
1431ae349f5Scvs2svn 	      case IPPROTO_TCP:
1441ae349f5Scvs2svn 		cproto = P_TCP;
1451ae349f5Scvs2svn 		th = (struct tcphdr *) ptop;
1461ae349f5Scvs2svn 		sport = ntohs(th->th_sport);
1471ae349f5Scvs2svn 		dport = ntohs(th->th_dport);
1481ae349f5Scvs2svn 		estab = (th->th_flags & TH_ACK);
1491ae349f5Scvs2svn 		if (estab == 0)
1501ae349f5Scvs2svn 		  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
1511ae349f5Scvs2svn 			    th->th_flags, sport, dport);
1521ae349f5Scvs2svn 		break;
1531ae349f5Scvs2svn 	      default:
1541ae349f5Scvs2svn 		return (A_DENY);/* We'll block unknown type of packet */
1551ae349f5Scvs2svn 	      }
1561ae349f5Scvs2svn 	      gotinfo = 1;
1575ca5389aSBrian Somers 	      LogPrintf(LogDEBUG, "dir = %p, proto = %d, srcop = %d,"
1585ca5389aSBrian Somers 			" dstop = %d, estab = %d\n", fp, cproto,
1591ae349f5Scvs2svn 			fp->opt.srcop, fp->opt.dstop, estab);
1601ae349f5Scvs2svn 	    }
1611ae349f5Scvs2svn 	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
1621ae349f5Scvs2svn 		      " dport = %d\n", n, cproto, sport, dport);
1631ae349f5Scvs2svn 	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
1641ae349f5Scvs2svn 
1651ae349f5Scvs2svn 	    if (cproto == fp->proto) {
1661ae349f5Scvs2svn 	      if ((fp->opt.srcop == OP_NONE ||
1671ae349f5Scvs2svn 		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
1681ae349f5Scvs2svn 		  &&
1691ae349f5Scvs2svn 		  (fp->opt.dstop == OP_NONE ||
1701ae349f5Scvs2svn 		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
1711ae349f5Scvs2svn 		  &&
1721ae349f5Scvs2svn 		  (fp->opt.estab == 0 || estab)) {
1731ae349f5Scvs2svn 		return (fp->action);
1741ae349f5Scvs2svn 	      }
1751ae349f5Scvs2svn 	    }
1761ae349f5Scvs2svn 	  } else {
1771ae349f5Scvs2svn 	    /* Address is mached. Make a decision. */
1781ae349f5Scvs2svn 	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
1791ae349f5Scvs2svn 	    return (fp->action);
1801ae349f5Scvs2svn 	  }
1811ae349f5Scvs2svn 	}
1821ae349f5Scvs2svn       }
1831ae349f5Scvs2svn       fp++;
1841ae349f5Scvs2svn     }
1851ae349f5Scvs2svn     return (A_DENY);		/* No rule is mached. Deny this packet */
1861ae349f5Scvs2svn   }
1871ae349f5Scvs2svn   return (A_PERMIT);		/* No rule is given. Permit this packet */
1881ae349f5Scvs2svn }
1891ae349f5Scvs2svn 
1905ca5389aSBrian Somers #ifdef notdef
1911ae349f5Scvs2svn static void
1921ae349f5Scvs2svn IcmpError(struct ip * pip, int code)
1931ae349f5Scvs2svn {
1941ae349f5Scvs2svn   struct mbuf *bp;
1951ae349f5Scvs2svn 
1961ae349f5Scvs2svn   if (pip->ip_p != IPPROTO_ICMP) {
1971ae349f5Scvs2svn     bp = mballoc(cnt, MB_IPIN);
1981ae349f5Scvs2svn     memcpy(MBUF_CTOP(bp), ptr, cnt);
1991ae349f5Scvs2svn     SendPppFrame(bp);
2005828db6dSBrian Somers     ipcp_AddOutOctets(cnt);
2011ae349f5Scvs2svn   }
2021ae349f5Scvs2svn }
2035ca5389aSBrian Somers #endif
2041ae349f5Scvs2svn 
2051ae349f5Scvs2svn /*
2061ae349f5Scvs2svn  *  For debugging aid.
2071ae349f5Scvs2svn  */
2081ae349f5Scvs2svn int
2095ca5389aSBrian Somers PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
2101ae349f5Scvs2svn {
2111ae349f5Scvs2svn   struct ip *pip;
2121ae349f5Scvs2svn   struct tcphdr *th;
2131ae349f5Scvs2svn   struct udphdr *uh;
2141ae349f5Scvs2svn   struct icmp *icmph;
2151ae349f5Scvs2svn   char *ptop;
2161ae349f5Scvs2svn   int mask, len, n;
2171ae349f5Scvs2svn   int pri = PRI_NORMAL;
2181ae349f5Scvs2svn   int logit, loglen;
2191ae349f5Scvs2svn   static char logbuf[200];
2201ae349f5Scvs2svn 
2215ca5389aSBrian Somers   logit = LogIsKept(LogTCPIP) && filter->logok;
2221ae349f5Scvs2svn   loglen = 0;
2231ae349f5Scvs2svn 
2241ae349f5Scvs2svn   pip = (struct ip *) cp;
2251ae349f5Scvs2svn 
2261ae349f5Scvs2svn   if (logit && loglen < sizeof logbuf) {
2275ca5389aSBrian Somers     snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
2281ae349f5Scvs2svn     loglen += strlen(logbuf + loglen);
2291ae349f5Scvs2svn   }
2301ae349f5Scvs2svn   ptop = (cp + (pip->ip_hl << 2));
2311ae349f5Scvs2svn 
2321ae349f5Scvs2svn   switch (pip->ip_p) {
2331ae349f5Scvs2svn   case IPPROTO_ICMP:
2341ae349f5Scvs2svn     if (logit && loglen < sizeof logbuf) {
2351ae349f5Scvs2svn       icmph = (struct icmp *) ptop;
2361ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2371ae349f5Scvs2svn 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
2381ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2391ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2401ae349f5Scvs2svn 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
2411ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2421ae349f5Scvs2svn     }
2431ae349f5Scvs2svn     break;
2441ae349f5Scvs2svn   case IPPROTO_UDP:
2451ae349f5Scvs2svn     if (logit && loglen < sizeof logbuf) {
2461ae349f5Scvs2svn       uh = (struct udphdr *) ptop;
2471ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2481ae349f5Scvs2svn 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
2491ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2501ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2511ae349f5Scvs2svn 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
2521ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2531ae349f5Scvs2svn     }
2541ae349f5Scvs2svn     break;
2551ae349f5Scvs2svn   case IPPROTO_TCP:
2561ae349f5Scvs2svn     th = (struct tcphdr *) ptop;
2571ae349f5Scvs2svn     if (pip->ip_tos == IPTOS_LOWDELAY)
2581ae349f5Scvs2svn       pri = PRI_FAST;
2591ae349f5Scvs2svn     else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
2601ae349f5Scvs2svn       if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
2611ae349f5Scvs2svn 	pri = PRI_FAST;
2621ae349f5Scvs2svn     }
2631ae349f5Scvs2svn     if (logit && loglen < sizeof logbuf) {
2641ae349f5Scvs2svn       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
2651ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2661ae349f5Scvs2svn 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
2671ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2681ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2691ae349f5Scvs2svn 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
2701ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2711ae349f5Scvs2svn       n = 0;
2721ae349f5Scvs2svn       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
2731ae349f5Scvs2svn 	if (th->th_flags & mask) {
2741ae349f5Scvs2svn 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
2751ae349f5Scvs2svn 	  loglen += strlen(logbuf + loglen);
2761ae349f5Scvs2svn 	}
2771ae349f5Scvs2svn 	n++;
2781ae349f5Scvs2svn       }
2791ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2801ae349f5Scvs2svn 	       "  seq:%x  ack:%x (%d/%d)",
2811ae349f5Scvs2svn 	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
2821ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2831ae349f5Scvs2svn       if ((th->th_flags & TH_SYN) && nb > 40) {
2841ae349f5Scvs2svn 	u_short *sp;
2851ae349f5Scvs2svn 
2861ae349f5Scvs2svn 	ptop += 20;
2871ae349f5Scvs2svn 	sp = (u_short *) ptop;
2881ae349f5Scvs2svn 	if (ntohs(sp[0]) == 0x0204) {
2891ae349f5Scvs2svn 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
2901ae349f5Scvs2svn 		   " MSS = %d", ntohs(sp[1]));
2911ae349f5Scvs2svn 	  loglen += strlen(logbuf + loglen);
2921ae349f5Scvs2svn 	}
2931ae349f5Scvs2svn       }
2941ae349f5Scvs2svn     }
2951ae349f5Scvs2svn     break;
2961ae349f5Scvs2svn   }
2971ae349f5Scvs2svn 
2985ca5389aSBrian Somers   if ((FilterCheck(pip, filter) & A_DENY)) {
2991ae349f5Scvs2svn     if (logit)
3001ae349f5Scvs2svn       LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
3015ca5389aSBrian Somers #ifdef notdef
3021ae349f5Scvs2svn     if (direction == 0)
3031ae349f5Scvs2svn       IcmpError(pip, pri);
3045ca5389aSBrian Somers #endif
3051ae349f5Scvs2svn     return (-1);
3061ae349f5Scvs2svn   } else {
3075ca5389aSBrian Somers     /* Check Keep Alive filter */
3081ae349f5Scvs2svn     if (logit)
3091e991daaSBrian Somers       if (FilterCheck(pip, &bundle->filter.alive) & A_DENY)
3101ae349f5Scvs2svn         LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
3111e991daaSBrian Somers       else
3121ae349f5Scvs2svn         LogPrintf(LogTCPIP, "%s\n", logbuf);
3131ae349f5Scvs2svn     return (pri);
3141ae349f5Scvs2svn   }
3151ae349f5Scvs2svn }
3161ae349f5Scvs2svn 
3171ae349f5Scvs2svn void
3187a6f8720SBrian Somers IpInput(struct bundle *bundle, struct mbuf * bp)
3197a6f8720SBrian Somers {
3201ae349f5Scvs2svn   u_char *cp;
3211ae349f5Scvs2svn   struct mbuf *wp;
3221ae349f5Scvs2svn   int nb, nw;
3231ae349f5Scvs2svn   struct tun_data tun;
3241e991daaSBrian Somers   struct ip *pip = (struct ip *)tun.data;
3251ae349f5Scvs2svn 
3261ae349f5Scvs2svn   tun_fill_header(tun, AF_INET);
3271ae349f5Scvs2svn   cp = tun.data;
3281ae349f5Scvs2svn   nb = 0;
3291ae349f5Scvs2svn   for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
3301ae349f5Scvs2svn     if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
3311ae349f5Scvs2svn       LogPrintf(LogERROR, "IpInput: Packet too large (%d) - dropped\n",
3321ae349f5Scvs2svn                 plength(bp));
3331ae349f5Scvs2svn       pfree(bp);
3341ae349f5Scvs2svn       return;
3351ae349f5Scvs2svn     }
3361ae349f5Scvs2svn     memcpy(cp, MBUF_CTOP(wp), wp->cnt);
3371ae349f5Scvs2svn     cp += wp->cnt;
3381ae349f5Scvs2svn     nb += wp->cnt;
3391ae349f5Scvs2svn   }
3401ae349f5Scvs2svn 
3411ae349f5Scvs2svn #ifndef NOALIAS
3421ae349f5Scvs2svn   if (mode & MODE_ALIAS) {
3431ae349f5Scvs2svn     struct tun_data *frag;
3441ae349f5Scvs2svn     int iresult;
3451ae349f5Scvs2svn     char *fptr;
3461ae349f5Scvs2svn 
3471ae349f5Scvs2svn     iresult = VarPacketAliasIn(tun.data, sizeof tun.data);
3481ae349f5Scvs2svn     nb = ntohs(((struct ip *) tun.data)->ip_len);
3491ae349f5Scvs2svn 
3501ae349f5Scvs2svn     if (nb > MAX_MRU) {
3511ae349f5Scvs2svn       LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
3521ae349f5Scvs2svn       pfree(bp);
3531ae349f5Scvs2svn       return;
3541ae349f5Scvs2svn     }
3551ae349f5Scvs2svn     if (iresult == PKT_ALIAS_OK
3561ae349f5Scvs2svn 	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
3575ca5389aSBrian Somers       if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
3581ae349f5Scvs2svn 	pfree(bp);
3591ae349f5Scvs2svn 	return;
3601ae349f5Scvs2svn       }
3611e991daaSBrian Somers 
3621e991daaSBrian Somers       if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
3631e991daaSBrian Somers         bundle_StartIdleTimer(bundle);
3641e991daaSBrian Somers 
3655828db6dSBrian Somers       ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
3661ae349f5Scvs2svn 
3671ae349f5Scvs2svn       nb = ntohs(((struct ip *) tun.data)->ip_len);
3681ae349f5Scvs2svn       nb += sizeof tun - sizeof tun.data;
3697a6f8720SBrian Somers       nw = write(bundle->tun_fd, &tun, nb);
3701ae349f5Scvs2svn       if (nw != nb)
3711ae349f5Scvs2svn         if (nw == -1)
3721ae349f5Scvs2svn 	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
3731ae349f5Scvs2svn                     strerror(errno));
3741ae349f5Scvs2svn         else
3751ae349f5Scvs2svn 	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
3761ae349f5Scvs2svn 
3771ae349f5Scvs2svn       if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
3781ae349f5Scvs2svn 	while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) {
3791ae349f5Scvs2svn 	  VarPacketAliasFragmentIn(tun.data, fptr);
3801ae349f5Scvs2svn 	  nb = ntohs(((struct ip *) fptr)->ip_len);
3811ae349f5Scvs2svn           frag = (struct tun_data *)
3821ae349f5Scvs2svn 	    ((char *)fptr - sizeof tun + sizeof tun.data);
3831ae349f5Scvs2svn           nb += sizeof tun - sizeof tun.data;
3847a6f8720SBrian Somers 	  nw = write(bundle->tun_fd, frag, nb);
3851ae349f5Scvs2svn 	  if (nw != nb)
3861ae349f5Scvs2svn             if (nw == -1)
3871ae349f5Scvs2svn 	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
3881ae349f5Scvs2svn                         strerror(errno));
3891ae349f5Scvs2svn             else
3901ae349f5Scvs2svn 	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
3911ae349f5Scvs2svn 	  free(frag);
3921ae349f5Scvs2svn 	}
3931ae349f5Scvs2svn       }
3941ae349f5Scvs2svn     } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
3951ae349f5Scvs2svn       nb = ntohs(((struct ip *) tun.data)->ip_len);
3961ae349f5Scvs2svn       nb += sizeof tun - sizeof tun.data;
3971ae349f5Scvs2svn       frag = (struct tun_data *)malloc(nb);
3981ae349f5Scvs2svn       if (frag == NULL)
3991ae349f5Scvs2svn 	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
4001ae349f5Scvs2svn       else {
4011ae349f5Scvs2svn         tun_fill_header(*frag, AF_INET);
4021ae349f5Scvs2svn 	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
4031ae349f5Scvs2svn 	VarPacketAliasSaveFragment(frag->data);
4041ae349f5Scvs2svn       }
4051ae349f5Scvs2svn     }
4061ae349f5Scvs2svn   } else
4071ae349f5Scvs2svn #endif /* #ifndef NOALIAS */
4081ae349f5Scvs2svn   {			/* no aliasing */
4095ca5389aSBrian Somers     if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
4101ae349f5Scvs2svn       pfree(bp);
4111ae349f5Scvs2svn       return;
4121ae349f5Scvs2svn     }
4131e991daaSBrian Somers 
4141e991daaSBrian Somers     if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
4151e991daaSBrian Somers       bundle_StartIdleTimer(bundle);
4161e991daaSBrian Somers 
4175828db6dSBrian Somers     ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
4181e991daaSBrian Somers 
4191ae349f5Scvs2svn     nb += sizeof tun - sizeof tun.data;
4207a6f8720SBrian Somers     nw = write(bundle->tun_fd, &tun, nb);
4211ae349f5Scvs2svn     if (nw != nb)
4221ae349f5Scvs2svn       if (nw == -1)
4231ae349f5Scvs2svn 	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
4241ae349f5Scvs2svn       else
4251ae349f5Scvs2svn         LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4261ae349f5Scvs2svn   }
4271ae349f5Scvs2svn   pfree(bp);
4281ae349f5Scvs2svn }
4291ae349f5Scvs2svn 
4301ae349f5Scvs2svn static struct mqueue IpOutputQueues[PRI_FAST + 1];
4311ae349f5Scvs2svn 
4321ae349f5Scvs2svn void
4331ae349f5Scvs2svn IpEnqueue(int pri, char *ptr, int count)
4341ae349f5Scvs2svn {
4351ae349f5Scvs2svn   struct mbuf *bp;
4361ae349f5Scvs2svn 
4371ae349f5Scvs2svn   bp = mballoc(count, MB_IPQ);
4381ae349f5Scvs2svn   memcpy(MBUF_CTOP(bp), ptr, count);
4391ae349f5Scvs2svn   Enqueue(&IpOutputQueues[pri], bp);
4401ae349f5Scvs2svn }
4411ae349f5Scvs2svn 
4421ae349f5Scvs2svn int
443f4768038SBrian Somers ip_QueueLen()
4441ae349f5Scvs2svn {
4451ae349f5Scvs2svn   struct mqueue *queue;
446f4768038SBrian Somers   int result = 0;
4471ae349f5Scvs2svn 
448f4768038SBrian Somers   for (queue = &IpOutputQueues[PRI_MAX]; queue >= IpOutputQueues; queue--)
449f4768038SBrian Somers     result += queue->qlen;
450f4768038SBrian Somers 
451f4768038SBrian Somers   return result;
4521ae349f5Scvs2svn }
4531ae349f5Scvs2svn 
4541ae349f5Scvs2svn void
455f4768038SBrian Somers IpStartOutput(struct link *l, struct bundle *bundle)
4561ae349f5Scvs2svn {
4571ae349f5Scvs2svn   struct mqueue *queue;
4581ae349f5Scvs2svn   struct mbuf *bp;
4591ae349f5Scvs2svn   int cnt;
4601ae349f5Scvs2svn 
4615828db6dSBrian Somers   if (bundle->ncp.ipcp.fsm.state != ST_OPENED)
4621ae349f5Scvs2svn     return;
4631e991daaSBrian Somers 
4641e991daaSBrian Somers   for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--)
4651ae349f5Scvs2svn     if (queue->top) {
4661ae349f5Scvs2svn       bp = Dequeue(queue);
4671ae349f5Scvs2svn       if (bp) {
4681e991daaSBrian Somers         struct ip *pip = (struct ip *)MBUF_CTOP(bp);
4691e991daaSBrian Somers 
4701ae349f5Scvs2svn 	cnt = plength(bp);
471f4768038SBrian Somers 	SendPppFrame(l, bp, bundle);
4721e991daaSBrian Somers         if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
473ab886ad0SBrian Somers           bundle_StartIdleTimer(bundle);
4745828db6dSBrian Somers         ipcp_AddOutOctets(&bundle->ncp.ipcp, cnt);
4751ae349f5Scvs2svn 	break;
4761ae349f5Scvs2svn       }
4771ae349f5Scvs2svn     }
4781e991daaSBrian Somers 
4791ae349f5Scvs2svn }
480