Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet/ip_input.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet/ip_input.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.3.4.1 retrieving revision 1.16 diff -u -p -r1.3.4.1 -r1.16 --- src/sys/netinet/ip_input.c 1993/09/24 08:54:56 1.3.4.1 +++ src/sys/netinet/ip_input.c 1995/05/14 08:23:00 1.16 @@ -1,6 +1,8 @@ +/* $NetBSD: ip_input.c,v 1.16 1995/05/14 08:23:00 cgd Exp $ */ + /* - * Copyright (c) 1982, 1986, 1988 Regents of the University of California. - * All rights reserved. + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,33 +32,30 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)ip_input.c 7.19 (Berkeley) 5/25/91 - * $Id: ip_input.c,v 1.3.4.1 1993/09/24 08:54:56 mycroft Exp $ + * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 */ -#include "param.h" -#include "systm.h" -#include "malloc.h" -#include "mbuf.h" -#include "domain.h" -#include "protosw.h" -#include "socket.h" -#include "errno.h" -#include "time.h" -#include "kernel.h" - -#include "machine/cpu.h" - -#include "../net/if.h" -#include "../net/route.h" - -#include "in.h" -#include "in_systm.h" -#include "ip.h" -#include "in_pcb.h" -#include "in_var.h" -#include "ip_var.h" -#include "ip_icmp.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include #ifndef IPFORWARDING #ifdef GATEWAY @@ -70,6 +69,7 @@ #endif int ipforwarding = IPFORWARDING; int ipsendredirects = IPSENDREDIRECTS; +int ip_defttl = IPDEFTTL; #ifdef DIAGNOSTIC int ipprintfs = 0; #endif @@ -79,6 +79,7 @@ extern struct protosw inetsw[]; u_char ip_protox[IPPROTO_MAX]; int ipqmaxlen = IFQ_MAXLEN; struct in_ifaddr *in_ifaddr; /* first inet address */ +struct ifqueue ipintrq; /* * We need to save the IP options in case a protocol wants to respond @@ -97,13 +98,15 @@ static struct ip_srcrt { #ifdef GATEWAY extern int if_index; -u_long *ip_ifmatrix; +u_int32_t *ip_ifmatrix; #endif +static void save_rte __P((u_char *, struct in_addr)); /* * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. */ +void ip_init() { register struct protosw *pr; @@ -123,13 +126,12 @@ ip_init() ip_id = time.tv_sec & 0xffff; ipintrq.ifq_maxlen = ipqmaxlen; #ifdef GATEWAY - i = (if_index + 1) * (if_index + 1) * sizeof (u_long); - if ((ip_ifmatrix = (u_long *) malloc(i, M_RTABLE, M_WAITOK)) == 0) - panic("no memory for ip_ifmatrix"); + i = (if_index + 1) * (if_index + 1) * sizeof (u_int32_t); + ip_ifmatrix = (u_int32_t *) malloc(i, M_RTABLE, M_WAITOK); + bzero((char *)ip_ifmatrix, i); #endif } -struct ip *ip_reass(); struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET }; struct route ipforward_rt; @@ -137,6 +139,7 @@ struct route ipforward_rt; * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */ +void ipintr() { register struct ip *ip; @@ -144,13 +147,7 @@ ipintr() register struct ipq *fp; register struct in_ifaddr *ia; int hlen, s; -#ifdef PARANOID - static int busy = 0; - if (busy) - panic("ipintr: called recursively\n"); - ++busy; -#endif next: /* * Get next datagram off input queue and get IP header @@ -159,12 +156,8 @@ next: s = splimp(); IF_DEQUEUE(&ipintrq, m); splx(s); - if (m == 0) { -#ifdef PARANOID - --busy; -#endif + if (m == 0) return; - } #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("ipintr no HDR"); @@ -182,6 +175,10 @@ next: goto next; } ip = mtod(m, struct ip *); + if (ip->ip_v != IPVERSION) { + ipstat.ips_badvers++; + goto bad; + } hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) { /* minimum header length */ ipstat.ips_badhlen++; @@ -251,7 +248,7 @@ next: ia->ia_ifp == m->m_pkthdr.rcvif && #endif (ia->ia_ifp->if_flags & IFF_BROADCAST)) { - u_long t; + u_int32_t t; if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == ip->ip_dst.s_addr) @@ -269,7 +266,63 @@ next: goto ours; } } - if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) + if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { + struct in_multi *inm; +#ifdef MROUTING + extern struct socket *ip_mrouter; + + if (m->m_flags & M_EXT) { + if ((m = m_pullup(m, hlen)) == 0) { + ipstat.ips_toosmall++; + goto next; + } + ip = mtod(m, struct ip *); + } + + if (ip_mrouter) { + /* + * If we are acting as a multicast router, all + * incoming multicast packets are passed to the + * kernel-level multicast forwarding function. + * The packet is returned (relatively) intact; if + * ip_mforward() returns a non-zero value, the packet + * must be discarded, else it may be accepted below. + * + * (The IP ident field is put in the same byte order + * as expected when ip_mforward() is called from + * ip_output().) + */ + ip->ip_id = htons(ip->ip_id); + if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) { + ipstat.ips_cantforward++; + m_freem(m); + goto next; + } + ip->ip_id = ntohs(ip->ip_id); + + /* + * The process-level routing demon needs to receive + * all multicast IGMP packets, whether or not this + * host belongs to their destination groups. + */ + if (ip->ip_p == IPPROTO_IGMP) + goto ours; + ipstat.ips_forward++; + } +#endif + /* + * See if we belong to the destination multicast group on the + * arrival interface. + */ + IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); + if (inm == NULL) { + ipstat.ips_cantforward++; + m_freem(m); + goto next; + } + goto ours; + } + if (ip->ip_dst.s_addr == (u_int32_t)INADDR_BROADCAST) goto ours; if (ip->ip_dst.s_addr == INADDR_ANY) goto ours; @@ -319,9 +372,18 @@ found: * convert offset of this to bytes. */ ip->ip_len -= hlen; - ((struct ipasfrag *)ip)->ipf_mff = 0; - if (ip->ip_off & IP_MF) - ((struct ipasfrag *)ip)->ipf_mff = 1; + ((struct ipasfrag *)ip)->ipf_mff &= ~1; + if (ip->ip_off & IP_MF) { + /* + * Make sure that fragments have a data length + * that's a non-zero multiple of 8 bytes. + */ + if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) + ipstat.ips_badfrags++; + goto bad; + } + ((struct ipasfrag *)ip)->ipf_mff |= 1; + } ip->ip_off <<= 3; /* @@ -329,13 +391,12 @@ found: * or if this is not the first fragment, * attempt reassembly; if it succeeds, proceed. */ - if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { + if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { ipstat.ips_fragments++; ip = ip_reass((struct ipasfrag *)ip, fp); if (ip == 0) goto next; - else - ipstat.ips_reassembled++; + ipstat.ips_reassembled++; m = dtom(ip); } else if (fp) @@ -448,7 +509,7 @@ insert: return (0); next += q->ip_len; } - if (q->ipf_prev->ipf_mff) + if (q->ipf_prev->ipf_mff & 1) return (0); /* @@ -474,6 +535,7 @@ insert: */ ip = fp->ipq_next; ip->ip_len = next; + ip->ipf_mff &= ~1; ((struct ip *)ip)->ip_src = fp->ipq_src; ((struct ip *)ip)->ip_dst = fp->ipq_dst; remque(fp); @@ -500,6 +562,7 @@ dropfrag: * Free a fragment reassembly header and all * associated datagrams. */ +void ip_freef(fp) struct ipq *fp; { @@ -518,6 +581,7 @@ ip_freef(fp) * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. */ +void ip_enq(p, prev) register struct ipasfrag *p, *prev; { @@ -531,6 +595,7 @@ ip_enq(p, prev) /* * To ip_enq as remque is to insque. */ +void ip_deq(p) register struct ipasfrag *p; { @@ -544,6 +609,7 @@ ip_deq(p) * if a timer expires on a reassembly * queue, discard it. */ +void ip_slowtimo() { register struct ipq *fp; @@ -568,6 +634,7 @@ ip_slowtimo() /* * Drain off all datagram fragments. */ +void ip_drain() { @@ -577,9 +644,6 @@ ip_drain() } } -extern struct in_ifaddr *ifptoia(); -struct in_ifaddr *ip_rtaddr(); - /* * Do option processing on a datagram, * possibly discarding it if bad options are encountered, @@ -587,6 +651,7 @@ struct in_ifaddr *ip_rtaddr(); * Returns 1 if packet has been forwarded/freed, * 0 if the packet should be processed further. */ +int ip_dooptions(m) struct mbuf *m; { @@ -595,9 +660,10 @@ ip_dooptions(m) register struct ip_timestamp *ipt; register struct in_ifaddr *ia; int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; - struct in_addr *sin; + struct in_addr *sin, dst; n_time ntime; + dst = ip->ip_dst; cp = (u_char *)(ip + 1); cnt = (ip->ip_hl << 2) - sizeof (struct ip); for (; cnt > 0; cnt -= optlen, cp += optlen) { @@ -665,7 +731,7 @@ ip_dooptions(m) #define INA struct in_ifaddr * #define SA struct sockaddr * if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) - ia = in_iaonnetof(in_netof(ipaddr.sin_addr)); + ia = (INA)ifa_ifwithnet((SA)&ipaddr); } else ia = ip_rtaddr(ipaddr.sin_addr); if (ia == 0) { @@ -677,7 +743,10 @@ ip_dooptions(m) bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); - forward = 1; + /* + * Let ip_intr's mcast routing check handle mcast pkts + */ + forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); break; case IPOPT_RR: @@ -713,7 +782,7 @@ ip_dooptions(m) ipt = (struct ip_timestamp *)cp; if (ipt->ipt_len < 5) goto bad; - if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { + if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) { if (++ipt->ipt_oflw == 0) goto bad; break; @@ -728,7 +797,11 @@ ip_dooptions(m) if (ipt->ipt_ptr + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; - ia = ifptoia(m->m_pkthdr.rcvif); + ipaddr.sin_addr = dst; + ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, + m->m_pkthdr.rcvif); + if (ia == 0) + continue; bcopy((caddr_t)&IA_SIN(ia)->sin_addr, (caddr_t)sin, sizeof(struct in_addr)); ipt->ipt_ptr += sizeof(struct in_addr); @@ -757,10 +830,12 @@ ip_dooptions(m) if (forward) { ip_forward(m, 1); return (1); - } else - return (0); + } + return (0); bad: - icmp_error(m, type, code); + ip->ip_len -= ip->ip_hl << 2; /* XXX icmp_error adds in hdr length */ + icmp_error(m, type, code, 0, 0); + ipstat.ips_badoptions++; return (1); } @@ -796,6 +871,7 @@ ip_rtaddr(dst) * Save incoming source route for use in replies, * to be picked up later by ip_srcroute if the receiver is interested. */ +void save_rte(option, dst) u_char *option; struct in_addr dst; @@ -890,6 +966,7 @@ ip_srcroute() * will be moved, and return value is their length. * XXX should be deleted; last arg currently ignored. */ +void ip_stripoptions(m, mopt) register struct mbuf *m; struct mbuf *mopt; @@ -932,6 +1009,7 @@ u_char inetctlerrmap[PRC_NCMDS] = { * The srcrt parameter indicates whether the packet is being forwarded * via a source route. */ +void ip_forward(m, srcrt) struct mbuf *m; int srcrt; @@ -941,9 +1019,10 @@ ip_forward(m, srcrt) register struct rtentry *rt; int error, type = 0, code; struct mbuf *mcopy; - struct in_addr dest; + n_long dest; + struct ifnet *destifp; - dest.s_addr = 0; + dest = 0; #ifdef DIAGNOSTIC if (ipprintfs) printf("forward: src %x dst %x ttl %x\n", ip->ip_src, @@ -956,7 +1035,7 @@ ip_forward(m, srcrt) } HTONS(ip->ip_id); if (ip->ip_ttl <= IPTTLDEC) { - icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest); + icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); return; } ip->ip_ttl -= IPTTLDEC; @@ -974,7 +1053,7 @@ ip_forward(m, srcrt) rtalloc(&ipforward_rt); if (ipforward_rt.ro_rt == 0) { - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest); + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); return; } rt = ipforward_rt.ro_rt; @@ -1003,40 +1082,30 @@ ip_forward(m, srcrt) (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && satosin(rt_key(rt))->sin_addr.s_addr != 0 && ipsendredirects && !srcrt) { - struct in_ifaddr *ia; - u_long src = ntohl(ip->ip_src.s_addr); - u_long dst = ntohl(ip->ip_dst.s_addr); +#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) + u_int32_t src = ntohl(ip->ip_src.s_addr); - if ((ia = ifptoia(m->m_pkthdr.rcvif)) && - (src & ia->ia_subnetmask) == ia->ia_subnet) { + if (RTA(rt) && + (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { if (rt->rt_flags & RTF_GATEWAY) - dest = satosin(rt->rt_gateway)->sin_addr; + dest = satosin(rt->rt_gateway)->sin_addr.s_addr; else - dest = ip->ip_dst; - /* - * If the destination is reached by a route to host, - * is on a subnet of a local net, or is directly - * on the attached net (!), use host redirect. - * (We may be the correct first hop for other subnets.) - */ -#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) + dest = ip->ip_dst.s_addr; + /* Router requirements says to only send host redirects */ type = ICMP_REDIRECT; - if ((rt->rt_flags & RTF_HOST) || - (rt->rt_flags & RTF_GATEWAY) == 0) - code = ICMP_REDIRECT_HOST; - else if (RTA(rt)->ia_subnetmask != RTA(rt)->ia_netmask && - (dst & RTA(rt)->ia_netmask) == RTA(rt)->ia_net) - code = ICMP_REDIRECT_HOST; - else - code = ICMP_REDIRECT_NET; + code = ICMP_REDIRECT_HOST; #ifdef DIAGNOSTIC if (ipprintfs) - printf("redirect (%d) to %x\n", code, dest.s_addr); + printf("redirect (%d) to %lx\n", code, (u_int32_t)dest); #endif } } - error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING); + error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING +#ifdef DIRECTED_BROADCAST + | IP_ALLOWBROADCAST +#endif + , 0); if (error) ipstat.ips_cantforward++; else { @@ -1051,6 +1120,8 @@ ip_forward(m, srcrt) } if (mcopy == NULL) return; + destifp = NULL; + switch (error) { case 0: /* forwarded, but need redirect */ @@ -1069,6 +1140,8 @@ ip_forward(m, srcrt) case EMSGSIZE: type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; + if (ipforward_rt.ro_rt) + destifp = ipforward_rt.ro_rt->rt_ifp; ipstat.ips_cantfrag++; break; @@ -1077,5 +1150,36 @@ ip_forward(m, srcrt) code = 0; break; } - icmp_error(mcopy, type, code, dest); + icmp_error(mcopy, type, code, dest, destifp); +} + +int +ip_sysctl(name, namelen, oldp, oldlenp, newp, newlen) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + /* All sysctl names at this level are terminal. */ + if (namelen != 1) + return (ENOTDIR); + + switch (name[0]) { + case IPCTL_FORWARDING: + return (sysctl_int(oldp, oldlenp, newp, newlen, &ipforwarding)); + case IPCTL_SENDREDIRECTS: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &ipsendredirects)); + case IPCTL_DEFTTL: + return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_defttl)); +#ifdef notyet + case IPCTL_DEFMTU: + return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtu)); +#endif + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ }