📄 ip_input.c
字号:
pMbufTmp = pMbPktFrag->m_nextpkt; pMbPktFrag->m_nextpkt = NULL ; m_cat (pMbuf, pMbPktFrag); /* concatenate the fragment */ } pIpHdrFrag = mtod(pMbuf, struct ipasfrag *); pIpHdrFrag->ip_len = len; /* length of the ip packet */ if (len > 0xffff - (pIpHdrFrag->ip_hl << 2)) /* ping of death */ goto dropFrag; /* drop entire chain */ pIpHdrFrag->ipf_mff &= ~1; remque(pIpFragQueue); (void) m_free (pIpFragQueue->pMbufHdr); /* some debugging cruft by sklower, below, will go away soon */ if (pMbuf->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ len = 0; for (pMbufTmp = pMbuf; pMbufTmp; pMbufTmp = pMbufTmp->m_next) len += pMbufTmp->m_len; pMbuf->m_pkthdr.len = len; } return (pMbuf); /* return the assembled packet */ dropFrag:#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_WARNING event */ WV_NET_ADDRIN_EVENT_1 (NET_CORE_EVENT, WV_NET_WARNING, 8, 13, pIpHdr->ip_src.s_addr, pIpHdr->ip_dst.s_addr, WV_NETEVENT_IPIN_FRAGDROP, WV_NET_RECV, pIpHdrFrag)#endif /* INCLUDE_WVNET */#endif#ifdef VIRTUAL_STACK _ipstat.ips_fragdropped++;#else ipstat.ips_fragdropped++;#endif /* VIRTUAL_STACK */ m_freem (pMbuf); /* free the fragment */ return (NULL); }/* * Free a fragment reassembly header and all * associated datagrams. */voidip_freef(fp) struct ipq *fp;{ struct mbuf ** pPtrMbuf; struct mbuf * pMbuf;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_ADDRIN_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 7, 17, fp->ipq_src.s_addr, fp->ipq_dst.s_addr, WV_NETEVENT_IPFRAGFREE_START, fp->ipq_src.s_addr, fp->ipq_dst.s_addr)#endif /* INCLUDE_WVNET */#endif /* free all fragments */ pPtrMbuf = &(fp->pMbufPkt); while (*pPtrMbuf) { pMbuf = (*pPtrMbuf)->m_nextpkt; m_freem (*pPtrMbuf); *pPtrMbuf = pMbuf; } remque(fp); (void) m_free(fp->pMbufHdr);}n_timeiptime(){ u_long t; /* t is time in milliseconds (i hope) */ t = ((int) tickGet () * 1000) / sysClkRateGet (); return (htonl(t));}/* * IP timer processing; * if a timer expires on a reassembly * queue, discard it. */voidip_slowtimo(){ register struct ipq *fp; int s = splnet();#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_MARKER_0 (NET_AUX_EVENT, WV_NET_INFO, 8, 18, WV_NETEVENT_IPTIMER_FRAGFREE)#endif /* INCLUDE_WVNET */#endif#ifdef VIRTUAL_STACK fp = _ipq.next;#else fp = ipq.next;#endif if (fp == 0) { splx(s); return; }#ifdef VIRTUAL_STACK while (fp != &_ipq) {#else while (fp != &ipq) {#endif --fp->ipq_ttl; fp = fp->next; if (fp->prev->ipq_ttl == 0) {#ifdef VIRTUAL_STACK _ipstat.ips_fragtimeout++;#else ipstat.ips_fragtimeout++;#endif /* VIRTUAL_STACK */ ip_freef(fp->prev); } } splx(s); return;}/* * Drain off all datagram fragments and excess (unused) route entries. */voidip_drain(){#ifdef VIRTUAL_STACK while (_ipq.next != &_ipq) { _ipstat.ips_fragdropped++; ip_freef(_ipq.next); }#else while (ipq.next != &ipq) { ipstat.ips_fragdropped++; ip_freef(ipq.next); }#endif /* VIRTUAL_STACK */ routeDrain(); return;}/* * Do option processing on a datagram, * possibly discarding it if bad options are encountered, * or forwarding it if source-routed. * Returns 1 if packet has been forwarded/freed, * 0 if the packet should be processed further. */intip_dooptions(m) struct mbuf *m;{ register struct ip *ip = mtod(m, struct ip *); register u_char *cp; 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, 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) { opt = cp[IPOPT_OPTVAL]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) optlen = 1; else { optlen = cp[IPOPT_OLEN]; if (optlen <= 0 || optlen > cnt) { code = &cp[IPOPT_OLEN] - (u_char *)ip; goto bad; } } switch (opt) { default: break; /* * Source routing with record. * Find interface with current destination address. * If none on this machine then drop if strictly routed, * or do nothing if loosely routed. * Record interface address and bring up next address * component. If strictly routed make sure next * address is on directly accessible net. */ case IPOPT_LSRR: case IPOPT_SSRR: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } input_ipaddr.sin_addr = ip->ip_dst; TOS_SET (&input_ipaddr, ip->ip_tos); /* tos routing */ ia = (struct in_ifaddr *) ifa_ifwithaddr((struct sockaddr *)&input_ipaddr); if (ia == 0) { if (opt == IPOPT_SSRR) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } /* * Loose routing, and not at next destination * yet; nothing to do except forward. */ break; } off--; /* 0 origin */ if (off > optlen - sizeof(struct in_addr)) { /* * End of source route. Should be for us. */#ifdef SRCRT save_rte(cp, ip->ip_src);#endif /* SRCRT */ break; } /* * locate outgoing interface */ bcopy((caddr_t)(cp + off), (caddr_t)&input_ipaddr.sin_addr, sizeof(input_ipaddr.sin_addr)); if (opt == IPOPT_SSRR) {#define INA struct in_ifaddr *#define SA struct sockaddr * if ((ia = (INA)ifa_ifwithdstaddr((SA)&input_ipaddr)) == 0) ia = (INA)ifa_ifwithnet((SA)&input_ipaddr); } else ia = ip_rtaddr(input_ipaddr.sin_addr); if (ia == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } ip->ip_dst = input_ipaddr.sin_addr; bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); /* * Let ip_intr's mcast routing check handle mcast pkts */ forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); break; case IPOPT_RR: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } /* * If no space remains, ignore. */ off--; /* 0 origin */ if (off > optlen - sizeof(struct in_addr)) break; bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&input_ipaddr.sin_addr, sizeof(input_ipaddr.sin_addr)); /* * locate outgoing interface; if we're the destination, * use the incoming interface (should be same). */ if ((ia = (INA)ifa_ifwithaddr((SA)&input_ipaddr)) == 0 && (ia = ip_rtaddr(input_ipaddr.sin_addr)) == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_HOST; goto bad; } bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); break; case IPOPT_TS: code = cp - (u_char *)ip; ipt = (struct ip_timestamp *)cp; if (ipt->ipt_len < 5) goto bad; if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { if (++ipt->ipt_oflw == 0) goto bad; break; } sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); switch (ipt->ipt_flg) { case IPOPT_TS_TSONLY: break; case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; input_ipaddr.sin_addr = dst; ia = (INA)ifaof_ifpforaddr((SA)&input_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); break; case IPOPT_TS_PRESPEC: if (ipt->ipt_ptr + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; bcopy((caddr_t)sin, (caddr_t)&input_ipaddr.sin_addr, sizeof(struct in_addr)); if (ifa_ifwithaddr((SA)&input_ipaddr) == 0) continue; ipt->ipt_ptr += sizeof(struct in_addr); break; default: goto bad; } ntime = iptime(); bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, sizeof(n_time)); ipt->ipt_ptr += sizeof(n_time); } } if (forward) { ip_forward(m, 1); return (1); } return (0);bad: ip->ip_len -= ip->ip_hl << 2; /* XXX icmp_error adds in hdr length */ if (_icmpErrorHook != NULL) (*_icmpErrorHook) (m, type, code, 0, 0); #ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_EVENT_2 (NET_CORE_EVENT, WV_NET_CRITICAL, 18, 9, WV_NETEVENT_IPIN_BADOPT, WV_NET_RECV, type, code)#endif /* INCLUDE_WVNET */#endif#ifdef VIRTUAL_STACK _ipstat.ips_badoptions++;#else ipstat.ips_badoptions++;#endif /* VIRTUAL_STACK */ return (1);}/* * Given address of next destination (final or next hop), * return internet address info of interface to be used to get there. */struct in_ifaddr *ip_rtaddr(dst) struct in_addr dst;{ register struct sockaddr_in *sin; sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; if (ipforward_rt.ro_rt == 0 || (ipforward_rt.ro_rt->rt_flags & RTF_UP) == 0 || dst.s_addr != sin->sin_addr.s_addr) { if (ipforward_rt.ro_rt) { RTFREE(ipforward_rt.ro_rt); ipforward_rt.ro_rt = 0; } sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_addr = dst; ipforward_rt.ro_rt = rtalloc2 (&ipforward_rt.ro_dst); } if (ipforward_rt.ro_rt == 0) return ((struct in_ifaddr *)0); return ((struct in_ifaddr *) ipforward_rt.ro_rt->rt_ifa);}#ifdef SRCRT/* * Save incoming source route for use in replies, * to be picked up later by ip_srcroute if the receiver is interested. */voidsave_rte(option, dst) u_char *option; struct in_addr dst;{ unsigned olen; olen = option[IPOPT_OLEN];#ifdef DIAGNOSTIC if (ipprintfs) printf("save_rte: olen %d\n", olen);#endif if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) return; bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen); ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); ip_srcrt.dst = dst;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -