void ip_frag_timer (void) { T_NET_BUF *frag; int_t ix; syscall(wai_sem(SEM_IP4_FRAG_QUEUE)); for (ix = NUM_IP4_FRAG_QUEUE; ix -- > 0; ) { frag = ip_frag_queue[ix]; if (frag != NULL && GET_QIP4_HDR(frag)->ttl > 0 && -- GET_QIP4_HDR(frag)->ttl == 0) { NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_TMOUT], 1); NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_DROP], 1); ip_freef(ix); } } syscall(sig_sem(SEM_IP4_FRAG_QUEUE)); }
/* * IP timer processing; * if a timer expires on a reassembly * queue, discard it. */ void ip_slowtimo(void) { struct ipq *fp; DEBUG_CALL("ip_slowtimo"); fp = (struct ipq *) ipq.next; if (fp == 0) return; while (fp != &ipq) { --fp->ipq_ttl; fp = (struct ipq *) fp->next; if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { ipstat.ips_fragtimeout++; ip_freef((struct ipq *) fp->prev); } } }
static T_NET_BUF * ip_reass (T_IP4_HDR *ip4h, T_NET_BUF *input) { T_NET_BUF *frag, *prev; T_IN4_ADDR dst, src; int_t ix; uint_t id, off, len; NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_FRAGS], 1); NET_COUNT_MIB(ip_stats.ipReasmReqds, 1); src = ntohl(ip4h->src); dst = ntohl(ip4h->dst); NTOHS(ip4h->id); NTOHS(ip4h->flg_off); id = ip4h->id; ix = id % NUM_IP4_FRAG_QUEUE; syscall(wai_sem(SEM_IP4_FRAG_QUEUE)); /* * ID、IPアドレス、上位プロトコルが異なるフラグメントがキューに有れば破棄する。 */ frag = ip_frag_queue[ix]; if (frag != NULL && (id != GET_IP4_HDR(frag)->id || dst != frag_dst[ix] || src != ntohl(GET_IP4_HDR(frag)->src) || ip4h->proto != GET_IP4_HDR(frag)->proto)) { NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_DROP], 1); NET_COUNT_MIB(ip_stats.ipReasmFails, 1); ip_freef(ix); } frag = ip_frag_queue[ix]; if (frag == NULL) { NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN], 1); /* 新規の ID なら、宛先アドレスを保存して、キューにつなぐ。*/ frag_dst [ix] = dst; ip_frag_queue[ix] = input; ((T_QIP4_HDR *)ip4h)->next = NULL; input = NULL; /* 再構成タイムアウトを設定する。*/ ip4h->ttl = IP4_FRAGTTL; } else { /* 正しい位置に挿入する。*/ prev = NULL; while (frag != NULL && IP4_FLGOFF_OFF(ip4h->flg_off) > IP4_FLGOFF_OFF(GET_QIP4_HDR(frag)->flg_off)) { prev = frag; frag = GET_QIP4_HDR(frag)->next; } ((T_QIP4_HDR *)ip4h)->next = frag; if (prev == NULL) { ip4h->ttl = GET_QIP4_HDR(frag)->ttl; ip_frag_queue[ix] = input; } else GET_QIP4_HDR(prev)->next = input; input = NULL; /* 全てのフラグメントが揃っているか調べる。*/ off = 0; for (frag = ip_frag_queue[ix]; frag != NULL; frag = GET_QIP4_HDR(frag)->next) { if ((IP4_FLGOFF_OFF(GET_QIP4_HDR(frag)->flg_off) << 3) != off) { /* 途中が抜けていたら終了する。*/ syscall(sig_sem(SEM_IP4_FRAG_QUEUE)); return NULL; } off += ntohs(GET_QIP4_HDR(frag)->len) - (IP4_VHL_HL(GET_QIP4_HDR(frag)->vhl) << 2); prev = frag; } /* 全てのフラグメントが揃ったら再構成する。*/ if ((GET_QIP4_HDR(prev)->flg_off & IP4_MF) == 0) { /* ネットワークバッファを獲得する。*/ if (tget_net_buf(&input, IF_IP4_HDR_SIZE + off, TMO_IP4_FRAG_GET_NET_BUF) == E_OK) { NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_OK], 1); NET_COUNT_MIB(ip_stats.ipReasmOKs, 1); /* IPv4 ヘッダを設定する。*/ frag = ip_frag_queue[ix]; ip4h = GET_IP4_HDR(input); *ip4h = *GET_IP4_HDR(frag); ip4h->dst = htonl(frag_dst[ix]); ip4h->len = htons(IP4_HDR_SIZE + off); ip4h->vhl = IP4_MAKE_VHL(IPV4_VERSION, IP4_HDR_SIZE >> 2); ip4h->ttl = GET_QIP4_HDR(prev)->ttl; ip4h->flg_off = ip4h->id = 0; /* データグラムを再構成する。*/ off = IP4_HDR_SIZE; while (frag != NULL) { len = ntohs(GET_QIP4_HDR(frag)->len) - (IP4_VHL_HL(GET_QIP4_HDR(frag)->vhl) << 2); memcpy((uint8_t *)ip4h + off, GET_QIP4_SDU(frag), len); off += len; frag = GET_QIP4_HDR(frag)->next; } } else { NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_NO_BUF], 1); NET_COUNT_IP4(net_count_ip4[NC_IP4_FRAG_IN_DROP], 1); NET_COUNT_MIB(ip_stats.ipReasmFails, 1); } /* キューを空にする。*/ ip_freef(ix); }
/* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */ void ip_input(struct mbuf *m) { Slirp *slirp = m->slirp; struct ip *ip; int hlen; DEBUG_CALL("ip_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m_len = %d", m->m_len); if (m->m_len < sizeof (struct ip)) { return; } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { goto bad; } hlen = ip->ip_hl << 2; if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */ goto bad; /* or packet too short */ } /* keep ip header intact for ICMP reply * ip->ip_sum = cksum(m, hlen); * if (ip->ip_sum) { */ if(cksum(m,hlen)) { goto bad; } /* * Convert fields to host representation. */ NTOHS(ip->ip_len); if (ip->ip_len < hlen) { goto bad; } NTOHS(ip->ip_id); NTOHS(ip->ip_off); /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_len < ip->ip_len) { goto bad; } if (slirp->restricted) { if ((ip->ip_dst.s_addr & slirp->vnetwork_mask.s_addr) == slirp->vnetwork_addr.s_addr) { if (ip->ip_dst.s_addr == 0xffffffff && ip->ip_p != IPPROTO_UDP) goto bad; } else { uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr; struct ex_list *ex_ptr; if ((ip->ip_dst.s_addr & inv_mask) == inv_mask) { goto bad; } for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) if (ex_ptr->ex_addr.s_addr == ip->ip_dst.s_addr) break; if (!ex_ptr) goto bad; } } /* Should drop packet if mbuf too long? hmmm... */ if (m->m_len > ip->ip_len) m_adj(m, ip->ip_len - m->m_len); /* check ip_ttl for a correct ICMP reply */ if(ip->ip_ttl==0 || ip->ip_ttl==1) { icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); goto bad; } /* * If offset or IP_MF are set, must reassemble. * Otherwise, nothing need be done. * (We could look in the reassembly queue to see * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) * * XXX This should fail, don't fragment yet */ if (ip->ip_off &~ IP_DF) { struct ipq *fp; struct qlink *l; /* * Look for queue of fragments * of this datagram. */ for (l = slirp->ipq.ip_link.next; l != &slirp->ipq.ip_link; l = l->next) { fp = container_of(l, struct ipq, ip_link); if (ip->ip_id == fp->ipq_id && ip->ip_src.s_addr == fp->ipq_src.s_addr && ip->ip_dst.s_addr == fp->ipq_dst.s_addr && ip->ip_p == fp->ipq_p) goto found; } fp = NULL; 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; if (ip->ip_off & IP_MF) ip->ip_tos |= 1; else ip->ip_tos &= ~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 (ip->ip_tos & 1 || ip->ip_off) { ip = ip_reass(slirp, ip, fp); if (ip == NULL) return; m = dtom(slirp, ip); } else if (fp) ip_freef(slirp, fp); } else
/* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */ void ipintr() { register struct ip *ip; register struct mbuf *m; register struct ipq *fp; register struct in_ifaddr *ia; int hlen, s; next: /* * Get next datagram off input queue and get IP header * in first mbuf. */ s = splimp(); IF_DEQUEUE(&ipintrq, m); splx(s); if (m == 0) return; #ifdef DIAGNOSTIC if ((m->m_flags & M_PKTHDR) == 0) panic("ipintr no HDR"); #endif /* * If no IP addresses have been set yet but the interfaces * are receiving, can't do anything with incoming packets yet. */ if (in_ifaddr == NULL) goto bad; ipstat.ips_total++; if (m->m_len < sizeof (struct ip) && (m = m_pullup(m, sizeof (struct ip))) == 0) { ipstat.ips_toosmall++; goto next; } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { ipstat.ips_badvers++; goto bad; } hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) { /* minimum header length */ ipstat.ips_badhlen++; goto bad; } if (hlen > m->m_len) { if ((m = m_pullup(m, hlen)) == 0) { ipstat.ips_badhlen++; goto next; } ip = mtod(m, struct ip *); } ip->ip_sum = in_cksum(m, hlen); if (ip->ip_sum) { ipstat.ips_badsum++; goto bad; } /* * Convert fields to host representation. */ NTOHS(ip->ip_len); if (ip->ip_len < hlen) { ipstat.ips_badlen++; goto bad; } NTOHS(ip->ip_id); NTOHS(ip->ip_off); /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_pkthdr.len < ip->ip_len) { ipstat.ips_tooshort++; goto bad; } if (m->m_pkthdr.len > ip->ip_len) { if (m->m_len == m->m_pkthdr.len) { m->m_len = ip->ip_len; m->m_pkthdr.len = ip->ip_len; } else m_adj(m, ip->ip_len - m->m_pkthdr.len); } /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ ip_nhops = 0; /* for source routed packets */ if (hlen > sizeof (struct ip) && ip_dooptions(m)) goto next; /* * Check our list of addresses, to see if the packet is for us. */ for (ia = in_ifaddr; ia; ia = ia->ia_next) { #define satosin(sa) ((struct sockaddr_in *)(sa)) if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) goto ours; if ( #ifdef DIRECTED_BROADCAST ia->ia_ifp == m->m_pkthdr.rcvif && #endif (ia->ia_ifp->if_flags & IFF_BROADCAST)) { u_long t; if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == ip->ip_dst.s_addr) goto ours; if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) goto ours; /* * Look for all-0's host part (old broadcast addr), * either for subnet or net. */ t = ntohl(ip->ip_dst.s_addr); if (t == ia->ia_subnet) goto ours; if (t == ia->ia_net) goto ours; } } if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { struct in_multi *inm; #ifdef MROUTING extern struct socket *ip_mrouter; if (ip_mrouter) { /* * If we are acting as a multicast router, all * incoming multicast packets are passed to the * kernel-level multicast forwarding function. * The packet is returned (relatively) intact; if * ip_mforward() returns a non-zero value, the packet * must be discarded, else it may be accepted below. * * (The IP ident field is put in the same byte order * as expected when ip_mforward() is called from * ip_output().) */ ip->ip_id = htons(ip->ip_id); if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) { ipstat.ips_cantforward++; m_freem(m); goto next; } ip->ip_id = ntohs(ip->ip_id); /* * The process-level routing demon needs to receive * all multicast IGMP packets, whether or not this * host belongs to their destination groups. */ if (ip->ip_p == IPPROTO_IGMP) goto ours; ipstat.ips_forward++; } #endif /* * See if we belong to the destination multicast group on the * arrival interface. */ IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm); if (inm == NULL) { ipstat.ips_cantforward++; m_freem(m); goto next; } goto ours; } if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) goto ours; if (ip->ip_dst.s_addr == INADDR_ANY) goto ours; /* * Not for us; forward if possible and desirable. */ if (ipforwarding == 0) { ipstat.ips_cantforward++; m_freem(m); } else ip_forward(m, 0); goto next; ours: /* * If offset or IP_MF are set, must reassemble. * Otherwise, nothing need be done. * (We could look in the reassembly queue to see * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) */ if (ip->ip_off &~ IP_DF) { if (m->m_flags & M_EXT) { /* XXX */ if ((m = m_pullup(m, sizeof (struct ip))) == 0) { ipstat.ips_toosmall++; goto next; } ip = mtod(m, struct ip *); } /* * Look for queue of fragments * of this datagram. */ for (fp = ipq.next; fp != &ipq; fp = fp->next) if (ip->ip_id == fp->ipq_id && ip->ip_src.s_addr == fp->ipq_src.s_addr && ip->ip_dst.s_addr == fp->ipq_dst.s_addr && ip->ip_p == fp->ipq_p) goto found; fp = 0; 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); if (ip == 0) goto next; ipstat.ips_reassembled++; m = dtom(ip); } else if (fp) ip_freef(fp); } else
/* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */ void ip_input(struct mbuf *m) { register struct ip *ip; int hlen; DEBUG_CALL("ip_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m_len = %d", m->m_len); STAT(ipstat.ips_total++); if (m->m_len < (int)sizeof (struct ip)) { STAT(ipstat.ips_toosmall++); return; } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { STAT(ipstat.ips_badvers++); goto bad; } hlen = ip->ip_hl << 2; if (hlen < (int)sizeof(struct ip ) || hlen>m->m_len) {/* min header length */ STAT(ipstat.ips_badhlen++); /* or packet too short */ goto bad; } /* keep ip header intact for ICMP reply * ip->ip_sum = cksum(m, hlen); * if (ip->ip_sum) { */ if(cksum(m,hlen)) { STAT(ipstat.ips_badsum++); goto bad; } /* * Convert fields to host representation. */ NTOHS(ip->ip_len); if (ip->ip_len < hlen) { STAT(ipstat.ips_badlen++); goto bad; } NTOHS(ip->ip_id); NTOHS(ip->ip_off); /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_len < ip->ip_len) { STAT(ipstat.ips_tooshort++); goto bad; } if (slirp_restrict) { if (ip_geth(ip->ip_dst) != special_addr_ip) { if (ip_getn(ip->ip_dst) == 0xffffffffu && ip->ip_p != IPPROTO_UDP) goto bad; } else { int host = ip_geth(ip->ip_dst) & 0xff; struct ex_list *ex_ptr; if (host == 0xff) goto bad; for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) if (ex_ptr->ex_addr == host) break; if (!ex_ptr) goto bad; } } /* Should drop packet if mbuf too long? hmmm... */ if (m->m_len > ip->ip_len) m_adj(m, ip->ip_len - m->m_len); /* check ip_ttl for a correct ICMP reply */ if(ip->ip_ttl==0 || ip->ip_ttl==1) { icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); goto bad; } /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ /* We do no IP options */ /* if (hlen > sizeof (struct ip) && ip_dooptions(m)) * goto next; */ /* * If offset or IP_MF are set, must reassemble. * Otherwise, nothing need be done. * (We could look in the reassembly queue to see * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) * * XXX This should fail, don't fragment yet */ if (ip->ip_off &~ IP_DF) { register struct ipq *fp; struct qlink *l; /* * Look for queue of fragments * of this datagram. */ for (l = ipq.ip_link.next; l != &ipq.ip_link; l = l->next) { fp = container_of(l, struct ipq, ip_link); if (ip->ip_id == fp->ipq_id && ip_equal(ip->ip_src, fp->ipq_src) && ip_equal(ip->ip_dst, fp->ipq_dst) && ip->ip_p == fp->ipq_p) goto found; } fp = NULL; 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; if (ip->ip_off & IP_MF) ip->ip_tos |= 1; else ip->ip_tos &= ~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 (ip->ip_tos & 1 || ip->ip_off) { STAT(ipstat.ips_fragments++); ip = ip_reass(ip, fp); if (ip == NULL) return; STAT(ipstat.ips_reassembled++); m = dtom(ip); } else if (fp) ip_freef(fp); } else
/* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassemble. Process options. Pass to next level. */ void ip_input(struct mbuf *m) { struct ip *ip; int hlen; DEBUG_CALL("ip_input"); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m_len = %d", m->m_len); ipstat.ips_total++; if (m->m_len < sizeof (struct ip)) { ipstat.ips_toosmall++; return; } ip = mtod(m, struct ip *); if (ip->ip_v != IPVERSION) { ipstat.ips_badvers++; goto bad; } hlen = ip->ip_hl << 2; if (hlen<sizeof(struct ip ) || hlen>m->m_len) {/* min header length */ ipstat.ips_badhlen++; /* or packet too short */ goto bad; } /* keep ip header intact for ICMP reply * ip->ip_sum = cksum(m, hlen); * if (ip->ip_sum) { */ if(cksum(m,hlen)) { ipstat.ips_badsum++; goto bad; } /* * Convert fields to host representation. */ NTOHS(ip->ip_len); if (ip->ip_len < hlen) { ipstat.ips_badlen++; goto bad; } NTOHS(ip->ip_id); NTOHS(ip->ip_off); /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_len < ip->ip_len) { ipstat.ips_tooshort++; goto bad; } /* Should drop packet if mbuf too long? hmmm... */ if (m->m_len > ip->ip_len) m_adj(m, ip->ip_len - m->m_len); /* check ip_ttl for a correct ICMP reply */ if(ip->ip_ttl==0 || ip->ip_ttl==1) { icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); goto bad; } /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ /* We do no IP options */ /* if (hlen > sizeof (struct ip) && ip_dooptions(m)) * goto next; */ /* * If offset or IP_MF are set, must reassemble. * Otherwise, nothing need be done. * (We could look in the reassembly queue to see * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) * * XXX This should fail, don't fragment yet */ if (ip->ip_off &~ IP_DF) { register struct ipq *fp; /* * Look for queue of fragments * of this datagram. */ for (fp = (struct ipq *) ipq.next; fp != &ipq; fp = (struct ipq *) fp->next) if (ip->ip_id == fp->ipq_id && ip->ip_src.s_addr == fp->ipq_src.s_addr && ip->ip_dst.s_addr == fp->ipq_dst.s_addr && ip->ip_p == fp->ipq_p) goto found; fp = 0; 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; if (ip->ip_off & IP_MF) ((struct ipasfrag *)ip)->ipf_mff |= 1; else ((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); if (ip == 0) return; ipstat.ips_reassembled++; m = dtom(ip); } else if (fp) ip_freef(fp); } else ip->ip_len -= hlen; /* * Switch out to protocol's input routine. */ ipstat.ips_delivered++; switch (ip->ip_p) { case IPPROTO_TCP: tcp_input(m, hlen, (struct socket *)NULL); break; case IPPROTO_UDP: udp_input(m, hlen); break; case IPPROTO_ICMP: icmp_input(m, hlen); break; default: ipstat.ips_noproto++; m_free(m); } return; bad: m_freem(m); return; }
/* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassamble. If complete and fragment queue exists, discard. * Process options. Pass to next level. */ ipintr() { register struct ip *ip; register struct mbuf *m; struct mbuf *m0; register int i; register struct ipq *fp; register struct in_ifaddr *ia; struct ifnet *ifp; int hlen, s; /* IOdebug( "ipintr: called" ); */ next: /* * Get next datagram off input queue and get IP header * in first mbuf. */ s = splimp(); IF_DEQUEUEIF(&ipintrq, m, ifp); splx(s); if (m == NULL) { /* IOdebug( "ipintr: no more mbufs" ); */ return; } /* * If no IP addresses have been set yet but the interfaces * are receiving, can't do anything with incoming packets yet. */ if (in_ifaddr == NULL) goto bad; ipstat.ips_total++; if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && (m = m_pullup(m, sizeof (struct ip))) == 0) { ipstat.ips_toosmall++; goto next; } ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) { /* minimum header length */ ipstat.ips_badhlen++; goto bad; } if (hlen > m->m_len) { if ((m = m_pullup(m, hlen)) == 0) { ipstat.ips_badhlen++; goto next; } ip = mtod(m, struct ip *); } if (ipcksum) if (ip->ip_sum = in_cksum(m, hlen)) { ipstat.ips_badsum++; /* IOdebug( "ipintr: bad checksum" ); */ goto bad; } /* * Convert fields to host representation. */ ip->ip_len = ntohs((u_short)ip->ip_len); if (ip->ip_len < hlen) { ipstat.ips_badlen++; goto bad; } ip->ip_id = ntohs(ip->ip_id); ip->ip_off = ntohs((u_short)ip->ip_off); /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ i = -(u_short)ip->ip_len; m0 = m; for (;;) { i += m->m_len; if (m->m_next == 0) break; m = m->m_next; } if (i != 0) { if (i < 0) { ipstat.ips_tooshort++; m = m0; goto bad; } if (i <= m->m_len) m->m_len -= i; else m_adj(m0, -i); } m = m0; /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ ip_nhops = 0; /* for source routed packets */ if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp)) goto next; /* * Check our list of addresses, to see if the packet is for us. */ /* IOdebug( "ipintr: checking address" ); */ for (ia = in_ifaddr; ia; ia = ia->ia_next) { #define satosin(sa) ((struct sockaddr_in *)(sa)) if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) goto ours; if ( #ifdef DIRECTED_BROADCAST ia->ia_ifp == ifp && #endif (ia->ia_ifp->if_flags & IFF_BROADCAST)) { u_long t; if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == ip->ip_dst.s_addr) goto ours; if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) goto ours; /* * Look for all-0's host part (old broadcast addr), * either for subnet or net. */ t = ntohl(ip->ip_dst.s_addr); if (t == ia->ia_subnet) goto ours; if (t == ia->ia_net) goto ours; } } if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) goto ours; if (ip->ip_dst.s_addr == INADDR_ANY) goto ours; /* * Not for us; forward if possible and desirable. */ ip_forward(ip, ifp); /* IOdebug( "ipintr: not for us" ); */ goto next; ours: /* IOdebug( "ipintr: ours" ); */ /* * If offset or IP_MF are set, must reassemble. * Otherwise, nothing need be done. * (We could look in the reassembly queue to see * if the packet was previously fragmented, * but it's not worth the time; just let them time out.) */ if (ip->ip_off &~ IP_DF) { /* * Look for queue of fragments * of this datagram. */ for (fp = ipq.next; fp != &ipq; fp = fp->next) if (ip->ip_id == fp->ipq_id && ip->ip_src.s_addr == fp->ipq_src.s_addr && ip->ip_dst.s_addr == fp->ipq_dst.s_addr && ip->ip_p == fp->ipq_p) goto found; fp = 0; 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 = 0; 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 || ip->ip_off) { /* IOdebug( "ipintr: attempting reassembly" ); */ ipstat.ips_fragments++; ip = ip_reass((struct ipasfrag *)ip, fp); if (ip == NULL) { /* IOdebug( "ipintr: attempt failed" ); */ goto next; } m = dtom(ip); } else if (fp) ip_freef(fp); } else ip->ip_len -= hlen; /* * Switch out to protocol's input routine. */ /* IOdebug( "ipintr: handling packet of len %d", ip->ip_len ); */ (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp); /* IOdebug( "ipintr: handled" ); */ goto next; bad: /* IOdebug( "ipintr: bad input" ); */ m_freem(m); goto next; }