X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/8a13b73762073376faf12d2b8b2d763eeb7def70..4f483d7dc3ca3e5a8ac5145cdc54a67819dea48e:/usr/src/sys/netinet/ip_input.c diff --git a/usr/src/sys/netinet/ip_input.c b/usr/src/sys/netinet/ip_input.c index 014e589cbd..04fc07c13f 100644 --- a/usr/src/sys/netinet/ip_input.c +++ b/usr/src/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* ip_input.c 1.19 81/11/26 */ +/* ip_input.c 1.38 82/03/31 */ #include "../h/param.h" #include "../h/systm.h" @@ -15,9 +15,12 @@ #include "../net/tcp.h" u_char ip_protox[IPPROTO_MAX]; +int ipqmaxlen = IFQ_MAXLEN; +struct ifnet *ifinet; /* first inet interface */ /* - * Ip initialization. + * IP initialization: fill in IP protocol switch table. + * All protocols not implemented in kernel go to raw IP protocol handler. */ ip_init() { @@ -36,14 +39,15 @@ COUNT(IP_INIT); ip_protox[pr->pr_protocol] = pr - protosw; ipq.next = ipq.prev = &ipq; ip_id = time & 0xffff; + ipintrq.ifq_maxlen = ipqmaxlen; + ifinet = if_ifwithaf(AF_INET); } u_char ipcksum = 1; struct ip *ip_reass(); - -/* - * Ip input routines. - */ +int ipforwarding = 1; +int ipprintfs = 0; +struct sockaddr_in ipaddr = { AF_INET }; /* * Ip input routine. Checksum and byte swap header. If fragmented @@ -54,7 +58,7 @@ ipintr() { register struct ip *ip; register struct mbuf *m; - struct mbuf *m0; + struct mbuf *m0, *mopt; register int i; register struct ipq *fp; int hlen, s; @@ -70,26 +74,30 @@ next: splx(s); if (m == 0) return; - if (m->m_len < sizeof (struct ip) && - m_pullup(m, sizeof (struct ip)) == 0) - goto bad; + if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && + (m = m_pullup(m, sizeof (struct ip))) == 0) + return; ip = mtod(m, struct ip *); - if ((hlen = ip->ip_hl << 2) > m->m_len && - m_pullup(m, hlen) == 0) - goto bad; + if ((hlen = ip->ip_hl << 2) > m->m_len) { + if ((m = m_pullup(m, hlen)) == 0) + return; + ip = mtod(m, struct ip *); + } if (ipcksum) - if ((ip->ip_sum = in_cksum(m, hlen)) != 0xffff) { - printf("ip_sum %x\n", ip->ip_sum); + if (ip->ip_sum = in_cksum(m, hlen)) { + printf("ip_sum %x\n", ip->ip_sum); /* XXX */ ipstat.ips_badsum++; goto bad; } +#if vax /* * Convert fields to host representation. */ ip->ip_len = ntohs((u_short)ip->ip_len); ip->ip_id = ntohs(ip->ip_id); ip->ip_off = ntohs((u_short)ip->ip_off); +#endif /* * Check that the amount of data in the buffers @@ -98,12 +106,17 @@ next: * Drop packet if shorter than we expect. */ i = 0; - for (m0 = m; m != NULL; m = m->m_next) + m0 = m; + for (; m != NULL; m = m->m_next) { + if (m->m_free) panic("ipinput already free"); i += m->m_len; + } m = m0; if (i != ip->ip_len) { - if (i < ip->ip_len) + if (i < ip->ip_len) { + ipstat.ips_tooshort++; goto bad; + } m_adj(m, ip->ip_len - i); } @@ -113,16 +126,44 @@ next: */ if (hlen > sizeof (struct ip)) ip_dooptions(ip); - if (ifnet && ip->ip_dst.s_addr != ifnet->if_addr.s_addr && - if_ifwithaddr(ip->ip_dst) == 0) { - if (--ip->ip_ttl == 0) { + + /* + * Fast check on the first internet + * interface in the list. + */ + if (ifinet) { + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)&ifinet->if_addr; + if (sin->sin_addr.s_addr == ip->ip_dst.s_addr) + goto ours; + if ((ifinet->if_flags & IFF_BROADCAST) && + sin->sin_addr.s_addr == ip->ip_dst.s_addr) + goto ours; + } + ipaddr.sin_addr = ip->ip_dst; + if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0) { + if (ipprintfs) + printf("forward: src %x dst %x ttl %x\n", ip->ip_src, + ip->ip_dst, ip->ip_ttl); + if (ipforwarding == 0) + goto bad; + if (ip->ip_ttl < IPTTLDEC) { icmp_error(ip, ICMP_TIMXCEED, 0); goto next; } - ip_output(dtom(ip), (struct mbuf *)0); + ip->ip_ttl -= IPTTLDEC; + mopt = m_get(M_DONTWAIT); + if (mopt == 0) + goto bad; + ip_stripoptions(ip, mopt); + + /* last 0 here means no directed broadcast */ + (void) ip_output(m0, mopt, 0, 0); goto next; } +ours: /* * Look for queue of fragments * of this datagram. @@ -201,7 +242,7 @@ COUNT(IP_REASS); * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { - if ((t = m_get(1)) == NULL) + if ((t = m_get(M_WAIT)) == NULL) goto dropfrag; t->m_off = MMINOFF; fp = mtod(t, struct ipq *); @@ -212,6 +253,8 @@ COUNT(IP_REASS); fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; fp->ipq_src = ((struct ip *)ip)->ip_src; fp->ipq_dst = ((struct ip *)ip)->ip_dst; + q = (struct ipasfrag *)fp; + goto insert; } /* @@ -245,6 +288,7 @@ COUNT(IP_REASS); i = (ip->ip_off + ip->ip_len) - q->ip_off; if (i < q->ip_len) { q->ip_len -= i; + q->ip_off += i; m_adj(dtom(q), i); break; } @@ -253,6 +297,7 @@ COUNT(IP_REASS); ip_deq(q->ipf_prev); } +insert: /* * Stick new segment in its place; * check for complete reassembly. @@ -275,8 +320,12 @@ COUNT(IP_REASS); t = m->m_next; m->m_next = 0; m_cat(m, t); - while ((q = q->ipf_next) != (struct ipasfrag *)fp) - m_cat(m, dtom(q)); + q = q->ipf_next; + while (q != (struct ipasfrag *)fp) { + t = dtom(q); + q = q->ipf_next; + m_cat(m, t); + } /* * Create header for new ip packet by @@ -359,7 +408,12 @@ ip_slowtimo() int s = splnet(); COUNT(IP_SLOWTIMO); - for (fp = ipq.next; fp != &ipq; ) + fp = ipq.next; + if (fp == 0) { + splx(s); + return; + } + while (fp != &ipq) if (--fp->ipq_ttl == 0) fp = ip_freef(fp); else @@ -422,7 +476,8 @@ COUNT(IP_DOOPTIONS); if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1)) break; sin = (struct in_addr *)(cp + cp[2]); - ifp = if_ifwithaddr(*sin); + ipaddr.sin_addr = *sin; + ifp = if_ifwithaddr((struct sockaddr *)&ipaddr); if (ifp == 0) { if (opt == IPOPT_SSRR) goto bad; @@ -433,7 +488,8 @@ COUNT(IP_DOOPTIONS); if (cp[2] > optlen - (sizeof (long) - 1)) break; ip->ip_dst = sin[1]; - if (opt == IPOPT_SSRR && if_ifonnetof(ip->ip_dst)==0) + if (opt == IPOPT_SSRR && + if_ifonnetof(ip->ip_dst.s_net) == 0) goto bad; break; @@ -455,12 +511,14 @@ COUNT(IP_DOOPTIONS); case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr + 8 > ipt->ipt_len) goto bad; - /* stamp with ``first'' interface address */ - *sin++ = ifnet->if_addr; + if (ifinet == 0) + goto bad; /* ??? */ + *sin++ = ((struct sockaddr_in *)&ifinet->if_addr)->sin_addr; break; case IPOPT_TS_PRESPEC: - if (if_ifwithaddr(*sin) == 0) + ipaddr.sin_addr = *sin; + if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0) continue; if (ipt->ipt_ptr + 8 > ipt->ipt_len) goto bad; @@ -486,9 +544,9 @@ bad: * Second argument is buffer to which options * will be moved, and return value is their length. */ -ip_stripoptions(ip, cp) +ip_stripoptions(ip, mopt) struct ip *ip; - char *cp; + struct mbuf *mopt; { register int i; register struct mbuf *m; @@ -498,9 +556,12 @@ COUNT(IP_STRIPOPTIONS); olen = (ip->ip_hl<<2) - sizeof (struct ip); m = dtom(ip); ip++; - if (cp) - bcopy((caddr_t)ip, cp, (unsigned)olen); + if (mopt) { + mopt->m_len = olen; + mopt->m_off = MMINOFF; + bcopy((caddr_t)ip, mtod(m, caddr_t), (unsigned)olen); + } i = m->m_len - (sizeof (struct ip) + olen); bcopy((caddr_t)ip+olen, (caddr_t)ip, (unsigned)i); - m->m_len -= i; + m->m_len -= olen; }