📄 ip_input.c
字号:
* set ip_mff if more fragments are expected, * convert offset of this to bytes. */ ip->ip_len -= hlen; ((struct ipasfrag *)ip)->ipf_mff &= ~1; if (ip->ip_off & IP_MF) ((struct ipasfrag *)ip)->ipf_mff |= 1; ip->ip_off <<= 3; /* * If datagram marked as having more fragments * or if this is not the first fragment, * attempt reassembly; if it succeeds, proceed. */ if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { ipstat.ips_fragments++; if ((m = ipReAssemble (m, fp)) == NULL) goto next; ipstat.ips_reassembled++; } else if (fp) ip_freef(fp); } else ip->ip_len -= hlen;#ifdef FORWARD_BROADCASTS if ((m->m_flags & M_BCAST) && (proxyBroadcastHook != NULL)) (* proxyBroadcastHook) (m, m->m_pkthdr.rcvif);#endif /* * Switch out to protocol's input routine. */ ipstat.ips_delivered++; (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); goto next;bad: m_freem(m); goto next;}/********************************************************************************* ipReAssemble - reassemble ip fragments** This function reassembles the ip fragments and returns the pointer to the* mbuf chain if reassembly is complete orelse returns null.** RETURNS: pMbuf/NULL** SEE ALSO: ,** NOMANUAL*/LOCAL struct mbuf * ipReAssemble ( FAST struct mbuf * pMbuf, /* pointer to mbuf chain fragment */ FAST struct ipq * pIpFragQueue /* pointer to ip fragment queue */ ) { FAST struct mbuf ** pPtrMbuf; /* pointer to ptr to mbuf */ FAST struct mbuf * pMbPktFrag = NULL; /* pointer to the packet */ FAST struct ip * pIpHdr; /* pointer to ip header */ FAST struct ipasfrag * pIpHdrFrag; /* ipfragment header */ FAST int len; FAST struct mbuf * pMbufTmp; /* pointer to mbuf */ pIpHdr = mtod (pMbuf, struct ip *); pMbuf->m_nextpkt = NULL; /* * If first fragment to arrive, create a reassembly queue. */ if (pIpFragQueue == 0) { if ((pMbufTmp = mBufClGet (M_DONTWAIT, MT_FTABLE, sizeof(struct ipq), TRUE)) == NULL) goto dropFrag; pIpFragQueue = mtod(pMbufTmp, struct ipq *); insque(pIpFragQueue, &ipq); pIpFragQueue->ipq_ttl = ipfragttl; /* configuration parameter */ pIpFragQueue->ipq_p = pIpHdr->ip_p; pIpFragQueue->ipq_id = pIpHdr->ip_id; pIpFragQueue->ipq_src = ((struct ip *)pIpHdr)->ip_src; pIpFragQueue->ipq_dst = ((struct ip *)pIpHdr)->ip_dst; pIpFragQueue->pMbufHdr = pMbufTmp; /* back pointer to mbuf */ pIpFragQueue->pMbufPkt = pMbuf; /* first fragment received */ goto ipChkReAssembly; } for (pPtrMbuf = &(pIpFragQueue->pMbufPkt); *pPtrMbuf != NULL; pPtrMbuf = &(*pPtrMbuf)->m_nextpkt) { pMbPktFrag = *pPtrMbuf; pIpHdrFrag = mtod(pMbPktFrag, struct ipasfrag *); if ((USHORT)pIpHdr->ip_off > (USHORT)pIpHdrFrag->ip_off) { if ((len = (signed int)((USHORT)pIpHdrFrag->ip_off + pIpHdrFrag->ip_len - (USHORT)pIpHdr->ip_off)) > 0) { if (len >= pIpHdr->ip_len) goto dropFrag; /* drop the fragment */ pIpHdrFrag->ip_len -= len; m_adj(pMbPktFrag, -len); /* trim from the tail */ } if (pMbPktFrag->m_nextpkt == NULL) { /* this is the likely case most of the time */ pMbPktFrag->m_nextpkt = pMbuf; /* insert the fragment */ pMbuf->m_nextpkt = NULL; break; } } else /* if pIpHdr->ip_off <= pIpHdrFrag->ip_off */ { /* if complete overlap */ while (((USHORT)pIpHdr->ip_off + pIpHdr->ip_len) >= ((USHORT)pIpHdrFrag->ip_off + pIpHdrFrag->ip_len)) { *pPtrMbuf = (*pPtrMbuf)->m_nextpkt; pMbPktFrag->m_nextpkt = NULL; m_freem (pMbPktFrag); /* drop the fragment */ pMbPktFrag = *pPtrMbuf; if (pMbPktFrag == NULL) break; pIpHdrFrag = mtod(pMbPktFrag, struct ipasfrag *); } /* if partial overlap trim my data at the end*/ if ((pMbPktFrag != NULL) && ((len = (((USHORT)pIpHdr->ip_off + pIpHdr->ip_len) - pIpHdrFrag->ip_off)) > 0)) { pIpHdr->ip_len -= len; m_adj (pMbuf, -len); /* trim from the tail */ } pMbuf->m_nextpkt = pMbPktFrag; *pPtrMbuf = pMbuf; /* insert the current fragment */ break; } } ipChkReAssembly: len = 0; for (pMbPktFrag = pIpFragQueue->pMbufPkt; pMbPktFrag != NULL; pMbPktFrag = pMbPktFrag->m_nextpkt) { pIpHdrFrag = mtod(pMbPktFrag, struct ipasfrag *); if ((USHORT)pIpHdrFrag->ip_off != len) return (NULL); len += pIpHdrFrag->ip_len; } if (pIpHdrFrag->ipf_mff & 1) /* last fragment's mff bit still set */ return (NULL); /* reassemble and concatenate all fragments */ pMbuf = pIpFragQueue->pMbufPkt; pMbufTmp = pMbuf->m_nextpkt; pMbuf->m_nextpkt = NULL; while (pMbufTmp != NULL) { pMbPktFrag = pMbufTmp; pIpHdrFrag = mtod(pMbPktFrag, struct ipasfrag *); pMbPktFrag->m_data += pIpHdrFrag->ip_hl << 2; /* remove the header */ pMbPktFrag->m_len -= pIpHdrFrag->ip_hl << 2; 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 */ 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: ipstat.ips_fragdropped++; 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; /* 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(); fp = ipq.next; if (fp == 0) { splx(s); return; } while (fp != &ipq) { --fp->ipq_ttl; fp = fp->next; if (fp->prev->ipq_ttl == 0) { ipstat.ips_fragtimeout++; ip_freef(fp->prev); } } splx(s); return;}/* * Drain off all datagram fragments. */voidip_drain(){ while (ipq.next != &ipq) { ipstat.ips_fragdropped++; ip_freef(ipq.next); } 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; } ipaddr.sin_addr = ip->ip_dst; TOS_SET (&ipaddr, ip->ip_tos); /* tos routing */ ia = (struct in_ifaddr *) ifa_ifwithaddr((struct sockaddr *)&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. */ save_rte(cp, ip->ip_src); break; } /* * locate outgoing interface */ bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); if (opt == IPOPT_SSRR) {#define INA struct in_ifaddr *#define SA struct sockaddr * if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) ia = (INA)ifa_ifwithnet((SA)&ipaddr); } else ia = ip_rtaddr(ipaddr.sin_addr); if (ia == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } ip->ip_dst = 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)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); /* * locate outgoing interface; if we're the destination, * use the incoming interface (should be same). */ if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && (ia = ip_rtaddr(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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -