📄 ip_input.c
字号:
for (i = 0; i < IPREASS_NHASH; i++) { if (ipq[i].prev != &ipq[i]) { ip_freef(ipq[i].prev); break; } } } else ip_freef(ipq[sum].prev); }found: /* * Adjust ip_len to not reflect header, * 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++; ip = ip_reass((struct ipasfrag *)ip, fp, &ipq[sum]); if (ip == 0) return; ipstat.ips_reassembled++; m = dtom(ip);#ifdef IPDIVERT if (frag_divert_port) { ip->ip_len += hlen; HTONS(ip->ip_len); HTONS(ip->ip_off); HTONS(ip->ip_id); ip->ip_sum = 0; ip->ip_sum = in_cksum_hdr(ip); NTOHS(ip->ip_id); NTOHS(ip->ip_off); NTOHS(ip->ip_len); ip->ip_len -= hlen; }#endif } else if (fp) ip_freef(fp); } else ip->ip_len -= hlen;#ifdef IPDIVERT /* * Divert reassembled packets to the divert protocol if required */ if (frag_divert_port) { ipstat.ips_delivered++; ip_divert_port = frag_divert_port; frag_divert_port = 0; (*inetsw[ip_protox[IPPROTO_DIVERT]].pr_input)(m, hlen); return; } /* Don't let packets divert themselves */ if (ip->ip_p == IPPROTO_DIVERT) { ipstat.ips_noproto++; goto bad; }#endif /* * Switch out to protocol's input routine. */ ipstat.ips_delivered++; (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen); return;bad: m_freem(m);}/* * IP software interrupt routine - to go away sometime soon */voidipintr(void){ int s; struct mbuf *m; while(1) { s = splimp(); IF_DEQUEUE(&ipintrq, m); splx(s); if (m == 0) return; ip_input(m); }}NETISR_SET(NETISR_IP, ipintr); /* * Take incoming datagram fragment and try to * reassemble it into whole datagram. If a chain for * reassembly of this datagram already exists, then it * is given as fp; otherwise have to make a chain. */static struct ip *ip_reass(ip, fp, where) register struct ipasfrag *ip; register struct ipq *fp; struct ipq *where;{ register struct mbuf *m = dtom(ip); register struct ipasfrag *q; struct mbuf *t; int hlen = ip->ip_hl << 2; int i, next; /* * Presence of header sizes in mbufs * would confuse code below. */ m->m_data += hlen; m->m_len -= hlen; /* * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); insque(fp, where); nipq++; fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; fp->ipq_id = ip->ip_id; 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;#ifdef IPDIVERT fp->ipq_divert = 0;#endif q = (struct ipasfrag *)fp; goto insert; } /* * Find a segment which begins after this one does. */ for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) if (q->ip_off > ip->ip_off) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ if (q->ipf_prev != (struct ipasfrag *)fp) { i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; if (i > 0) { if (i >= ip->ip_len) goto dropfrag; m_adj(dtom(ip), i); ip->ip_off += i; ip->ip_len -= i; } } /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { struct mbuf *m0; 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; } m0 = dtom(q); q = q->ipf_next; ip_deq(q->ipf_prev); m_freem(m0); }insert:#ifdef IPDIVERT /* * Any fragment diverting causes the whole packet to divert */ if (frag_divert_port != 0) fp->ipq_divert = frag_divert_port; frag_divert_port = 0;#endif /* * Stick new segment in its place; * check for complete reassembly. */ ip_enq(ip, q->ipf_prev); next = 0; for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { if (q->ip_off != next) return (0); next += q->ip_len; } if (q->ipf_prev->ipf_mff & 1) return (0); /* * Reassembly is complete. Make sure the packet is a sane size. */ if (next + (IP_VHL_HL(((struct ip *)fp->ipq_next)->ip_vhl) << 2) > IP_MAXPACKET) { ipstat.ips_toolong++; ip_freef(fp); return (0); } /* * Concatenate fragments. */ q = fp->ipq_next; m = dtom(q); t = m->m_next; m->m_next = 0; m_cat(m, t); q = q->ipf_next; while (q != (struct ipasfrag *)fp) { t = dtom(q); q = q->ipf_next; m_cat(m, t); }#ifdef IPDIVERT /* * Record divert port for packet, if any */ frag_divert_port = fp->ipq_divert;#endif /* * Create header for new ip packet by * modifying header of first packet; * dequeue and discard fragment reassembly header. * Make header visible. */ 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); nipq--; (void) m_free(dtom(fp)); m = dtom(ip); m->m_len += (ip->ip_hl << 2); m->m_data -= (ip->ip_hl << 2); /* some debugging cruft by sklower, below, will go away soon */ if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ register int plen = 0; for (t = m; m; m = m->m_next) plen += m->m_len; t->m_pkthdr.len = plen; } return ((struct ip *)ip);dropfrag: ipstat.ips_fragdropped++; m_freem(m); return (0);}/* * Free a fragment reassembly header and all * associated datagrams. */static voidip_freef(fp) struct ipq *fp;{ register struct ipasfrag *q, *p; for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { p = q->ipf_next; ip_deq(q); m_freem(dtom(q)); } remque(fp); (void) m_free(dtom(fp)); nipq--;}/* * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. */static voidip_enq(p, prev) register struct ipasfrag *p, *prev;{ p->ipf_prev = prev; p->ipf_next = prev->ipf_next; prev->ipf_next->ipf_prev = p; prev->ipf_next = p;}/* * To ip_enq as remque is to insque. */static voidip_deq(p) register struct ipasfrag *p;{ p->ipf_prev->ipf_next = p->ipf_next; p->ipf_next->ipf_prev = p->ipf_prev;}/* * IP timer processing; * if a timer expires on a reassembly * queue, discard it. */voidip_slowtimo(){ register struct ipq *fp; int s = splnet(); int i; for (i = 0; i < IPREASS_NHASH; i++) { fp = ipq[i].next; if (fp == 0) continue; while (fp != &ipq[i]) { --fp->ipq_ttl; fp = fp->next; if (fp->prev->ipq_ttl == 0) { ipstat.ips_fragtimeout++; ip_freef(fp->prev); } } } splx(s);}/* * Drain off all datagram fragments. */voidip_drain(){ int i; for (i = 0; i < IPREASS_NHASH; i++) { while (ipq[i].next != &ipq[i]) { ipstat.ips_fragdropped++; ip_freef(ipq[i].next); } } in_rtqdrain();}/* * 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. */static 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_VHL_HL(ip->ip_vhl) << 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; 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; } if (!ip_dosourceroute) goto nosourcerouting; /* * 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. */ if (!ip_acceptsourceroute) goto nosourcerouting; save_rte(cp, ip->ip_src); break; } if (!ip_dosourceroute) { char buf[4*sizeof "123"];nosourcerouting: strcpy(buf, inet_ntoa(ip->ip_dst)); log(LOG_WARNING, "attempted source route from %s to %s\n", inet_ntoa(ip->ip_src), buf); type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } /* * locate outgoing interface */ (void)memcpy(&ipaddr.sin_addr, cp + off, 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; (void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr), 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -