X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/405c9168af72200b21fd65c6312d9b6dc4ab358f..15aae2a01acfd47907155f1dfecc7b2a98c2ab4b:/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 f9aa3aec3b..1f2cd30802 100644 --- a/usr/src/sys/netinet/ip_input.c +++ b/usr/src/sys/netinet/ip_input.c @@ -1,23 +1,30 @@ -/* ip_input.c 1.21 81/12/02 */ +/* ip_input.c 1.56 82/10/23 */ #include "../h/param.h" #include "../h/systm.h" -#include "../h/clock.h" #include "../h/mbuf.h" #include "../h/protosw.h" #include "../h/socket.h" -#include "../net/in.h" -#include "../net/in_systm.h" +#include +#include +#include "../h/kernel.h" + #include "../net/if.h" -#include "../net/ip.h" /* belongs before in.h */ -#include "../net/ip_var.h" -#include "../net/ip_icmp.h" -#include "../net/tcp.h" +#include "../net/route.h" +#include "../netinet/in.h" +#include "../netinet/in_pcb.h" +#include "../netinet/in_systm.h" +#include "../netinet/ip.h" +#include "../netinet/ip_var.h" +#include "../netinet/ip_icmp.h" +#include "../netinet/tcp.h" u_char ip_protox[IPPROTO_MAX]; +int ipqmaxlen = IFQ_MAXLEN; +struct ifnet *ifinet; /* first inet interface */ /* - * Ip initialization: fill in IP protocol switch table. + * IP initialization: fill in IP protocol switch table. * All protocols not implemented in kernel go to raw IP protocol handler. */ ip_init() @@ -25,7 +32,6 @@ ip_init() register struct protosw *pr; register int i; -COUNT(IP_INIT); pr = pffindproto(PF_INET, IPPROTO_RAW); if (pr == 0) panic("ip_init"); @@ -36,11 +42,14 @@ COUNT(IP_INIT); pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) ip_protox[pr->pr_protocol] = pr - protosw; ipq.next = ipq.prev = &ipq; - ip_id = time & 0xffff; + ip_id = time.tv_sec & 0xffff; + ipintrq.ifq_maxlen = ipqmaxlen; + ifinet = if_ifwithaf(AF_INET); } u_char ipcksum = 1; struct ip *ip_reass(); +struct sockaddr_in ipaddr = { AF_INET }; /* * Ip input routine. Checksum and byte swap header. If fragmented @@ -56,7 +65,6 @@ ipintr() register struct ipq *fp; int hlen, s; -COUNT(IPINTR); next: /* * Get next datagram off input queue and get IP header @@ -67,28 +75,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) { - if (m_pullup(m, hlen) == 0) - goto bad; + if ((m = m_pullup(m, hlen)) == 0) + return; ip = mtod(m, struct ip *); } if (ipcksum) - if ((ip->ip_sum = in_cksum(m, hlen)) != 0xffff) { + if (ip->ip_sum = in_cksum(m, hlen)) { printf("ip_sum %x\n", ip->ip_sum); /* XXX */ ipstat.ips_badsum++; goto bad; } +#if vax || pdp11 || ns16032 /* * 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 @@ -96,35 +106,57 @@ next: * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ - i = 0; + i = -ip->ip_len; m0 = m; - for (; m != NULL; m = m->m_next) + for (;;) { i += m->m_len; - m = m0; - if (i != ip->ip_len) { - if (i < ip->ip_len) { + if (m->m_next == 0) + break; + m = m->m_next; + } + if (i != 0) { + if (i < 0) { ipstat.ips_tooshort++; goto bad; } - m_adj(m, ip->ip_len - i); + if (i <= m->m_len) + m->m_len -= i; + else + m_adj(m0, -i); } + m = m0; /* * Process options and, if not destined for us, - * ship it on. + * ship it on. ip_dooptions returns 1 when an + * error was detected (causing an icmp message + * to be sent). */ - 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) { - icmp_error(ip, ICMP_TIMXCEED, 0); - goto next; - } - (void) ip_output(dtom(ip), (struct mbuf *)0); + if (hlen > sizeof (struct ip) && ip_dooptions(ip)) + goto next; + + /* + * 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; + sin = (struct sockaddr_in *)&ifinet->if_broadaddr; + 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) { + ip_forward(ip); goto next; } +ours: /* * Look for queue of fragments * of this datagram. @@ -190,7 +222,6 @@ ip_reass(ip, fp) struct mbuf *t; int hlen = ip->ip_hl << 2; int i, next; -COUNT(IP_REASS); /* * Presence of header sizes in mbufs @@ -203,9 +234,8 @@ 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 *); insque(fp, &ipq); fp->ipq_ttl = IPFRAGTTL; @@ -249,6 +279,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; } @@ -280,8 +311,12 @@ insert: 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 @@ -315,7 +350,6 @@ ip_freef(fp) { register struct ipasfrag *q; struct mbuf *m; -COUNT(IP_FREEF); for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) m_freem(dtom(q)); @@ -334,7 +368,6 @@ ip_enq(p, prev) register struct ipasfrag *p, *prev; { -COUNT(IP_ENQ); p->ipf_prev = prev; p->ipf_next = prev->ipf_next; prev->ipf_next->ipf_prev = p; @@ -348,7 +381,6 @@ ip_deq(p) register struct ipasfrag *p; { -COUNT(IP_DEQ); p->ipf_prev->ipf_next = p->ipf_next; p->ipf_next->ipf_prev = p->ipf_prev; } @@ -363,8 +395,12 @@ ip_slowtimo() register struct ipq *fp; 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 @@ -378,7 +414,6 @@ COUNT(IP_SLOWTIMO); ip_drain() { -COUNT(IP_DRAIN); while (ipq.next != &ipq) (void) ip_freef(ipq.next); } @@ -392,13 +427,12 @@ ip_dooptions(ip) struct ip *ip; { register u_char *cp; - int opt, optlen, cnt; + int opt, optlen, cnt, code, type; struct in_addr *sin; register struct ip_timestamp *ipt; register struct ifnet *ifp; struct in_addr t; -COUNT(IP_DOOPTIONS); cp = (u_char *)(ip + 1); cnt = (ip->ip_hl << 2) - sizeof (struct ip); for (; cnt > 0; cnt -= optlen, cp += optlen) { @@ -424,10 +458,13 @@ COUNT(IP_DOOPTIONS); * address on directly accessible net. */ case IPOPT_LSRR: + case IPOPT_SSRR: 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); + type = ICMP_UNREACH, code = ICMP_UNREACH_SRCFAIL; if (ifp == 0) { if (opt == IPOPT_SSRR) goto bad; @@ -438,11 +475,14 @@ 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(in_netof(ip->ip_dst)) == 0) goto bad; break; case IPOPT_TS: + code = cp - (u_char *)ip; + type = ICMP_PARAMPROB; ipt = (struct ip_timestamp *)cp; if (ipt->ipt_len < 5) goto bad; @@ -460,12 +500,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)) continue; if (ipt->ipt_ptr + 8 > ipt->ipt_len) goto bad; @@ -479,10 +521,10 @@ COUNT(IP_DOOPTIONS); ipt->ipt_ptr += 4; } } - return; + return (0); bad: - /* SHOULD FORCE ICMP MESSAGE */ - return; + icmp_error(ip, type, code); + return (1); } /* @@ -491,21 +533,130 @@ 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; int olen; -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; +} + +u_char inetctlerrmap[] = { + ECONNABORTED, ECONNABORTED, 0, 0, + 0, 0, + EHOSTDOWN, EHOSTUNREACH, ENETUNREACH, EHOSTUNREACH, + ECONNREFUSED, ECONNREFUSED, EMSGSIZE, 0, + 0, 0, 0, 0 +}; + +ip_ctlinput(cmd, arg) + int cmd; + caddr_t arg; +{ + struct in_addr *in; + int tcp_abort(), udp_abort(); + extern struct inpcb tcb, udb; + + if (cmd < 0 || cmd > PRC_NCMDS) + return; + if (inetctlerrmap[cmd] == 0) + return; /* XXX */ + if (cmd == PRC_IFDOWN) + in = &((struct sockaddr_in *)arg)->sin_addr; + else if (cmd == PRC_HOSTDEAD || cmd == PRC_HOSTUNREACH) + in = (struct in_addr *)arg; + else + in = &((struct icmp *)arg)->icmp_ip.ip_dst; +/* THIS IS VERY QUESTIONABLE, SHOULD HIT ALL PROTOCOLS */ + in_pcbnotify(&tcb, in, (int)inetctlerrmap[cmd], tcp_abort); + in_pcbnotify(&udb, in, (int)inetctlerrmap[cmd], udp_abort); +} + +int ipprintfs = 0; +int ipforwarding = 1; +/* + * Forward a packet. If some error occurs return the sender + * and icmp packet. Note we can't always generate a meaningful + * icmp message because icmp doesn't have a large enough repetoire + * of codes and types. + */ +ip_forward(ip) + register struct ip *ip; +{ + register int error, type, code; + struct mbuf *mopt, *mcopy; + + if (ipprintfs) + printf("forward: src %x dst %x ttl %x\n", ip->ip_src, + ip->ip_dst, ip->ip_ttl); + if (ipforwarding == 0) { + /* can't tell difference between net and host */ + type = ICMP_UNREACH, code = ICMP_UNREACH_NET; + goto sendicmp; + } + if (ip->ip_ttl < IPTTLDEC) { + type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS; + goto sendicmp; + } + ip->ip_ttl -= IPTTLDEC; + mopt = m_get(M_DONTWAIT); + if (mopt == 0) { + m_freem(dtom(ip)); + return; + } + + /* + * Save at most 64 bytes of the packet in case + * we need to generate an ICMP message to the src. + */ + mcopy = m_copy(dtom(ip), 0, imin(ip->ip_len, 64)); + ip_stripoptions(ip, mopt); + + /* last 0 here means no directed broadcast */ + if ((error = ip_output(dtom(ip), mopt, (struct route *)0, 0)) == 0) { + if (mcopy) + m_freem(mcopy); + return; + } + ip = mtod(mcopy, struct ip *); + type = ICMP_UNREACH, code = 0; /* need ``undefined'' */ + switch (error) { + + case ENETUNREACH: + case ENETDOWN: + code = ICMP_UNREACH_NET; + break; + + case EMSGSIZE: + code = ICMP_UNREACH_NEEDFRAG; + break; + + case EPERM: + code = ICMP_UNREACH_PORT; + break; + + case ENOBUFS: + type = ICMP_SOURCEQUENCH; + break; + + case EHOSTDOWN: + case EHOSTUNREACH: + code = ICMP_UNREACH_HOST; + break; + } +sendicmp: + icmp_error(ip, type, code); }