ip_input.c
来自「操作系统SunOS 4.1.3版本的源码」· C语言 代码 · 共 811 行 · 第 1/2 页
C
811 行
#ifdef DUMP_DEBUG1 dprint(dump_debug, 6, "ip_reass(1): q 0x%x m 0x%x t 0x%x\n", q, m, t);#endif /* DUMP_DEBUG */ m_cat(m, t); q = q->ipf_next; while (q != (struct ipasfrag *)fp) { t = dtom(q); q = q->ipf_next;#ifdef DUMP_DEBUG1 dprint(dump_debug, 6, "ip_reass(2): q 0x%x m 0x%x t 0x%x\n", q, m, t);#endif /* DUMP_DEBUG */ m_cat(m, t); }#ifdef DUMP_DEBUG1 dprint(dump_debug, 6, "ip_reass: mcat OK\n");#endif /* DUMP_DEBUG */ /* * 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); (void) m_free(dtom(fp)); m = dtom(ip); m->m_len += sizeof (struct ipasfrag); m->m_off -= sizeof (struct ipasfrag); return ((struct ip *)ip);dropfrag: m_freem(m); return (0);}/* * Free a fragment reassembly header and all * associated datagrams. */ip_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));}/* * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. */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. */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(); ip_reasstot = 0; fp = ipq.next; if (fp == 0) { (void) splx(s); return; } while (fp != &ipq) { ip_reasstot++; --fp->ipq_ttl; fp = fp->next; if (fp->prev->ipq_ttl == 0) ip_freef(fp->prev); } (void) splx(s);}/* * Drain off all datagram fragments. */ip_drain(){ while (ipq.next != &ipq) ip_freef(ipq.next);}/* * Do option processing on a datagram, * possibly discarding it if bad options * are encountered. */ip_dooptions(ip) struct ip *ip;{#ifdef NEVER register u_char *cp; int opt, optlen, cnt, code, type; struct in_addr *sin; register struct ip_timestamp *ipt; register struct ifnet *ifp; struct in_addr t;#endif NEVER#ifdef DUMP_DEBUG1 dprint(dump_debug, 0, "ip_dooptions(ip 0x%x)\n", ip);#endif /* DUMP_DEBUG */#ifdef NEVER cp = (u_char *)(ip + 1); cnt = (ip->ip_hl << 2) - sizeof (struct ip); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[0]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) optlen = 1; else optlen = cp[1]; 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 (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1)) break; sin = (struct in_addr *)(cp + cp[2]); 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; break; } t = ip->ip_dst; ip->ip_dst = *sin; *sin = t; cp[2] += 4; if (cp[2] > optlen - (sizeof (long) - 1)) break; ip->ip_dst = sin[1]; 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; if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { if (++ipt->ipt_oflw == 0) goto bad; break; } sin = (struct in_addr *)(cp+cp[2]); switch (ipt->ipt_flg) { case IPOPT_TS_TSONLY: break; case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr + 8 > ipt->ipt_len) goto bad; if (ifinet == 0) goto bad; /* ??? */ *sin++ = ((struct sockaddr_in *) &ifinet->if_addr)->sin_addr; break; case IPOPT_TS_PRESPEC: ipaddr.sin_addr = *sin; if (if_ifwithaddr((struct sockaddr *)&ipaddr) == 0) continue; if (ipt->ipt_ptr + 8 > ipt->ipt_len) goto bad; ipt->ipt_ptr += 4; break; default: goto bad; } *(n_time *)sin = iptime(); ipt->ipt_ptr += 4; } }#endif /* NEVER */ return (0);#ifdef NEVERbad: icmp_error(ip, type, code); return (1);#endif NEVER}#ifdef NEVER/* * Strip out IP options, at higher * level protocol in the kernel. * Second argument is buffer to which options * will be moved, and return value is their length. */ip_stripoptions(ip, mopt) struct ip *ip; struct mbuf *mopt;{ register int i; register struct mbuf *m; int olen; olen = (ip->ip_hl<<2) - sizeof (struct ip); m = dtom(ip); ip++; 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 -= olen;}u_char inetctlerrmap[PRC_NCMDS] = { ECONNABORTED, ECONNABORTED, 0, 0, 0, 0, EHOSTDOWN, EHOSTUNREACH, ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, EMSGSIZE, 0, 0, 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);}#endif /* NEVER */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;{#ifdef NEVER register int error, type, code; struct mbuf *mopt, *mcopy;#endif NEVER#ifdef DUMP_DEBUG1 dprint(dump_debug, 0, "ip_forward(ip 0x%x)\n", ip);#endif /* DUMP_DEBUG */#ifdef NEVER /* * don't forward broadcasts which escape from the net * for which they were destined -- happens with multiple * IP nets on one Ethernet */ if (in_netof(ip->ip_dst) == INADDR_ANY || (in_lnaof(ip->ip_dst) == INADDR_ANY && in_netof(ip->ip_dst) == in_netof(ip->ip_src))) { m_freem(dtom(ip)); return; } 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, MT_DATA); if (mopt == NULL) { 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); error = ip_output(dtom(ip), mopt, (struct route *)0, IP_FORWARDING); if (error == 0) { if (mcopy) m_freem(mcopy); return; } if (mcopy == NULL) 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: /* don't give error replies to broadcasts */ if (in_lnaof(ip->ip_dst) == INADDR_ANY) { m_freem(dtom(ip)); return; } icmp_error(ip, type, code);#endif /* NEVER */}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?