xref: /freebsd/usr.sbin/ppp/ip.c (revision 63f98b41d4c0c0e7b444ac30997a391c40f9947d)
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  *
2063f98b41SBrian Somers  * $Id: ip.c,v 1.38.2.21 1998/04/07 23:45:52 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  *	TODO:
231ae349f5Scvs2svn  *		o Return ICMP message for filterd packet
241ae349f5Scvs2svn  *		  and optionaly record it into log.
251ae349f5Scvs2svn  */
262764b86aSBrian Somers #include <sys/types.h>
271ae349f5Scvs2svn #include <netinet/in.h>
281ae349f5Scvs2svn #include <netinet/in_systm.h>
291ae349f5Scvs2svn #include <netinet/ip.h>
301ae349f5Scvs2svn #include <netinet/ip_icmp.h>
311ae349f5Scvs2svn #include <netinet/udp.h>
321ae349f5Scvs2svn #include <netinet/tcp.h>
331ae349f5Scvs2svn #include <arpa/inet.h>
341ae349f5Scvs2svn 
351ae349f5Scvs2svn #ifndef NOALIAS
361ae349f5Scvs2svn #include <alias.h>
371ae349f5Scvs2svn #endif
381ae349f5Scvs2svn #include <errno.h>
391ae349f5Scvs2svn #include <stdio.h>
401ae349f5Scvs2svn #include <stdlib.h>
411ae349f5Scvs2svn #include <string.h>
421ae349f5Scvs2svn #include <unistd.h>
431ae349f5Scvs2svn 
441ae349f5Scvs2svn #include "mbuf.h"
451ae349f5Scvs2svn #include "log.h"
461ae349f5Scvs2svn #include "defs.h"
471ae349f5Scvs2svn #include "timer.h"
481ae349f5Scvs2svn #include "fsm.h"
49879ed6faSBrian Somers #include "lqr.h"
501ae349f5Scvs2svn #include "hdlc.h"
511ae349f5Scvs2svn #include "loadalias.h"
525828db6dSBrian Somers #include "throughput.h"
535828db6dSBrian Somers #include "iplist.h"
54eaa4df37SBrian Somers #include "slcompress.h"
555828db6dSBrian Somers #include "ipcp.h"
561ae349f5Scvs2svn #include "filter.h"
572f786681SBrian Somers #include "descriptor.h"
583b0f8d2eSBrian Somers #include "lcp.h"
593b0f8d2eSBrian Somers #include "ccp.h"
603b0f8d2eSBrian Somers #include "link.h"
613b0f8d2eSBrian Somers #include "mp.h"
627a6f8720SBrian Somers #include "bundle.h"
631ae349f5Scvs2svn #include "vjcomp.h"
641ae349f5Scvs2svn #include "tun.h"
651ae349f5Scvs2svn #include "ip.h"
661ae349f5Scvs2svn 
671ae349f5Scvs2svn static const u_short interactive_ports[32] = {
681ae349f5Scvs2svn   544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
691ae349f5Scvs2svn   0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
701ae349f5Scvs2svn };
711ae349f5Scvs2svn 
721ae349f5Scvs2svn #define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
731ae349f5Scvs2svn 
741ae349f5Scvs2svn static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
751ae349f5Scvs2svn 
761ae349f5Scvs2svn static int
771ae349f5Scvs2svn PortMatch(int op, u_short pport, u_short rport)
781ae349f5Scvs2svn {
791ae349f5Scvs2svn   switch (op) {
801ae349f5Scvs2svn     case OP_EQ:
811ae349f5Scvs2svn     return (pport == rport);
821ae349f5Scvs2svn   case OP_GT:
831ae349f5Scvs2svn     return (pport > rport);
841ae349f5Scvs2svn   case OP_LT:
851ae349f5Scvs2svn     return (pport < rport);
861ae349f5Scvs2svn   default:
871ae349f5Scvs2svn     return (0);
881ae349f5Scvs2svn   }
891ae349f5Scvs2svn }
901ae349f5Scvs2svn 
911ae349f5Scvs2svn /*
921ae349f5Scvs2svn  *  Check a packet against with defined filters
931ae349f5Scvs2svn  */
941ae349f5Scvs2svn static int
955ca5389aSBrian Somers FilterCheck(struct ip *pip, struct filter *filter)
961ae349f5Scvs2svn {
9763f98b41SBrian Somers   int gotinfo, cproto, estab, syn, finrst, n, len, didname;
981ae349f5Scvs2svn   struct tcphdr *th;
991ae349f5Scvs2svn   struct udphdr *uh;
1001ae349f5Scvs2svn   struct icmp *ih;
1011ae349f5Scvs2svn   char *ptop;
1021ae349f5Scvs2svn   u_short sport, dport;
1035ca5389aSBrian Somers   struct filterent *fp = filter->rule;
1048390b576SBrian Somers   char dbuff[100];
1051ae349f5Scvs2svn 
1061ae349f5Scvs2svn   if (fp->action) {
10763f98b41SBrian Somers     cproto = gotinfo = estab = syn = finrst = didname = 0;
1081ae349f5Scvs2svn     sport = dport = 0;
1091ae349f5Scvs2svn     for (n = 0; n < MAXFILTERS; n++) {
1101ae349f5Scvs2svn       if (fp->action) {
1111ae349f5Scvs2svn 	/* permit fragments on in and out filter */
1125ca5389aSBrian Somers         if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0)
1131ae349f5Scvs2svn 	  return (A_PERMIT);
1145ca5389aSBrian Somers 
1158390b576SBrian Somers         if (!didname)
1168390b576SBrian Somers           LogPrintf(LogDEBUG, "%s filter:\n", filter->name);
1178390b576SBrian Somers         didname = 1;
1188390b576SBrian Somers 
1191ae349f5Scvs2svn 	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
1201ae349f5Scvs2svn 	    (fp->saddr.s_addr & fp->smask.s_addr) &&
1211ae349f5Scvs2svn 	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
1221ae349f5Scvs2svn 	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
1231ae349f5Scvs2svn 	  if (fp->proto) {
1241ae349f5Scvs2svn 	    if (!gotinfo) {
1251ae349f5Scvs2svn 	      ptop = (char *) pip + (pip->ip_hl << 2);
1261ae349f5Scvs2svn 
1271ae349f5Scvs2svn 	      switch (pip->ip_p) {
1281ae349f5Scvs2svn 	      case IPPROTO_ICMP:
1291ae349f5Scvs2svn 		cproto = P_ICMP;
1301ae349f5Scvs2svn 		ih = (struct icmp *) ptop;
1311ae349f5Scvs2svn 		sport = ih->icmp_type;
13263f98b41SBrian Somers 		estab = syn = finrst = -1;
1338390b576SBrian Somers                 if (LogIsKept(LogDEBUG))
1348390b576SBrian Somers 		  snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
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);
14163f98b41SBrian Somers 		estab = syn = finrst = -1;
1428390b576SBrian Somers                 if (LogIsKept(LogDEBUG))
1438390b576SBrian Somers 		  snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
1448390b576SBrian Somers                            sport, dport);
1451ae349f5Scvs2svn 		break;
1461ae349f5Scvs2svn 	      case IPPROTO_TCP:
1471ae349f5Scvs2svn 		cproto = P_TCP;
1481ae349f5Scvs2svn 		th = (struct tcphdr *) ptop;
1491ae349f5Scvs2svn 		sport = ntohs(th->th_sport);
1501ae349f5Scvs2svn 		dport = ntohs(th->th_dport);
1511ae349f5Scvs2svn 		estab = (th->th_flags & TH_ACK);
15263f98b41SBrian Somers 		syn = (th->th_flags & TH_SYN);
15363f98b41SBrian Somers 		finrst = (th->th_flags & (TH_FIN|TH_RST));
1548390b576SBrian Somers                 if (LogIsKept(LogDEBUG) && !estab)
1558390b576SBrian Somers 		  snprintf(dbuff, sizeof dbuff,
1568390b576SBrian Somers                            "flags = %02x, sport = %d, dport = %d",
1571ae349f5Scvs2svn                            th->th_flags, sport, dport);
1581ae349f5Scvs2svn 		break;
1591ae349f5Scvs2svn 	      default:
1601ae349f5Scvs2svn 		return (A_DENY);       /* We'll block unknown type of packet */
1611ae349f5Scvs2svn 	      }
1628390b576SBrian Somers               if (LogIsKept(LogDEBUG)) {
1638390b576SBrian Somers                 if (estab != -1) {
1648390b576SBrian Somers                   len = strlen(dbuff);
16563f98b41SBrian Somers                   snprintf(dbuff + len, sizeof dbuff - len,
16663f98b41SBrian Somers                            ", estab = %d, syn = %d, finrst = %d",
16763f98b41SBrian Somers                            estab, syn, finrst);
1681ae349f5Scvs2svn                 }
1698390b576SBrian Somers 	        LogPrintf(LogDEBUG, " Filter: proto = %s, %s\n",
1708390b576SBrian Somers                           filter_Proto2Nam(cproto), dbuff);
1718390b576SBrian Somers               }
1728390b576SBrian Somers 	      gotinfo = 1;
1738390b576SBrian Somers 	    }
1748390b576SBrian Somers             if (LogIsKept(LogDEBUG)) {
1758390b576SBrian Somers 	      if (fp->opt.srcop != OP_NONE) {
1768390b576SBrian Somers                 snprintf(dbuff, sizeof dbuff, ", src %s %d",
1778390b576SBrian Somers                          filter_Op2Nam(fp->opt.srcop), fp->opt.srcport);
1788390b576SBrian Somers                 len = strlen(dbuff);
1798390b576SBrian Somers               } else
1808390b576SBrian Somers                 len = 0;
1818390b576SBrian Somers 	      if (fp->opt.dstop != OP_NONE) {
1828390b576SBrian Somers                 snprintf(dbuff + len, sizeof dbuff - len,
1838390b576SBrian Somers                          ", dst %s %d", filter_Op2Nam(fp->opt.dstop),
1848390b576SBrian Somers                          fp->opt.dstport);
1858390b576SBrian Somers               } else if (!len)
1868390b576SBrian Somers                 *dbuff = '\0';
1878390b576SBrian Somers 
1888390b576SBrian Somers 	      LogPrintf(LogDEBUG, "  rule = %d: Address match, "
1898390b576SBrian Somers                         "check against proto %s%s, action = %s\n",
1908390b576SBrian Somers                         n, filter_Proto2Nam(fp->proto),
1918390b576SBrian Somers                         dbuff, filter_Action2Nam(fp->action));
1928390b576SBrian Somers             }
1931ae349f5Scvs2svn 
1941ae349f5Scvs2svn 	    if (cproto == fp->proto) {
1951ae349f5Scvs2svn 	      if ((fp->opt.srcop == OP_NONE ||
19663f98b41SBrian Somers 		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) &&
1971ae349f5Scvs2svn 		  (fp->opt.dstop == OP_NONE ||
19863f98b41SBrian Somers 		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) &&
19963f98b41SBrian Somers 		  (fp->opt.estab == 0 || estab) &&
20063f98b41SBrian Somers 		  (fp->opt.syn == 0 || syn) &&
20163f98b41SBrian Somers 		  (fp->opt.finrst == 0 || finrst)) {
2021ae349f5Scvs2svn 		return (fp->action);
2031ae349f5Scvs2svn 	      }
2041ae349f5Scvs2svn 	    }
2051ae349f5Scvs2svn 	  } else {
2061ae349f5Scvs2svn 	    /* Address is mached. Make a decision. */
2078390b576SBrian Somers 	    LogPrintf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
2088390b576SBrian Somers                       filter_Action2Nam(fp->action));
2091ae349f5Scvs2svn 	    return (fp->action);
2101ae349f5Scvs2svn 	  }
2118390b576SBrian Somers 	} else
2128390b576SBrian Somers 	  LogPrintf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
2131ae349f5Scvs2svn       }
2141ae349f5Scvs2svn       fp++;
2151ae349f5Scvs2svn     }
2161ae349f5Scvs2svn     return (A_DENY);		/* No rule is mached. Deny this packet */
2171ae349f5Scvs2svn   }
2181ae349f5Scvs2svn   return (A_PERMIT);		/* No rule is given. Permit this packet */
2191ae349f5Scvs2svn }
2201ae349f5Scvs2svn 
2215ca5389aSBrian Somers #ifdef notdef
2221ae349f5Scvs2svn static void
2231ae349f5Scvs2svn IcmpError(struct ip * pip, int code)
2241ae349f5Scvs2svn {
2251ae349f5Scvs2svn   struct mbuf *bp;
2261ae349f5Scvs2svn 
2271ae349f5Scvs2svn   if (pip->ip_p != IPPROTO_ICMP) {
2281ae349f5Scvs2svn     bp = mballoc(cnt, MB_IPIN);
2291ae349f5Scvs2svn     memcpy(MBUF_CTOP(bp), ptr, cnt);
2301ae349f5Scvs2svn     SendPppFrame(bp);
2315828db6dSBrian Somers     ipcp_AddOutOctets(cnt);
2321ae349f5Scvs2svn   }
2331ae349f5Scvs2svn }
2345ca5389aSBrian Somers #endif
2351ae349f5Scvs2svn 
2361ae349f5Scvs2svn /*
2371ae349f5Scvs2svn  *  For debugging aid.
2381ae349f5Scvs2svn  */
2391ae349f5Scvs2svn int
2405ca5389aSBrian Somers PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
2411ae349f5Scvs2svn {
2421ae349f5Scvs2svn   struct ip *pip;
2431ae349f5Scvs2svn   struct tcphdr *th;
2441ae349f5Scvs2svn   struct udphdr *uh;
2451ae349f5Scvs2svn   struct icmp *icmph;
2461ae349f5Scvs2svn   char *ptop;
2471ae349f5Scvs2svn   int mask, len, n;
2481ae349f5Scvs2svn   int pri = PRI_NORMAL;
2491ae349f5Scvs2svn   int logit, loglen;
2501ae349f5Scvs2svn   static char logbuf[200];
2511ae349f5Scvs2svn 
2525ca5389aSBrian Somers   logit = LogIsKept(LogTCPIP) && filter->logok;
2531ae349f5Scvs2svn   loglen = 0;
2541ae349f5Scvs2svn 
2551ae349f5Scvs2svn   pip = (struct ip *) cp;
2561ae349f5Scvs2svn 
2571ae349f5Scvs2svn   if (logit && loglen < sizeof logbuf) {
2585ca5389aSBrian Somers     snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
2591ae349f5Scvs2svn     loglen += strlen(logbuf + loglen);
2601ae349f5Scvs2svn   }
2611ae349f5Scvs2svn   ptop = (cp + (pip->ip_hl << 2));
2621ae349f5Scvs2svn 
2631ae349f5Scvs2svn   switch (pip->ip_p) {
2641ae349f5Scvs2svn   case IPPROTO_ICMP:
2651ae349f5Scvs2svn     if (logit && loglen < sizeof logbuf) {
2661ae349f5Scvs2svn       icmph = (struct icmp *) ptop;
2671ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2681ae349f5Scvs2svn 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
2691ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2701ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2711ae349f5Scvs2svn 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
2721ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2731ae349f5Scvs2svn     }
2741ae349f5Scvs2svn     break;
2751ae349f5Scvs2svn   case IPPROTO_UDP:
2761ae349f5Scvs2svn     if (logit && loglen < sizeof logbuf) {
2771ae349f5Scvs2svn       uh = (struct udphdr *) ptop;
2781ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2791ae349f5Scvs2svn 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
2801ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2811ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2821ae349f5Scvs2svn 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
2831ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2841ae349f5Scvs2svn     }
2851ae349f5Scvs2svn     break;
2861ae349f5Scvs2svn   case IPPROTO_TCP:
2871ae349f5Scvs2svn     th = (struct tcphdr *) ptop;
2881ae349f5Scvs2svn     if (pip->ip_tos == IPTOS_LOWDELAY)
2891ae349f5Scvs2svn       pri = PRI_FAST;
2901ae349f5Scvs2svn     else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
2911ae349f5Scvs2svn       if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
2921ae349f5Scvs2svn 	pri = PRI_FAST;
2931ae349f5Scvs2svn     }
2941ae349f5Scvs2svn     if (logit && loglen < sizeof logbuf) {
2951ae349f5Scvs2svn       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
2961ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
2971ae349f5Scvs2svn 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
2981ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
2991ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3001ae349f5Scvs2svn 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
3011ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
3021ae349f5Scvs2svn       n = 0;
3031ae349f5Scvs2svn       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
3041ae349f5Scvs2svn 	if (th->th_flags & mask) {
3051ae349f5Scvs2svn 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
3061ae349f5Scvs2svn 	  loglen += strlen(logbuf + loglen);
3071ae349f5Scvs2svn 	}
3081ae349f5Scvs2svn 	n++;
3091ae349f5Scvs2svn       }
3101ae349f5Scvs2svn       snprintf(logbuf + loglen, sizeof logbuf - loglen,
3111ae349f5Scvs2svn 	       "  seq:%x  ack:%x (%d/%d)",
3121ae349f5Scvs2svn 	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
3131ae349f5Scvs2svn       loglen += strlen(logbuf + loglen);
3141ae349f5Scvs2svn       if ((th->th_flags & TH_SYN) && nb > 40) {
3151ae349f5Scvs2svn 	u_short *sp;
3161ae349f5Scvs2svn 
3171ae349f5Scvs2svn 	ptop += 20;
3181ae349f5Scvs2svn 	sp = (u_short *) ptop;
3191ae349f5Scvs2svn 	if (ntohs(sp[0]) == 0x0204) {
3201ae349f5Scvs2svn 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
3211ae349f5Scvs2svn 		   " MSS = %d", ntohs(sp[1]));
3221ae349f5Scvs2svn 	  loglen += strlen(logbuf + loglen);
3231ae349f5Scvs2svn 	}
3241ae349f5Scvs2svn       }
3251ae349f5Scvs2svn     }
3261ae349f5Scvs2svn     break;
3271ae349f5Scvs2svn   }
3281ae349f5Scvs2svn 
3295ca5389aSBrian Somers   if ((FilterCheck(pip, filter) & A_DENY)) {
3301ae349f5Scvs2svn     if (logit)
3311ae349f5Scvs2svn       LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
3325ca5389aSBrian Somers #ifdef notdef
3331ae349f5Scvs2svn     if (direction == 0)
3341ae349f5Scvs2svn       IcmpError(pip, pri);
3355ca5389aSBrian Somers #endif
3361ae349f5Scvs2svn     return (-1);
3371ae349f5Scvs2svn   } else {
3385ca5389aSBrian Somers     /* Check Keep Alive filter */
3391ae349f5Scvs2svn     if (logit)
3401e991daaSBrian Somers       if (FilterCheck(pip, &bundle->filter.alive) & A_DENY)
3411ae349f5Scvs2svn         LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
3421e991daaSBrian Somers       else
3431ae349f5Scvs2svn         LogPrintf(LogTCPIP, "%s\n", logbuf);
3441ae349f5Scvs2svn     return (pri);
3451ae349f5Scvs2svn   }
3461ae349f5Scvs2svn }
3471ae349f5Scvs2svn 
3481ae349f5Scvs2svn void
3497a6f8720SBrian Somers IpInput(struct bundle *bundle, struct mbuf * bp)
3507a6f8720SBrian Somers {
3511ae349f5Scvs2svn   u_char *cp;
3521ae349f5Scvs2svn   struct mbuf *wp;
3531ae349f5Scvs2svn   int nb, nw;
3541ae349f5Scvs2svn   struct tun_data tun;
3551e991daaSBrian Somers   struct ip *pip = (struct ip *)tun.data;
3561ae349f5Scvs2svn 
3571ae349f5Scvs2svn   tun_fill_header(tun, AF_INET);
3581ae349f5Scvs2svn   cp = tun.data;
3591ae349f5Scvs2svn   nb = 0;
3601ae349f5Scvs2svn   for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
3611ae349f5Scvs2svn     if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
3621ae349f5Scvs2svn       LogPrintf(LogERROR, "IpInput: Packet too large (%d) - dropped\n",
3631ae349f5Scvs2svn                 plength(bp));
3641ae349f5Scvs2svn       pfree(bp);
3651ae349f5Scvs2svn       return;
3661ae349f5Scvs2svn     }
3671ae349f5Scvs2svn     memcpy(cp, MBUF_CTOP(wp), wp->cnt);
3681ae349f5Scvs2svn     cp += wp->cnt;
3691ae349f5Scvs2svn     nb += wp->cnt;
3701ae349f5Scvs2svn   }
3711ae349f5Scvs2svn 
3721ae349f5Scvs2svn #ifndef NOALIAS
37385602e52SBrian Somers   if (AliasEnabled()) {
3741ae349f5Scvs2svn     struct tun_data *frag;
3751ae349f5Scvs2svn     int iresult;
3761ae349f5Scvs2svn     char *fptr;
3771ae349f5Scvs2svn 
3782764b86aSBrian Somers     iresult = (*PacketAlias.In)(tun.data, sizeof tun.data);
3791ae349f5Scvs2svn     nb = ntohs(((struct ip *) tun.data)->ip_len);
3801ae349f5Scvs2svn 
3811ae349f5Scvs2svn     if (nb > MAX_MRU) {
3821ae349f5Scvs2svn       LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
3831ae349f5Scvs2svn       pfree(bp);
3841ae349f5Scvs2svn       return;
3851ae349f5Scvs2svn     }
3861ae349f5Scvs2svn     if (iresult == PKT_ALIAS_OK
3871ae349f5Scvs2svn 	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
3885ca5389aSBrian Somers       if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
3891ae349f5Scvs2svn 	pfree(bp);
3901ae349f5Scvs2svn 	return;
3911ae349f5Scvs2svn       }
3921e991daaSBrian Somers 
3931e991daaSBrian Somers       if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
3941e991daaSBrian Somers         bundle_StartIdleTimer(bundle);
3951e991daaSBrian Somers 
3965828db6dSBrian Somers       ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
3971ae349f5Scvs2svn 
3981ae349f5Scvs2svn       nb = ntohs(((struct ip *) tun.data)->ip_len);
3991ae349f5Scvs2svn       nb += sizeof tun - sizeof tun.data;
4007a6f8720SBrian Somers       nw = write(bundle->tun_fd, &tun, nb);
4011ae349f5Scvs2svn       if (nw != nb)
4021ae349f5Scvs2svn         if (nw == -1)
4031ae349f5Scvs2svn 	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
4041ae349f5Scvs2svn                     strerror(errno));
4051ae349f5Scvs2svn         else
4061ae349f5Scvs2svn 	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4071ae349f5Scvs2svn 
4081ae349f5Scvs2svn       if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
4092764b86aSBrian Somers 	while ((fptr = (*PacketAlias.GetFragment)(tun.data)) != NULL) {
4102764b86aSBrian Somers 	  (*PacketAlias.FragmentIn)(tun.data, fptr);
4111ae349f5Scvs2svn 	  nb = ntohs(((struct ip *) fptr)->ip_len);
4121ae349f5Scvs2svn           frag = (struct tun_data *)
4131ae349f5Scvs2svn 	    ((char *)fptr - sizeof tun + sizeof tun.data);
4141ae349f5Scvs2svn           nb += sizeof tun - sizeof tun.data;
4157a6f8720SBrian Somers 	  nw = write(bundle->tun_fd, frag, nb);
4161ae349f5Scvs2svn 	  if (nw != nb)
4171ae349f5Scvs2svn             if (nw == -1)
4181ae349f5Scvs2svn 	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
4191ae349f5Scvs2svn                         strerror(errno));
4201ae349f5Scvs2svn             else
4211ae349f5Scvs2svn 	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4221ae349f5Scvs2svn 	  free(frag);
4231ae349f5Scvs2svn 	}
4241ae349f5Scvs2svn       }
4251ae349f5Scvs2svn     } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
4261ae349f5Scvs2svn       nb = ntohs(((struct ip *) tun.data)->ip_len);
4271ae349f5Scvs2svn       nb += sizeof tun - sizeof tun.data;
4281ae349f5Scvs2svn       frag = (struct tun_data *)malloc(nb);
4291ae349f5Scvs2svn       if (frag == NULL)
4301ae349f5Scvs2svn 	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
4311ae349f5Scvs2svn       else {
4321ae349f5Scvs2svn         tun_fill_header(*frag, AF_INET);
4331ae349f5Scvs2svn 	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
4342764b86aSBrian Somers 	(*PacketAlias.SaveFragment)(frag->data);
4351ae349f5Scvs2svn       }
4361ae349f5Scvs2svn     }
4371ae349f5Scvs2svn   } else
4381ae349f5Scvs2svn #endif /* #ifndef NOALIAS */
4391ae349f5Scvs2svn   {			/* no aliasing */
4405ca5389aSBrian Somers     if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
4411ae349f5Scvs2svn       pfree(bp);
4421ae349f5Scvs2svn       return;
4431ae349f5Scvs2svn     }
4441e991daaSBrian Somers 
4451e991daaSBrian Somers     if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
4461e991daaSBrian Somers       bundle_StartIdleTimer(bundle);
4471e991daaSBrian Somers 
4485828db6dSBrian Somers     ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
4491e991daaSBrian Somers 
4501ae349f5Scvs2svn     nb += sizeof tun - sizeof tun.data;
4517a6f8720SBrian Somers     nw = write(bundle->tun_fd, &tun, nb);
4521ae349f5Scvs2svn     if (nw != nb)
4531ae349f5Scvs2svn       if (nw == -1)
4541ae349f5Scvs2svn 	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
4551ae349f5Scvs2svn       else
4561ae349f5Scvs2svn         LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
4571ae349f5Scvs2svn   }
4581ae349f5Scvs2svn   pfree(bp);
4591ae349f5Scvs2svn }
4601ae349f5Scvs2svn 
4611ae349f5Scvs2svn static struct mqueue IpOutputQueues[PRI_FAST + 1];
4621ae349f5Scvs2svn 
4631ae349f5Scvs2svn void
4641ae349f5Scvs2svn IpEnqueue(int pri, char *ptr, int count)
4651ae349f5Scvs2svn {
4661ae349f5Scvs2svn   struct mbuf *bp;
4671ae349f5Scvs2svn 
4681ae349f5Scvs2svn   bp = mballoc(count, MB_IPQ);
4691ae349f5Scvs2svn   memcpy(MBUF_CTOP(bp), ptr, count);
4701ae349f5Scvs2svn   Enqueue(&IpOutputQueues[pri], bp);
4711ae349f5Scvs2svn }
4721ae349f5Scvs2svn 
4731ae349f5Scvs2svn int
474f4768038SBrian Somers ip_QueueLen()
4751ae349f5Scvs2svn {
4761ae349f5Scvs2svn   struct mqueue *queue;
477f4768038SBrian Somers   int result = 0;
4781ae349f5Scvs2svn 
479f4768038SBrian Somers   for (queue = &IpOutputQueues[PRI_MAX]; queue >= IpOutputQueues; queue--)
480f4768038SBrian Somers     result += queue->qlen;
481f4768038SBrian Somers 
482f4768038SBrian Somers   return result;
4831ae349f5Scvs2svn }
4841ae349f5Scvs2svn 
4853b0f8d2eSBrian Somers int
4863b0f8d2eSBrian Somers IpFlushPacket(struct link *l, struct bundle *bundle)
4871ae349f5Scvs2svn {
4881ae349f5Scvs2svn   struct mqueue *queue;
4891ae349f5Scvs2svn   struct mbuf *bp;
4901ae349f5Scvs2svn   int cnt;
4911ae349f5Scvs2svn 
4925828db6dSBrian Somers   if (bundle->ncp.ipcp.fsm.state != ST_OPENED)
4933b0f8d2eSBrian Somers     return 0;
4941e991daaSBrian Somers 
4951e991daaSBrian Somers   for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--)
4961ae349f5Scvs2svn     if (queue->top) {
4971ae349f5Scvs2svn       bp = Dequeue(queue);
4981ae349f5Scvs2svn       if (bp) {
4991e991daaSBrian Somers         struct ip *pip = (struct ip *)MBUF_CTOP(bp);
5001e991daaSBrian Somers 
5011ae349f5Scvs2svn 	cnt = plength(bp);
502f4768038SBrian Somers 	SendPppFrame(l, bp, bundle);
5031e991daaSBrian Somers         if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
504ab886ad0SBrian Somers           bundle_StartIdleTimer(bundle);
5055828db6dSBrian Somers         ipcp_AddOutOctets(&bundle->ncp.ipcp, cnt);
5063b0f8d2eSBrian Somers 	return 1;
5071ae349f5Scvs2svn       }
5081ae349f5Scvs2svn     }
5091e991daaSBrian Somers 
5103b0f8d2eSBrian Somers   return 0;
5111ae349f5Scvs2svn }
512