ip.c revision 51048
197403Sobrien/*
297403Sobrien *		PPP IP Protocol Interface
3132720Skan *
4132720Skan *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
597403Sobrien *
697403Sobrien *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
797403Sobrien *
897403Sobrien * Redistribution and use in source and binary forms are permitted
997403Sobrien * provided that the above copyright notice and this paragraph are
1097403Sobrien * duplicated in all such forms and that any documentation,
1197403Sobrien * advertising materials, and other materials related to such
1297403Sobrien * distribution and use acknowledge that the software was developed
1397403Sobrien * by the Internet Initiative Japan.  The name of the
1497403Sobrien * IIJ may not be used to endorse or promote products derived
1597403Sobrien * from this software without specific prior written permission.
1697403Sobrien * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1797403Sobrien * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1897403Sobrien * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1997403Sobrien *
2097403Sobrien * $FreeBSD: head/usr.sbin/ppp/ip.c 51048 1999-09-07 07:51:11Z brian $
2197403Sobrien *
2297403Sobrien *	TODO:
2397403Sobrien *		o Return ICMP message for filterd packet
2497403Sobrien *		  and optionaly record it into log.
2597403Sobrien */
2697403Sobrien#include <sys/param.h>
2797403Sobrien#if defined(__OpenBSD__) || defined(__NetBSD__)
2897403Sobrien#include <sys/socket.h>
2997403Sobrien#endif
3097403Sobrien#include <netinet/in.h>
3197403Sobrien#include <netinet/in_systm.h>
3297403Sobrien#include <netinet/ip.h>
3397403Sobrien#include <netinet/ip_icmp.h>
3497403Sobrien#include <netinet/udp.h>
3597403Sobrien#include <netinet/tcp.h>
3697403Sobrien#include <arpa/inet.h>
3797403Sobrien#include <sys/un.h>
3897403Sobrien
3997403Sobrien#include <errno.h>
40132720Skan#include <stdio.h>
41132720Skan#include <string.h>
4297403Sobrien#include <termios.h>
4397403Sobrien#include <unistd.h>
4497403Sobrien
4597403Sobrien#include "layer.h"
4697403Sobrien#include "proto.h"
4797403Sobrien#include "mbuf.h"
4897403Sobrien#include "log.h"
4997403Sobrien#include "defs.h"
50117397Skan#include "timer.h"
51117397Skan#include "fsm.h"
52117397Skan#include "lqr.h"
53117397Skan#include "hdlc.h"
54117397Skan#include "throughput.h"
55117397Skan#include "iplist.h"
56117397Skan#include "slcompress.h"
57117397Skan#include "ipcp.h"
5897403Sobrien#include "filter.h"
5997403Sobrien#include "descriptor.h"
6097403Sobrien#include "lcp.h"
6197403Sobrien#include "ccp.h"
6297403Sobrien#include "link.h"
6397403Sobrien#include "mp.h"
6497403Sobrien#ifndef NORADIUS
6597403Sobrien#include "radius.h"
6697403Sobrien#endif
6797403Sobrien#include "bundle.h"
6897403Sobrien#include "tun.h"
6997403Sobrien#include "ip.h"
7097403Sobrien
7197403Sobrienstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
7297403Sobrien
73132720Skanstatic __inline int
74132720SkanPortMatch(int op, u_short pport, u_short rport)
7597403Sobrien{
7697403Sobrien  switch (op) {
77117397Skan  case OP_EQ:
78117397Skan    return (pport == rport);
79117397Skan  case OP_GT:
80117397Skan    return (pport > rport);
81117397Skan  case OP_LT:
82117397Skan    return (pport < rport);
83117397Skan  default:
84117397Skan    return (0);
8597403Sobrien  }
8697403Sobrien}
87117397Skan
88117397Skan/*
89117397Skan *  Check a packet against a defined filter
90117397Skan *  Returns 0 to accept the packet, non-zero to drop the packet
91117397Skan *
92117397Skan *  If filtering is enabled, the initial fragment of a datagram must
9397403Sobrien *  contain the complete protocol header, and subsequent fragments
9497403Sobrien *  must not attempt to over-write it.
9597403Sobrien */
96117397Skanstatic int
97117397SkanFilterCheck(const struct ip *pip, const struct filter *filter)
98117397Skan{
99117397Skan  int gotinfo;			/* true if IP payload decoded */
100117397Skan  int cproto;			/* P_* protocol type if (gotinfo) */
101117397Skan  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
102117397Skan  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
103117397Skan  int n;			/* filter rule to process */
10497403Sobrien  int len;			/* bytes used in dbuff */
105132720Skan  int didname;			/* true if filter header printed */
106132720Skan  int match;			/* true if condition matched */
10797403Sobrien  const struct filterent *fp = filter->rule;
108117397Skan  char dbuff[100];
109117397Skan
110117397Skan  if (fp->f_action == A_NONE)
111117397Skan    return (0);		/* No rule is given. Permit this packet */
112117397Skan
11397403Sobrien  /* Deny any packet fragment that tries to over-write the header.
11497403Sobrien   * Since we no longer have the real header available, punt on the
11597403Sobrien   * largest normal header - 20 bytes for TCP without options, rounded
11697403Sobrien   * up to the next possible fragment boundary.  Since the smallest
117117397Skan   * `legal' MTU is 576, and the smallest recommended MTU is 296, any
11897403Sobrien   * fragmentation within this range is dubious at best */
11997403Sobrien  len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
12097403Sobrien  if (len > 0) {		/* Not first fragment within datagram */
121117397Skan    if (len < (24 >> 3))	/* don't allow fragment to over-write header */
122117397Skan      return (1);
123117397Skan    /* permit fragments on in and out filter */
124117397Skan    return (filter->fragok);
125117397Skan  }
126117397Skan
127117397Skan  cproto = gotinfo = estab = syn = finrst = didname = 0;
128117397Skan  sport = dport = 0;
129117397Skan  for (n = 0; n < MAXFILTERS; ) {
130117397Skan    if (fp->f_action == A_NONE) {
131132720Skan      n++;
13297403Sobrien      fp++;
13397403Sobrien      continue;
134132720Skan    }
13597403Sobrien
13697403Sobrien    if (!didname) {
137132720Skan      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
13897403Sobrien      didname = 1;
139117397Skan    }
14097403Sobrien
141117397Skan    match = 0;
142117397Skan    if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
143117397Skan	  fp->f_src.mask.s_addr) &&
144117397Skan	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
145117397Skan	  fp->f_dst.mask.s_addr)) {
146117397Skan      if (fp->f_proto != P_NONE) {
147117397Skan	if (!gotinfo) {
148117397Skan	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
149117397Skan	  const struct tcphdr *th;
150117397Skan	  const struct udphdr *uh;
151117397Skan	  const struct icmp *ih;
152117397Skan	  int datalen;	/* IP datagram length */
153117397Skan
154117397Skan	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
155117397Skan	  switch (pip->ip_p) {
156117397Skan	  case IPPROTO_ICMP:
157117397Skan	    cproto = P_ICMP;
158117397Skan	    if (datalen < 8)	/* ICMP must be at least 8 octets */
159117397Skan	      return (1);
160117397Skan	    ih = (const struct icmp *) ptop;
161117397Skan	    sport = ih->icmp_type;
162117397Skan	    estab = syn = finrst = -1;
163117397Skan	    if (log_IsKept(LogDEBUG))
164117397Skan	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
165117397Skan	    break;
166117397Skan	  case IPPROTO_IGMP:
167117397Skan	    cproto = P_IGMP;
168117397Skan	    if (datalen < 8)	/* IGMP uses 8-octet messages */
16997403Sobrien	      return (1);
17097403Sobrien	    estab = syn = finrst = -1;
17197403Sobrien	    sport = ntohs(0);
17297403Sobrien	    break;
17397403Sobrien#ifdef IPPROTO_OSPFIGP
17497403Sobrien	  case IPPROTO_OSPFIGP:
17597403Sobrien	    cproto = P_OSPF;
17697403Sobrien	    if (datalen < 8)	/* IGMP uses 8-octet messages */
17797403Sobrien	      return (1);
17897403Sobrien	    estab = syn = finrst = -1;
17997403Sobrien	    sport = ntohs(0);
18097403Sobrien	    break;
18197403Sobrien#endif
18297403Sobrien	  case IPPROTO_UDP:
18397403Sobrien	  case IPPROTO_IPIP:
18497403Sobrien	    cproto = P_UDP;
18597403Sobrien	    if (datalen < 8)	/* UDP header is 8 octets */
18697403Sobrien	      return (1);
18797403Sobrien	    uh = (const struct udphdr *) ptop;
18897403Sobrien	    sport = ntohs(uh->uh_sport);
18997403Sobrien	    dport = ntohs(uh->uh_dport);
190132720Skan	    estab = syn = finrst = -1;
19197403Sobrien	    if (log_IsKept(LogDEBUG))
19297403Sobrien	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
19397403Sobrien		       sport, dport);
19497403Sobrien	    break;
19597403Sobrien	  case IPPROTO_TCP:
19697403Sobrien	    cproto = P_TCP;
19797403Sobrien	    th = (const struct tcphdr *) ptop;
19897403Sobrien	    /* TCP headers are variable length.  The following code
19997403Sobrien	     * ensures that the TCP header length isn't de-referenced if
20097403Sobrien	     * the datagram is too short
20197403Sobrien	     */
20297403Sobrien	    if (datalen < 20 || datalen < (th->th_off << 2))
20397403Sobrien	      return (1);
20497403Sobrien	    sport = ntohs(th->th_sport);
20597403Sobrien	    dport = ntohs(th->th_dport);
20697403Sobrien	    estab = (th->th_flags & TH_ACK);
20797403Sobrien	    syn = (th->th_flags & TH_SYN);
20897403Sobrien	    finrst = (th->th_flags & (TH_FIN|TH_RST));
20997403Sobrien	    if (log_IsKept(LogDEBUG)) {
210117397Skan	      if (!estab)
211117397Skan		snprintf(dbuff, sizeof dbuff,
212117397Skan			 "flags = %02x, sport = %d, dport = %d",
213117397Skan			 th->th_flags, sport, dport);
214117397Skan	      else
215132720Skan		*dbuff = '\0';
216117397Skan	    }
217117397Skan	    break;
218117397Skan	  default:
219117397Skan	    return (1);	/* We'll block unknown type of packet */
220117397Skan	  }
221117397Skan
222117397Skan	  if (log_IsKept(LogDEBUG)) {
223117397Skan	    if (estab != -1) {
224117397Skan	      len = strlen(dbuff);
225117397Skan	      snprintf(dbuff + len, sizeof dbuff - len,
226117397Skan		       ", estab = %d, syn = %d, finrst = %d",
227117397Skan		       estab, syn, finrst);
228117397Skan	    }
229117397Skan	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
23097403Sobrien		       filter_Proto2Nam(cproto), dbuff);
23197403Sobrien	  }
232117397Skan	  gotinfo = 1;
23397403Sobrien	}
234117397Skan	if (log_IsKept(LogDEBUG)) {
235117397Skan	  if (fp->f_srcop != OP_NONE) {
236117397Skan	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
237117397Skan		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
238117397Skan	    len = strlen(dbuff);
239117397Skan	  } else
24097403Sobrien	    len = 0;
241117397Skan	  if (fp->f_dstop != OP_NONE) {
24297403Sobrien	    snprintf(dbuff + len, sizeof dbuff - len,
24397403Sobrien		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
244117397Skan		     fp->f_dstport);
245117397Skan	  } else if (!len)
246117397Skan	    *dbuff = '\0';
247117397Skan
248117397Skan	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
249117397Skan		     "check against proto %s%s, action = %s\n",
250117397Skan		     n, filter_Proto2Nam(fp->f_proto),
251117397Skan		     dbuff, filter_Action2Nam(fp->f_action));
252117397Skan	}
253117397Skan
254117397Skan	if (cproto == fp->f_proto) {
255117397Skan	  if ((fp->f_srcop == OP_NONE ||
256117397Skan	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
257117397Skan	      (fp->f_dstop == OP_NONE ||
258117397Skan	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
259117397Skan	      (fp->f_estab == 0 || estab) &&
260117397Skan	      (fp->f_syn == 0 || syn) &&
261117397Skan	      (fp->f_finrst == 0 || finrst)) {
262117397Skan	    match = 1;
263117397Skan	  }
264117397Skan	}
265117397Skan      } else {
266117397Skan	/* Address is matched and no protocol specified. Make a decision. */
267117397Skan	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
268117397Skan		   filter_Action2Nam(fp->f_action));
269117397Skan	match = 1;
270117397Skan      }
271117397Skan    } else
27297403Sobrien      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
273117397Skan
27497403Sobrien    if (match != fp->f_invert) {
275117397Skan      /* Take specified action */
276117397Skan      if (fp->f_action < A_NONE)
277117397Skan	fp = &filter->rule[n = fp->f_action];
278117397Skan      else
279117397Skan	return (fp->f_action != A_PERMIT);
280117397Skan    } else {
281117397Skan      n++;
282117397Skan      fp++;
283117397Skan    }
284117397Skan  }
285117397Skan  return (1);		/* No rule is mached. Deny this packet */
28697403Sobrien}
28797403Sobrien
28897403Sobrien#ifdef notdef
289117397Skanstatic void
290117397SkanIcmpError(struct ip *pip, int code)
291117397Skan{
292117397Skan  struct mbuf *bp;
293117397Skan
294117397Skan  if (pip->ip_p != IPPROTO_ICMP) {
295117397Skan    bp = mbuf_Alloc(cnt, MB_IPIN);
296117397Skan    memcpy(MBUF_CTOP(bp), ptr, cnt);
297117397Skan    vj_SendFrame(bp);
298117397Skan    ipcp_AddOutOctets(cnt);
299117397Skan  }
300117397Skan}
301117397Skan#endif
302117397Skan
303117397Skan/*
304117397Skan *  For debugging aid.
305117397Skan */
306117397Skanint
307117397SkanPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
308117397Skan{
309117397Skan  struct ip *pip;
310117397Skan  struct tcphdr *th;
311117397Skan  struct udphdr *uh;
312117397Skan  struct icmp *icmph;
31397403Sobrien  char *ptop;
31497403Sobrien  int mask, len, n;
31597403Sobrien  int pri = 0;
316117397Skan  int logit, loglen;
317117397Skan  char logbuf[200];
318117397Skan
319117397Skan  logit = log_IsKept(LogTCPIP) && filter->logok;
320117397Skan  loglen = 0;
321117397Skan
322117397Skan  pip = (struct ip *) cp;
323117397Skan
32497403Sobrien  if (logit && loglen < sizeof logbuf) {
32597403Sobrien    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
32697403Sobrien    loglen += strlen(logbuf + loglen);
32797403Sobrien  }
328117397Skan  ptop = (cp + (pip->ip_hl << 2));
329117397Skan
330117397Skan  switch (pip->ip_p) {
331117397Skan  case IPPROTO_ICMP:
332117397Skan    if (logit && loglen < sizeof logbuf) {
333117397Skan      icmph = (struct icmp *) ptop;
334117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
335117397Skan	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
336117397Skan      loglen += strlen(logbuf + loglen);
337117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
338117397Skan	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
339117397Skan      loglen += strlen(logbuf + loglen);
340117397Skan    }
341117397Skan    break;
342117397Skan
343117397Skan  case IPPROTO_UDP:
344117397Skan    uh = (struct udphdr *) ptop;
345117397Skan    if (pip->ip_tos == IPTOS_LOWDELAY)
346117397Skan      pri++;
34797403Sobrien
34897403Sobrien    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
34997403Sobrien        ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
350117397Skan                          ntohs(uh->uh_dport)))
351117397Skan      pri++;
352117397Skan
353117397Skan    if (logit && loglen < sizeof logbuf) {
354117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
355117397Skan	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
356117397Skan      loglen += strlen(logbuf + loglen);
35797403Sobrien      snprintf(logbuf + loglen, sizeof logbuf - loglen,
35897403Sobrien	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
35997403Sobrien      loglen += strlen(logbuf + loglen);
36097403Sobrien    }
361117397Skan    break;
362117397Skan
363117397Skan#ifdef IPPROTO_OSPFIGP
364117397Skan  case IPPROTO_OSPFIGP:
365117397Skan    if (logit && loglen < sizeof logbuf) {
366117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
367117397Skan	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
368117397Skan      loglen += strlen(logbuf + loglen);
369117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
370117397Skan	       "%s", inet_ntoa(pip->ip_dst));
371117397Skan      loglen += strlen(logbuf + loglen);
372117397Skan    }
373117397Skan    break;
374117397Skan#endif
375117397Skan
376117397Skan  case IPPROTO_IPIP:
377117397Skan    if (logit && loglen < sizeof logbuf) {
378117397Skan      uh = (struct udphdr *) ptop;
379117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
380117397Skan	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
381117397Skan      loglen += strlen(logbuf + loglen);
382117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
383117397Skan	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
384117397Skan      loglen += strlen(logbuf + loglen);
385117397Skan    }
38697403Sobrien    break;
38797403Sobrien
38897403Sobrien  case IPPROTO_IGMP:
389117397Skan    if (logit && loglen < sizeof logbuf) {
390117397Skan      uh = (struct udphdr *) ptop;
391117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
392117397Skan	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
393117397Skan      loglen += strlen(logbuf + loglen);
394117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
395117397Skan	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
396117397Skan      loglen += strlen(logbuf + loglen);
39797403Sobrien    }
39897403Sobrien    break;
39997403Sobrien
40097403Sobrien  case IPPROTO_TCP:
401117397Skan    th = (struct tcphdr *) ptop;
402117397Skan    if (pip->ip_tos == IPTOS_LOWDELAY)
403117397Skan      pri++;
404117397Skan
405117397Skan    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
406117397Skan        ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
407117397Skan                          ntohs(th->th_dport)))
408117397Skan      pri++;
409117397Skan
410117397Skan    if (logit && loglen < sizeof logbuf) {
411117397Skan      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
412117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
413117397Skan	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
414117397Skan      loglen += strlen(logbuf + loglen);
415117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
41697403Sobrien	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
41797403Sobrien      loglen += strlen(logbuf + loglen);
41897403Sobrien      n = 0;
419117397Skan      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
420117397Skan	if (th->th_flags & mask) {
421117397Skan	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
422117397Skan	  loglen += strlen(logbuf + loglen);
423117397Skan	}
424117397Skan	n++;
425117397Skan      }
426117397Skan      snprintf(logbuf + loglen, sizeof logbuf - loglen,
42797403Sobrien	       "  seq:%lx  ack:%lx (%d/%d)",
428117397Skan	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
42997403Sobrien      loglen += strlen(logbuf + loglen);
430117397Skan      if ((th->th_flags & TH_SYN) && nb > 40) {
431117397Skan	u_short *sp;
432117397Skan
433117397Skan	ptop += 20;
434117397Skan	sp = (u_short *) ptop;
435117397Skan	if (ntohs(sp[0]) == 0x0204) {
436117397Skan	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
437117397Skan		   " MSS = %d", ntohs(sp[1]));
438117397Skan	  loglen += strlen(logbuf + loglen);
439117397Skan	}
440117397Skan      }
441117397Skan    }
442117397Skan    break;
443117397Skan  }
444117397Skan
44597403Sobrien  if (FilterCheck(pip, filter)) {
44697403Sobrien    if (logit)
44797403Sobrien      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
448117397Skan#ifdef notdef
449117397Skan    if (direction == 0)
450117397Skan      IcmpError(pip, pri);
451117397Skan#endif
452117397Skan    return (-1);
453117397Skan  } else {
454117397Skan    /* Check Keep Alive filter */
455117397Skan    if (logit) {
456117397Skan      if (FilterCheck(pip, &bundle->filter.alive))
457117397Skan        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
458117397Skan      else
459117397Skan        log_Printf(LogTCPIP, "%s\n", logbuf);
460117397Skan    }
461117397Skan    return (pri);
462117397Skan  }
463117397Skan}
46497403Sobrien
46597403Sobrienstruct mbuf *
46697403Sobrienip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
467117397Skan{
468117397Skan  int nb, nw;
469117397Skan  struct tun_data tun;
470117397Skan  struct ip *pip;
471117397Skan
472117397Skan  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
473117397Skan    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
474117397Skan    mbuf_Free(bp);
475117397Skan    return NULL;
476117397Skan  }
477117397Skan
478117397Skan  mbuf_SetType(bp, MB_IPIN);
479117397Skan  tun_fill_header(tun, AF_INET);
48097403Sobrien  nb = mbuf_Length(bp);
48197403Sobrien  if (nb > sizeof tun.data) {
48297403Sobrien    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
483117397Skan               l->name, nb, (int)(sizeof tun.data));
484117397Skan    mbuf_Free(bp);
485117397Skan    return NULL;
486117397Skan  }
487117397Skan  mbuf_Read(bp, tun.data, nb);
488117397Skan
489117397Skan  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
490117397Skan    return NULL;
491117397Skan
492117397Skan  pip = (struct ip *)tun.data;
493117397Skan  if (!FilterCheck(pip, &bundle->filter.alive))
494117397Skan    bundle_StartIdleTimer(bundle);
49597403Sobrien
496117397Skan  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
49797403Sobrien
498117397Skan  nb += sizeof tun - sizeof tun.data;
499117397Skan  nw = write(bundle->dev.fd, &tun, nb);
500117397Skan  if (nw != nb) {
501117397Skan    if (nw == -1)
502117397Skan      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
503117397Skan                 l->name, nb, strerror(errno));
504117397Skan    else
505117397Skan      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
506117397Skan  }
507117397Skan
508117397Skan  return NULL;
509117397Skan}
510117397Skan
511117397Skanvoid
512117397Skanip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
51397403Sobrien{
514117397Skan  struct mbuf *bp;
51597403Sobrien
516117397Skan  if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
517117397Skan    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
518117397Skan  else {
519117397Skan    /*
520117397Skan     * We allocate an extra 6 bytes, four at the front and two at the end.
521117397Skan     * This is an optimisation so that we need to do less work in
522117397Skan     * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and
523117397Skan     * appending in hdlc_LayerPush().
524117397Skan     */
525117397Skan    bp = mbuf_Alloc(count + 6, MB_IPOUT);
526117397Skan    bp->offset += 4;
52797403Sobrien    bp->cnt -= 6;
528117397Skan    memcpy(MBUF_CTOP(bp), ptr, count);
52997403Sobrien    mbuf_Enqueue(ipcp->Queue + pri, bp);
530117397Skan  }
531117397Skan}
532117397Skan
533117397Skanvoid
534117397Skanip_DeleteQueue(struct ipcp *ipcp)
535117397Skan{
536117397Skan  struct mqueue *queue;
537117397Skan
538117397Skan  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
539117397Skan    while (queue->top)
540117397Skan      mbuf_Free(mbuf_Dequeue(queue));
541117397Skan}
54297403Sobrien
54397403Sobrienint
54497403Sobrienip_QueueLen(struct ipcp *ipcp)
545117397Skan{
546117397Skan  struct mqueue *queue;
547117397Skan  int result = 0;
548117397Skan
549117397Skan  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
550117397Skan    result += queue->qlen;
551117397Skan
552117397Skan  return result;
553117397Skan}
554117397Skan
555117397Skanint
556117397Skanip_PushPacket(struct link *l, struct bundle *bundle)
557117397Skan{
55897403Sobrien  struct ipcp *ipcp = &bundle->ncp.ipcp;
55997403Sobrien  struct mqueue *queue;
560117397Skan  struct mbuf *bp;
561132720Skan  struct ip *pip;
562132720Skan  int cnt;
563132720Skan
564132720Skan  if (ipcp->fsm.state != ST_OPENED)
56597403Sobrien    return 0;
56697403Sobrien
567117397Skan  queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
568117397Skan  do {
569117397Skan    if (queue->top) {
570117397Skan      bp = mbuf_Contiguous(mbuf_Dequeue(queue));
571117397Skan      cnt = mbuf_Length(bp);
572117397Skan      pip = (struct ip *)MBUF_CTOP(bp);
573117397Skan      if (!FilterCheck(pip, &bundle->filter.alive))
574117397Skan        bundle_StartIdleTimer(bundle);
575117397Skan      link_PushPacket(l, bp, bundle, 0, PROTO_IP);
576117397Skan      ipcp_AddOutOctets(ipcp, cnt);
577117397Skan      return 1;
57897403Sobrien    }
57997403Sobrien  } while (queue-- != ipcp->Queue);
58097403Sobrien
58197403Sobrien  return 0;
582117397Skan}
58397403Sobrien