xref: /freebsd/usr.sbin/ppp/ip.c (revision 1ae349f52c53416e04f1d038a8210f1a9fa7db2c)
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  *
201ae349f5Scvs2svn  * $Id: ip.c,v 1.37 1998/01/11 17:53:18 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>
301ae349f5Scvs2svn #include <net/if_tun.h>
311ae349f5Scvs2svn #include <netinet/in.h>
321ae349f5Scvs2svn #include <netinet/in_systm.h>
331ae349f5Scvs2svn #include <netinet/ip.h>
341ae349f5Scvs2svn #include <netinet/ip_icmp.h>
351ae349f5Scvs2svn #include <netinet/udp.h>
361ae349f5Scvs2svn #include <netinet/tcp.h>
371ae349f5Scvs2svn #include <arpa/inet.h>
381ae349f5Scvs2svn 
391ae349f5Scvs2svn #ifndef NOALIAS
401ae349f5Scvs2svn #include <alias.h>
411ae349f5Scvs2svn #endif
421ae349f5Scvs2svn #include <errno.h>
431ae349f5Scvs2svn #include <stdio.h>
441ae349f5Scvs2svn #include <stdlib.h>
451ae349f5Scvs2svn #include <string.h>
461ae349f5Scvs2svn #include <termios.h>
471ae349f5Scvs2svn #include <unistd.h>
481ae349f5Scvs2svn 
491ae349f5Scvs2svn #include "command.h"
501ae349f5Scvs2svn #include "mbuf.h"
511ae349f5Scvs2svn #include "log.h"
521ae349f5Scvs2svn #include "defs.h"
531ae349f5Scvs2svn #include "timer.h"
541ae349f5Scvs2svn #include "fsm.h"
551ae349f5Scvs2svn #include "hdlc.h"
561ae349f5Scvs2svn #include "loadalias.h"
571ae349f5Scvs2svn #include "vars.h"
581ae349f5Scvs2svn #include "filter.h"
591ae349f5Scvs2svn #include "os.h"
601ae349f5Scvs2svn #include "ipcp.h"
611ae349f5Scvs2svn #include "vjcomp.h"
621ae349f5Scvs2svn #include "lcp.h"
631ae349f5Scvs2svn #include "modem.h"
641ae349f5Scvs2svn #include "tun.h"
651ae349f5Scvs2svn #include "ip.h"
661ae349f5Scvs2svn 
671ae349f5Scvs2svn static struct pppTimer IdleTimer;
681ae349f5Scvs2svn 
691ae349f5Scvs2svn static void
701ae349f5Scvs2svn IdleTimeout(void *v)
711ae349f5Scvs2svn {
721ae349f5Scvs2svn   LogPrintf(LogPHASE, "Idle timer expired.\n");
731ae349f5Scvs2svn   reconnect(RECON_FALSE);
741ae349f5Scvs2svn   LcpClose();
751ae349f5Scvs2svn }
761ae349f5Scvs2svn 
771ae349f5Scvs2svn /*
781ae349f5Scvs2svn  *  Start Idle timer. If timeout is reached, we call LcpClose() to
791ae349f5Scvs2svn  *  close LCP and link.
801ae349f5Scvs2svn  */
811ae349f5Scvs2svn void
821ae349f5Scvs2svn StartIdleTimer()
831ae349f5Scvs2svn {
841ae349f5Scvs2svn   static time_t IdleStarted;
851ae349f5Scvs2svn 
861ae349f5Scvs2svn   if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) {
871ae349f5Scvs2svn     StopTimer(&IdleTimer);
881ae349f5Scvs2svn     IdleTimer.func = IdleTimeout;
891ae349f5Scvs2svn     IdleTimer.load = VarIdleTimeout * SECTICKS;
901ae349f5Scvs2svn     IdleTimer.state = TIMER_STOPPED;
911ae349f5Scvs2svn     time(&IdleStarted);
921ae349f5Scvs2svn     IdleTimer.arg = (void *)&IdleStarted;
931ae349f5Scvs2svn     StartTimer(&IdleTimer);
941ae349f5Scvs2svn   }
951ae349f5Scvs2svn }
961ae349f5Scvs2svn 
971ae349f5Scvs2svn void
981ae349f5Scvs2svn UpdateIdleTimer()
991ae349f5Scvs2svn {
1001ae349f5Scvs2svn   if (OsLinkIsUp())
1011ae349f5Scvs2svn     StartIdleTimer();
1021ae349f5Scvs2svn }
1031ae349f5Scvs2svn 
1041ae349f5Scvs2svn void
1051ae349f5Scvs2svn StopIdleTimer()
1061ae349f5Scvs2svn {
1071ae349f5Scvs2svn   StopTimer(&IdleTimer);
1081ae349f5Scvs2svn }
1091ae349f5Scvs2svn 
1101ae349f5Scvs2svn int
1111ae349f5Scvs2svn RemainingIdleTime()
1121ae349f5Scvs2svn {
1131ae349f5Scvs2svn   if (VarIdleTimeout == 0 || IdleTimer.state != TIMER_RUNNING ||
1141ae349f5Scvs2svn       IdleTimer.arg == NULL)
1151ae349f5Scvs2svn     return -1;
1161ae349f5Scvs2svn   return VarIdleTimeout - (time(NULL) - *(time_t *)IdleTimer.arg);
1171ae349f5Scvs2svn }
1181ae349f5Scvs2svn 
1191ae349f5Scvs2svn /*
1201ae349f5Scvs2svn  *  If any IP layer traffic is detected, refresh IdleTimer.
1211ae349f5Scvs2svn  */
1221ae349f5Scvs2svn static void
1231ae349f5Scvs2svn RestartIdleTimer(void)
1241ae349f5Scvs2svn {
1251ae349f5Scvs2svn   if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) {
1261ae349f5Scvs2svn     time((time_t *)IdleTimer.arg);
1271ae349f5Scvs2svn     StartTimer(&IdleTimer);
1281ae349f5Scvs2svn   }
1291ae349f5Scvs2svn }
1301ae349f5Scvs2svn 
1311ae349f5Scvs2svn static const u_short interactive_ports[32] = {
1321ae349f5Scvs2svn   544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1331ae349f5Scvs2svn   0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
1341ae349f5Scvs2svn };
1351ae349f5Scvs2svn 
1361ae349f5Scvs2svn #define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
1371ae349f5Scvs2svn 
1381ae349f5Scvs2svn static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
1391ae349f5Scvs2svn 
1401ae349f5Scvs2svn static const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"};
1411ae349f5Scvs2svn static struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters};
1421ae349f5Scvs2svn 
1431ae349f5Scvs2svn static int
1441ae349f5Scvs2svn PortMatch(int op, u_short pport, u_short rport)
1451ae349f5Scvs2svn {
1461ae349f5Scvs2svn   switch (op) {
1471ae349f5Scvs2svn     case OP_EQ:
1481ae349f5Scvs2svn     return (pport == rport);
1491ae349f5Scvs2svn   case OP_GT:
1501ae349f5Scvs2svn     return (pport > rport);
1511ae349f5Scvs2svn   case OP_LT:
1521ae349f5Scvs2svn     return (pport < rport);
1531ae349f5Scvs2svn   default:
1541ae349f5Scvs2svn     return (0);
1551ae349f5Scvs2svn   }
1561ae349f5Scvs2svn }
1571ae349f5Scvs2svn 
1581ae349f5Scvs2svn /*
1591ae349f5Scvs2svn  *  Check a packet against with defined filters
1601ae349f5Scvs2svn  */
1611ae349f5Scvs2svn static int
1621ae349f5Scvs2svn FilterCheck(struct ip * pip, int direction)
1631ae349f5Scvs2svn {
1641ae349f5Scvs2svn   struct filterent *fp = Filters[direction];
1651ae349f5Scvs2svn   int gotinfo, cproto, estab, n;
1661ae349f5Scvs2svn   struct tcphdr *th;
1671ae349f5Scvs2svn   struct udphdr *uh;
1681ae349f5Scvs2svn   struct icmp *ih;
1691ae349f5Scvs2svn   char *ptop;
1701ae349f5Scvs2svn   u_short sport, dport;
1711ae349f5Scvs2svn 
1721ae349f5Scvs2svn   if (fp->action) {
1731ae349f5Scvs2svn     cproto = gotinfo = estab = 0;
1741ae349f5Scvs2svn     sport = dport = 0;
1751ae349f5Scvs2svn     for (n = 0; n < MAXFILTERS; n++) {
1761ae349f5Scvs2svn       if (fp->action) {
1771ae349f5Scvs2svn 	/* permit fragments on in and out filter */
1781ae349f5Scvs2svn 	if ((direction == FL_IN || direction == FL_OUT) &&
1791ae349f5Scvs2svn 	    (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
1801ae349f5Scvs2svn 	  return (A_PERMIT);
1811ae349f5Scvs2svn 	}
1821ae349f5Scvs2svn 	LogPrintf(LogDEBUG, "rule = %d\n", n);
1831ae349f5Scvs2svn 	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
1841ae349f5Scvs2svn 	    (fp->saddr.s_addr & fp->smask.s_addr) &&
1851ae349f5Scvs2svn 	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
1861ae349f5Scvs2svn 	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
1871ae349f5Scvs2svn 	  if (fp->proto) {
1881ae349f5Scvs2svn 	    if (!gotinfo) {
1891ae349f5Scvs2svn 	      ptop = (char *) pip + (pip->ip_hl << 2);
1901ae349f5Scvs2svn 
1911ae349f5Scvs2svn 	      switch (pip->ip_p) {
1921ae349f5Scvs2svn 	      case IPPROTO_ICMP:
1931ae349f5Scvs2svn 		cproto = P_ICMP;
1941ae349f5Scvs2svn 		ih = (struct icmp *) ptop;
1951ae349f5Scvs2svn 		sport = ih->icmp_type;
1961ae349f5Scvs2svn 		estab = 1;
1971ae349f5Scvs2svn 		break;
1981ae349f5Scvs2svn 	      case IPPROTO_UDP:
1991ae349f5Scvs2svn 		cproto = P_UDP;
2001ae349f5Scvs2svn 		uh = (struct udphdr *) ptop;
2011ae349f5Scvs2svn 		sport = ntohs(uh->uh_sport);
2021ae349f5Scvs2svn 		dport = ntohs(uh->uh_dport);
2031ae349f5Scvs2svn 		estab = 1;
2041ae349f5Scvs2svn 		break;
2051ae349f5Scvs2svn 	      case IPPROTO_TCP:
2061ae349f5Scvs2svn 		cproto = P_TCP;
2071ae349f5Scvs2svn 		th = (struct tcphdr *) ptop;
2081ae349f5Scvs2svn 		sport = ntohs(th->th_sport);
2091ae349f5Scvs2svn 		dport = ntohs(th->th_dport);
2101ae349f5Scvs2svn 		estab = (th->th_flags & TH_ACK);
2111ae349f5Scvs2svn 		if (estab == 0)
2121ae349f5Scvs2svn 		  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
2131ae349f5Scvs2svn 			    th->th_flags, sport, dport);
2141ae349f5Scvs2svn 		break;
2151ae349f5Scvs2svn 	      default:
2161ae349f5Scvs2svn 		return (A_DENY);/* We'll block unknown type of packet */
2171ae349f5Scvs2svn 	      }
2181ae349f5Scvs2svn 	      gotinfo = 1;
2191ae349f5Scvs2svn 	      LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
2201ae349f5Scvs2svn 			" dstop = %d, estab = %d\n", direction, cproto,
2211ae349f5Scvs2svn 			fp->opt.srcop, fp->opt.dstop, estab);
2221ae349f5Scvs2svn 	    }
2231ae349f5Scvs2svn 	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
2241ae349f5Scvs2svn 		      " dport = %d\n", n, cproto, sport, dport);
2251ae349f5Scvs2svn 	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
2261ae349f5Scvs2svn 
2271ae349f5Scvs2svn 	    if (cproto == fp->proto) {
2281ae349f5Scvs2svn 	      if ((fp->opt.srcop == OP_NONE ||
2291ae349f5Scvs2svn 		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
2301ae349f5Scvs2svn 		  &&
2311ae349f5Scvs2svn 		  (fp->opt.dstop == OP_NONE ||
2321ae349f5Scvs2svn 		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
2331ae349f5Scvs2svn 		  &&
2341ae349f5Scvs2svn 		  (fp->opt.estab == 0 || estab)) {
2351ae349f5Scvs2svn 		return (fp->action);
2361ae349f5Scvs2svn 	      }
2371ae349f5Scvs2svn 	    }
2381ae349f5Scvs2svn 	  } else {
2391ae349f5Scvs2svn 	    /* Address is mached. Make a decision. */
2401ae349f5Scvs2svn 	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
2411ae349f5Scvs2svn 	    return (fp->action);
2421ae349f5Scvs2svn 	  }
2431ae349f5Scvs2svn 	}
2441ae349f5Scvs2svn       }
2451ae349f5Scvs2svn       fp++;
2461ae349f5Scvs2svn     }
2471ae349f5Scvs2svn     return (A_DENY);		/* No rule is mached. Deny this packet */
2481ae349f5Scvs2svn   }
2491ae349f5Scvs2svn   return (A_PERMIT);		/* No rule is given. Permit this packet */
2501ae349f5Scvs2svn }
2511ae349f5Scvs2svn 
2521ae349f5Scvs2svn static void
2531ae349f5Scvs2svn IcmpError(struct ip * pip, int code)
2541ae349f5Scvs2svn {
2551ae349f5Scvs2svn #ifdef notdef
2561ae349f5Scvs2svn   struct mbuf *bp;
2571ae349f5Scvs2svn 
2581ae349f5Scvs2svn   if (pip->ip_p != IPPROTO_ICMP) {
2591ae349f5Scvs2svn     bp = mballoc(cnt, MB_IPIN);
2601ae349f5Scvs2svn     memcpy(MBUF_CTOP(bp), ptr, cnt);
2611ae349f5Scvs2svn     SendPppFrame(bp);
2621ae349f5Scvs2svn     RestartIdleTimer();
2631ae349f5Scvs2svn     IpcpAddOutOctets(cnt);
2641ae349f5Scvs2svn   }
2651ae349f5Scvs2svn #endif
2661ae349f5Scvs2svn }
2671ae349f5Scvs2svn 
2681ae349f5Scvs2svn /*
2691ae349f5Scvs2svn  *  For debugging aid.
2701ae349f5Scvs2svn  */
2711ae349f5Scvs2svn int
2721ae349f5Scvs2svn PacketCheck(char *cp, int nb, int direction)
2731ae349f5Scvs2svn {
2741ae349f5Scvs2svn   struct ip *pip;
2751ae349f5Scvs2svn   struct tcphdr *th;
2761ae349f5Scvs2svn   struct udphdr *uh;
2771ae349f5Scvs2svn   struct icmp *icmph;
2781ae349f5Scvs2svn   char *ptop;
2791ae349f5Scvs2svn   int mask, len, n;
2801ae349f5Scvs2svn   int pri = PRI_NORMAL;
2811ae349f5Scvs2svn   int logit, loglen;
2821ae349f5Scvs2svn   static char logbuf[200];
2831ae349f5Scvs2svn 
2841ae349f5Scvs2svn   logit = LogIsKept(LogTCPIP) && direction != FL_DIAL;
2851ae349f5Scvs2svn   loglen = 0;
2861ae349f5Scvs2svn 
2871ae349f5Scvs2svn   pip = (struct ip *) cp;
2881ae349f5Scvs2svn 
2891ae349f5Scvs2svn   if (logit && loglen < sizeof logbuf) {
2901ae349f5Scvs2svn     snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ",
2911ae349f5Scvs2svn 	     Direction[direction]);
2921ae349f5Scvs2svn     loglen += strlen(logbuf + loglen);
2931ae349f5Scvs2svn   }
2941ae349f5Scvs2svn   ptop = (cp + (pip->ip_hl << 2));
2951ae349f5Scvs2svn 
2961ae349f5Scvs2svn   switch (pip->ip_p) {
2971ae349f5Scvs2svn   case IPPROTO_ICMP:
2981ae349f5Scvs2svn     if (logit && loglen < sizeof logbuf) {
2991ae349f5Scvs2svn       icmph = (struct icmp *) ptop;
3001ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3011ae349f5Scvs2svn 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
3021ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
3031ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3041ae349f5Scvs2svn 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
3051ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
3061ae349f5Scvs2svn     }
3071ae349f5Scvs2svn     break;
3081ae349f5Scvs2svn   case IPPROTO_UDP:
3091ae349f5Scvs2svn     if (logit && loglen < sizeof logbuf) {
3101ae349f5Scvs2svn       uh = (struct udphdr *) ptop;
3111ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3121ae349f5Scvs2svn 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
3131ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
3141ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3151ae349f5Scvs2svn 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
3161ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
3171ae349f5Scvs2svn     }
3181ae349f5Scvs2svn     break;
3191ae349f5Scvs2svn   case IPPROTO_TCP:
3201ae349f5Scvs2svn     th = (struct tcphdr *) ptop;
3211ae349f5Scvs2svn     if (pip->ip_tos == IPTOS_LOWDELAY)
3221ae349f5Scvs2svn       pri = PRI_FAST;
3231ae349f5Scvs2svn     else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
3241ae349f5Scvs2svn       if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
3251ae349f5Scvs2svn 	pri = PRI_FAST;
3261ae349f5Scvs2svn     }
3271ae349f5Scvs2svn     if (logit && loglen < sizeof logbuf) {
3281ae349f5Scvs2svn       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
3291ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3301ae349f5Scvs2svn 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
3311ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
3321ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3331ae349f5Scvs2svn 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
3341ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
3351ae349f5Scvs2svn       n = 0;
3361ae349f5Scvs2svn       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
3371ae349f5Scvs2svn 	if (th->th_flags & mask) {
3381ae349f5Scvs2svn 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
3391ae349f5Scvs2svn 	  loglen += strlen(logbuf + loglen);
3401ae349f5Scvs2svn 	}
3411ae349f5Scvs2svn 	n++;
3421ae349f5Scvs2svn       }
3431ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3441ae349f5Scvs2svn 	       "  seq:%x  ack:%x (%d/%d)",
3451ae349f5Scvs2svn 	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
3461ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
3471ae349f5Scvs2svn       if ((th->th_flags & TH_SYN) && nb > 40) {
3481ae349f5Scvs2svn 	u_short *sp;
3491ae349f5Scvs2svn 
3501ae349f5Scvs2svn 	ptop += 20;
3511ae349f5Scvs2svn 	sp = (u_short *) ptop;
3521ae349f5Scvs2svn 	if (ntohs(sp[0]) == 0x0204) {
3531ae349f5Scvs2svn 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
3541ae349f5Scvs2svn 		   " MSS = %d", ntohs(sp[1]));
3551ae349f5Scvs2svn 	  loglen += strlen(logbuf + loglen);
3561ae349f5Scvs2svn 	}
3571ae349f5Scvs2svn       }
3581ae349f5Scvs2svn     }
3591ae349f5Scvs2svn     break;
3601ae349f5Scvs2svn   }
3611ae349f5Scvs2svn 
3621ae349f5Scvs2svn   if ((FilterCheck(pip, direction) & A_DENY)) {
3631ae349f5Scvs2svn     if (logit)
3641ae349f5Scvs2svn       LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
3651ae349f5Scvs2svn     if (direction == 0)
3661ae349f5Scvs2svn       IcmpError(pip, pri);
3671ae349f5Scvs2svn     return (-1);
3681ae349f5Scvs2svn   } else {
3691ae349f5Scvs2svn     if (FilterCheck(pip, FL_KEEP) & A_DENY) {	/* Check Keep Alive filter */
3701ae349f5Scvs2svn       if (logit)
3711ae349f5Scvs2svn         LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
3721ae349f5Scvs2svn       ipKeepAlive = 0;
3731ae349f5Scvs2svn     } else {
3741ae349f5Scvs2svn       if (logit)
3751ae349f5Scvs2svn         LogPrintf(LogTCPIP, "%s\n", logbuf);
3761ae349f5Scvs2svn       ipKeepAlive = 1;
3771ae349f5Scvs2svn     }
3781ae349f5Scvs2svn     return (pri);
3791ae349f5Scvs2svn   }
3801ae349f5Scvs2svn }
3811ae349f5Scvs2svn 
3821ae349f5Scvs2svn void
3831ae349f5Scvs2svn IpInput(struct mbuf * bp)
3841ae349f5Scvs2svn {				/* IN: Pointer to IP pakcet */
3851ae349f5Scvs2svn   u_char *cp;
3861ae349f5Scvs2svn   struct mbuf *wp;
3871ae349f5Scvs2svn   int nb, nw;
3881ae349f5Scvs2svn   struct tun_data tun;
3891ae349f5Scvs2svn 
3901ae349f5Scvs2svn   tun_fill_header(tun, AF_INET);
3911ae349f5Scvs2svn   cp = tun.data;
3921ae349f5Scvs2svn   nb = 0;
3931ae349f5Scvs2svn   for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
3941ae349f5Scvs2svn     if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
3951ae349f5Scvs2svn       LogPrintf(LogERROR, "IpInput: Packet too large (%d) - dropped\n",
3961ae349f5Scvs2svn                 plength(bp));
3971ae349f5Scvs2svn       pfree(bp);
3981ae349f5Scvs2svn       return;
3991ae349f5Scvs2svn     }
4001ae349f5Scvs2svn     memcpy(cp, MBUF_CTOP(wp), wp->cnt);
4011ae349f5Scvs2svn     cp += wp->cnt;
4021ae349f5Scvs2svn     nb += wp->cnt;
4031ae349f5Scvs2svn   }
4041ae349f5Scvs2svn 
4051ae349f5Scvs2svn #ifndef NOALIAS
4061ae349f5Scvs2svn   if (mode & MODE_ALIAS) {
4071ae349f5Scvs2svn     struct tun_data *frag;
4081ae349f5Scvs2svn     int iresult;
4091ae349f5Scvs2svn     char *fptr;
4101ae349f5Scvs2svn 
4111ae349f5Scvs2svn     iresult = VarPacketAliasIn(tun.data, sizeof tun.data);
4121ae349f5Scvs2svn     nb = ntohs(((struct ip *) tun.data)->ip_len);
4131ae349f5Scvs2svn 
4141ae349f5Scvs2svn     if (nb > MAX_MRU) {
4151ae349f5Scvs2svn       LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
4161ae349f5Scvs2svn       pfree(bp);
4171ae349f5Scvs2svn       return;
4181ae349f5Scvs2svn     }
4191ae349f5Scvs2svn     if (iresult == PKT_ALIAS_OK
4201ae349f5Scvs2svn 	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
4211ae349f5Scvs2svn       if (PacketCheck(tun.data, nb, FL_IN) < 0) {
4221ae349f5Scvs2svn 	pfree(bp);
4231ae349f5Scvs2svn 	return;
4241ae349f5Scvs2svn       }
4251ae349f5Scvs2svn       IpcpAddInOctets(nb);
4261ae349f5Scvs2svn 
4271ae349f5Scvs2svn       nb = ntohs(((struct ip *) tun.data)->ip_len);
4281ae349f5Scvs2svn       nb += sizeof tun - sizeof tun.data;
4291ae349f5Scvs2svn       nw = write(tun_out, &tun, nb);
4301ae349f5Scvs2svn       if (nw != nb)
4311ae349f5Scvs2svn         if (nw == -1)
4321ae349f5Scvs2svn 	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
4331ae349f5Scvs2svn                     strerror(errno));
4341ae349f5Scvs2svn         else
4351ae349f5Scvs2svn 	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4361ae349f5Scvs2svn 
4371ae349f5Scvs2svn       if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
4381ae349f5Scvs2svn 	while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) {
4391ae349f5Scvs2svn 	  VarPacketAliasFragmentIn(tun.data, fptr);
4401ae349f5Scvs2svn 	  nb = ntohs(((struct ip *) fptr)->ip_len);
4411ae349f5Scvs2svn           frag = (struct tun_data *)
4421ae349f5Scvs2svn 	    ((char *)fptr - sizeof tun + sizeof tun.data);
4431ae349f5Scvs2svn           nb += sizeof tun - sizeof tun.data;
4441ae349f5Scvs2svn 	  nw = write(tun_out, frag, nb);
4451ae349f5Scvs2svn 	  if (nw != nb)
4461ae349f5Scvs2svn             if (nw == -1)
4471ae349f5Scvs2svn 	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
4481ae349f5Scvs2svn                         strerror(errno));
4491ae349f5Scvs2svn             else
4501ae349f5Scvs2svn 	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4511ae349f5Scvs2svn 	  free(frag);
4521ae349f5Scvs2svn 	}
4531ae349f5Scvs2svn       }
4541ae349f5Scvs2svn     } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
4551ae349f5Scvs2svn       nb = ntohs(((struct ip *) tun.data)->ip_len);
4561ae349f5Scvs2svn       nb += sizeof tun - sizeof tun.data;
4571ae349f5Scvs2svn       frag = (struct tun_data *)malloc(nb);
4581ae349f5Scvs2svn       if (frag == NULL)
4591ae349f5Scvs2svn 	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
4601ae349f5Scvs2svn       else {
4611ae349f5Scvs2svn         tun_fill_header(*frag, AF_INET);
4621ae349f5Scvs2svn 	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
4631ae349f5Scvs2svn 	VarPacketAliasSaveFragment(frag->data);
4641ae349f5Scvs2svn       }
4651ae349f5Scvs2svn     }
4661ae349f5Scvs2svn   } else
4671ae349f5Scvs2svn #endif /* #ifndef NOALIAS */
4681ae349f5Scvs2svn   {			/* no aliasing */
4691ae349f5Scvs2svn     if (PacketCheck(tun.data, nb, FL_IN) < 0) {
4701ae349f5Scvs2svn       pfree(bp);
4711ae349f5Scvs2svn       return;
4721ae349f5Scvs2svn     }
4731ae349f5Scvs2svn     IpcpAddInOctets(nb);
4741ae349f5Scvs2svn     nb += sizeof tun - sizeof tun.data;
4751ae349f5Scvs2svn     nw = write(tun_out, &tun, nb);
4761ae349f5Scvs2svn     if (nw != nb)
4771ae349f5Scvs2svn       if (nw == -1)
4781ae349f5Scvs2svn 	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
4791ae349f5Scvs2svn       else
4801ae349f5Scvs2svn         LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4811ae349f5Scvs2svn   }
4821ae349f5Scvs2svn   pfree(bp);
4831ae349f5Scvs2svn 
4841ae349f5Scvs2svn   RestartIdleTimer();
4851ae349f5Scvs2svn }
4861ae349f5Scvs2svn 
4871ae349f5Scvs2svn static struct mqueue IpOutputQueues[PRI_FAST + 1];
4881ae349f5Scvs2svn 
4891ae349f5Scvs2svn void
4901ae349f5Scvs2svn IpEnqueue(int pri, char *ptr, int count)
4911ae349f5Scvs2svn {
4921ae349f5Scvs2svn   struct mbuf *bp;
4931ae349f5Scvs2svn 
4941ae349f5Scvs2svn   bp = mballoc(count, MB_IPQ);
4951ae349f5Scvs2svn   memcpy(MBUF_CTOP(bp), ptr, count);
4961ae349f5Scvs2svn   Enqueue(&IpOutputQueues[pri], bp);
4971ae349f5Scvs2svn }
4981ae349f5Scvs2svn 
4991ae349f5Scvs2svn #if 0
5001ae349f5Scvs2svn int
5011ae349f5Scvs2svn IsIpEnqueued()
5021ae349f5Scvs2svn {
5031ae349f5Scvs2svn   struct mqueue *queue;
5041ae349f5Scvs2svn   int exist = 0;
5051ae349f5Scvs2svn 
5061ae349f5Scvs2svn   for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
5071ae349f5Scvs2svn     if (queue->qlen > 0) {
5081ae349f5Scvs2svn       exist = 1;
5091ae349f5Scvs2svn       break;
5101ae349f5Scvs2svn     }
5111ae349f5Scvs2svn   }
5121ae349f5Scvs2svn   return (exist);
5131ae349f5Scvs2svn }
5141ae349f5Scvs2svn #endif
5151ae349f5Scvs2svn 
5161ae349f5Scvs2svn void
5171ae349f5Scvs2svn IpStartOutput()
5181ae349f5Scvs2svn {
5191ae349f5Scvs2svn   struct mqueue *queue;
5201ae349f5Scvs2svn   struct mbuf *bp;
5211ae349f5Scvs2svn   int cnt;
5221ae349f5Scvs2svn 
5231ae349f5Scvs2svn   if (IpcpFsm.state != ST_OPENED)
5241ae349f5Scvs2svn     return;
5251ae349f5Scvs2svn   for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
5261ae349f5Scvs2svn     if (queue->top) {
5271ae349f5Scvs2svn       bp = Dequeue(queue);
5281ae349f5Scvs2svn       if (bp) {
5291ae349f5Scvs2svn 	cnt = plength(bp);
5301ae349f5Scvs2svn 	SendPppFrame(bp);
5311ae349f5Scvs2svn 	RestartIdleTimer();
5321ae349f5Scvs2svn         IpcpAddOutOctets(cnt);
5331ae349f5Scvs2svn 	break;
5341ae349f5Scvs2svn       }
5351ae349f5Scvs2svn     }
5361ae349f5Scvs2svn   }
5371ae349f5Scvs2svn }
538