📄 ip_input.c
字号:
(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp); goto next;bad: m_freem(m); goto next;}/* * 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. */struct ip *ip_reass(ip, fp) register struct ipasfrag *ip; register struct ipq *fp;{ register struct mbuf *m = dtom(ip), *mm; register struct ipasfrag *q; int hlen = ip->ip_hl << 2; int i, next; /* * Presence of header sizes in mbufs * would confuse code below. */ m->m_off += hlen; m->m_len -= hlen; /* * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { KM_ALLOC(fp, struct ipq *, sizeof(struct ipq),KM_FTABLE, KM_NOWAIT); if(fp == NULL) goto dropfrag; insque(fp, &ipq); 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; q = (struct ipasfrag *)fp; goto insert; } /* * Find a segment which begins after this one does. */ /* * This is a cheap append if everything is all set */ if(fp->ipq_prev->ip_off + fp->ipq_prev->ip_len == ip->ip_off) { q = (struct ipasfrag *)fp; goto insert; } 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) { 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; } q = q->ipf_next; m_freem(dtom(q->ipf_prev)); ip_deq(q->ipf_prev); }insert: /* * 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) { return (0); } /* * Reassembly is complete; concatenate fragments. */ q = fp->ipq_next; m = dtom(q); mm = m->m_next; m->m_next = 0; m_cat(m, mm); q = q->ipf_next; while (q != (struct ipasfrag *)fp) { mm = dtom(q); q = q->ipf_next; m_cat(m, mm); } /* * 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; ((struct ip *)ip)->ip_src = fp->ipq_src; ((struct ip *)ip)->ip_dst = fp->ipq_dst; remque(fp); KM_FREE(fp, KM_FTABLE); m = dtom(ip); m->m_len += (ip->ip_hl << 2); m->m_off -= (ip->ip_hl << 2); return ((struct ip *)ip);dropfrag: IPSTAT(ips_fragdropped++); m_freem(m); return (0);}/* * Free a fragment reassembly header and all * associated datagrams. *//* 12.9.88.us Enter with lk_ipq set. */ ip_freef(fp) struct ipq *fp;{ register struct ipasfrag *q, *p; if (smp_debug){ if (smp_owner(&lk_ipq) == 0) panic("ip_freef not lock owner"); } for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { p = q->ipf_next; ip_deq(q); m_freem(dtom(q)); } remque(fp); KM_FREE(fp, KM_FTABLE);}/* * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. *//* 12.9.88.us Enter with lk_ipq set. */ ip_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. *//* 12.9.88.us Enter with lk_ipq set. */ ip_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. */ip_slowtimo(){ register struct ipq *fp; int s = splnet(); /* 12.9.88.us. Bug fix - panicing from a null referenced pointer * from inadequate locking on lk_ipq. Note that all fixes on * 12.9.88 are to fix this panic. */ smp_lock(&lk_ipq, LK_RETRY); fp = ipq.next; if (fp == 0) { smp_unlock(&lk_ipq); 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); } } /* 12.8.88.us */ smp_unlock(&lk_ipq); splx(s);}/* * Drain off all datagram fragments. */ip_drain(){ /* 12.8.88.us */ smp_lock(&lk_ipq, LK_RETRY); while (ipq.next != &ipq) { IPSTAT(ips_fragdropped++); ip_freef(ipq.next); } /* 12.8.88.us */ smp_unlock(&lk_ipq);}extern struct in_ifaddr *ifptoia();struct in_ifaddr *ip_rtaddr();int icmp_badoptlen=0; /* debug only: count of bad optlens */int icmp_badlsrroffset=0; /* debug only: count of bad LSRR options *//* * Do option processing on a datagram, * possibly discarding it if bad options * are encountered. */ip_dooptions(ip, ifp) register struct ip *ip; struct ifnet *ifp;{ register u_char *cp; int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB; register struct ip_timestamp *ipt; register struct in_ifaddr *ia; struct in_addr *sin; n_time ntime; int s; 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; icmp_badoptlen++; m_freem(dtom(ip)); goto bad2; /* don't attempt reply pkt */ } } 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 on directly accessible net. */ case IPOPT_LSRR: case IPOPT_SSRR: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; icmp_badlsrroffset++; m_freem(dtom(ip)); goto bad2; /* don't attempt reply pkt */ }#ifdef mips bcopy(&ip->ip_dst, &ipaddr.sin_addr, sizeof(ip->ip_dst));#endif mips#ifdef vax ipaddr.sin_addr = ip->ip_dst;#endif vax 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 && in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) || (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; }#ifdef mips bcopy(&ipaddr.sin_addr, &ip->ip_dst, sizeof(ip->ip_dst));#endif mips#ifdef vax ip->ip_dst = ipaddr.sin_addr;#endif vax 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_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 ((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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -