📄 ip_input.c
字号:
/* * Retrieve incoming source route for use in replies, * in the same form used by setsockopt. * The first hop is placed before the options, will be removed later. */struct mbuf *ip_srcroute(){ register struct in_addr *p, *q; register struct mbuf *m; if (ip_nhops == 0) return ((struct mbuf *)0); m= mBufClGet(M_DONTWAIT, MT_SOOPTS, CL_SIZE_128, TRUE); if (m == 0) return ((struct mbuf *)0);#define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + OPTSIZ;#ifdef DIAGNOSTIC if (ipprintfs) printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);#endif /* * First save first hop for return route */ p = &ip_srcrt.route[ip_nhops - 1]; *(mtod(m, struct in_addr *)) = *p--;#ifdef DIAGNOSTIC if (ipprintfs) printf(" hops %lx", ntohl(mtod(m, struct in_addr *)->s_addr));#endif /* * Copy option fields and padding (nop) to mbuf. */ ip_srcrt.nop = IPOPT_NOP; ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; bcopy((caddr_t)&ip_srcrt.nop, mtod(m, caddr_t) + sizeof(struct in_addr), OPTSIZ); q = (struct in_addr *)(mtod(m, caddr_t) + sizeof(struct in_addr) + OPTSIZ);#undef OPTSIZ /* * Record return path as an IP source route, * reversing the path (pointers are now aligned). */ while (p >= ip_srcrt.route) {#ifdef DIAGNOSTIC if (ipprintfs) printf(" %lx", ntohl(q->s_addr));#endif *q++ = *p--; } /* * Last hop goes to final destination. */ *q = ip_srcrt.dst;#ifdef DIAGNOSTIC if (ipprintfs) printf(" %lx\n", ntohl(q->s_addr));#endif return (m);}#endif /* SRCRT *//* * 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. * XXX should be deleted; last arg currently ignored. */voidip_stripoptions(m, mopt) register struct mbuf *m; struct mbuf *mopt;{ register int i; struct ip *ip = mtod(m, struct ip *); register caddr_t opts; int olen; olen = (ip->ip_hl<<2) - sizeof (struct ip); opts = (caddr_t)(ip + 1); i = m->m_len - (sizeof (struct ip) + olen); bcopy(opts + olen, opts, (unsigned)i); m->m_len -= olen; if (m->m_flags & M_PKTHDR) m->m_pkthdr.len -= olen; ip->ip_hl = sizeof(struct ip) >> 2;}u_char inetctlerrmap[PRC_NCMDS] = { 0, 0, 0, 0, 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, EMSGSIZE, EHOSTUNREACH, 0, 0, 0, 0, 0, 0, ENOPROTOOPT};/* * Forward a packet. If some error occurs return the sender * an icmp packet. Note we can't always generate a meaningful * icmp message because icmp doesn't have a large enough repertoire * of codes and types. * * If not forwarding, just drop the packet. This could be confusing * if (_ipCfgFlags & IP_DO_FORWARDING) was zero but some routing protocol was * advancing us as a gateway to somewhere. However, we must let the routing * protocol deal with that. * * The srcrt parameter indicates whether the packet is being forwarded * via a source route. */voidip_forward(m, srcrt) struct mbuf *m; int srcrt;{ register struct ip *ip = mtod(m, struct ip *); register struct sockaddr_in *sin; register struct rtentry *rt; int error, type = 0, code = 0; struct mbuf *mcopy; n_long dest; struct ifnet *destifp;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET u_long srcAddr; /* Source IP address, unavailable after ip_output() */ u_long dstAddr; /* Dest. IP address, unavailable after ip_output() */#endif#endif dest = 0;#ifdef DIAGNOSTIC if (ipprintfs) printf("forward: src %x dst %x ttl %x\n", ip->ip_src, ip->ip_dst, ip->ip_ttl);#endif if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_ADDROUT_EVENT_1 (NET_CORE_EVENT, WV_NET_CRITICAL, 19, 10, ip->ip_src.s_addr, ip->ip_dst.s_addr, WV_NETEVENT_IPFWD_BADADDR, WV_NET_RECV, ip->ip_dst.s_addr)#endif /* INCLUDE_WVNET */#endif #ifdef VIRTUAL_STACK _ipstat.ips_cantforward++;#else ipstat.ips_cantforward++;#endif /* VIRTUAL_STACK */ m_freem(m); return; } HTONS(ip->ip_id); if (ip->ip_ttl <= IPTTLDEC) { if (_icmpErrorHook != NULL) { HTONS(ip->ip_len); (*_icmpErrorHook)(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); } return; } ip->ip_ttl -= IPTTLDEC; sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; if ((rt = ipforward_rt.ro_rt) == 0 || (rt->rt_flags & RTF_UP) == 0 || ip->ip_dst.s_addr != sin->sin_addr.s_addr) { if (ipforward_rt.ro_rt) { RTFREE(ipforward_rt.ro_rt); ipforward_rt.ro_rt = 0; } sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_addr = ip->ip_dst; ipforward_rt.ro_rt = rtalloc2 (&ipforward_rt.ro_dst); if (ipforward_rt.ro_rt == 0) {#ifdef VIRTUAL_STACK _ipstat.ips_noroute++;#else ipstat.ips_noroute++;#endif /* VIRTUAL_STACK */ if (_icmpErrorHook != NULL) (*_icmpErrorHook)(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); return; } rt = ipforward_rt.ro_rt; } /* * Save at most 64 bytes of the packet in case * we need to generate an ICMP message to the src. */ mcopy = m_copy(m, 0, min((int)ip->ip_len, 64)); /* * If forwarding packet using same interface that it came in on, * perhaps should send a redirect to sender to shortcut a hop. * Only send redirect if source is sending directly to us, * and if packet was not source routed (or has any options). * Also, don't send redirect if forwarding using a default route * or a route modified by a redirect. */#define satosin(sa) ((struct sockaddr_in *)(sa)) if (rt->rt_ifp == m->m_pkthdr.rcvif && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && satosin(rt_key(rt))->sin_addr.s_addr != 0 && (_ipCfgFlags & IP_DO_REDIRECT) && !srcrt) {#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa)) u_long src = ntohl(ip->ip_src.s_addr); if (RTA(rt) && (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) { if (rt->rt_flags & RTF_GATEWAY) dest = satosin(rt->rt_gateway)->sin_addr.s_addr; else dest = ip->ip_dst.s_addr; /* Router requirements says to only send host redirects */ type = ICMP_REDIRECT; code = ICMP_REDIRECT_HOST;#ifdef DIAGNOSTIC if (ipprintfs) printf("redirect (%d) to %lx\n", code, (u_long)dest);#endif } }#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* * Save the source and destination address from the original packet, * since they will be unavailable after the ip_output() call returns. */ srcAddr = ip->ip_src.s_addr; dstAddr = ip->ip_dst.s_addr;#endif#endif /* * Set the M_FORWARD flag to nominate the route for the fast path. */ m->m_flags |= M_FORWARD; error = ip_output(m, (struct mbuf *)0, &ipforward_rt, IP_FORWARDING#ifdef DIRECTED_BROADCAST | IP_ALLOWBROADCAST#endif , 0);#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_NOTICE event */ WV_NET_ADDROUT_EVENT_3 (NET_CORE_EVENT, WV_NET_NOTICE, 11, 15, srcAddr, dstAddr, WV_NETEVENT_IPFWD_STATUS, WV_NET_SEND, error, srcAddr, dstAddr)#endif /* INCLUDE_WVNET */#endif if (error)#ifdef VIRTUAL_STACK _ipstat.ips_cantforward++;#else ipstat.ips_cantforward++;#endif /* VIRTUAL_STACK */ else {#ifdef VIRTUAL_STACK _ipstat.ips_forward++;#else ipstat.ips_forward++;#endif /* VIRTUAL_STACK */ if (type)#ifdef VIRTUAL_STACK _ipstat.ips_redirectsent++;#else ipstat.ips_redirectsent++;#endif /* VIRTUAL_STACK */ else { if (mcopy) m_freem(mcopy); return; } } if (mcopy == NULL) return; destifp = NULL; switch (error) { case 0: /* forwarded, but need redirect */ /* type, code set above */ break; case ENETUNREACH: /* shouldn't happen, checked above */ case EHOSTUNREACH: case ENETDOWN: case EHOSTDOWN: default: type = ICMP_UNREACH; code = ICMP_UNREACH_HOST; break; case EMSGSIZE: type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; if (ipforward_rt.ro_rt) destifp = ipforward_rt.ro_rt->rt_ifp;#ifdef VIRTUAL_STACK _ipstat.ips_cantfrag++;#else ipstat.ips_cantfrag++;#endif /* VIRTUAL_STACK */ break; case ENOBUFS: type = ICMP_SOURCEQUENCH; code = 0; break; } if (_icmpErrorHook != NULL) (*_icmpErrorHook)(mcopy, type, code, dest, destifp);}#ifdef SYSCTL_SUPPORTintip_sysctl(name, namelen, oldp, oldlenp, newp, newlen) int *name; u_int namelen; void *oldp; size_t *oldlenp; void *newp; size_t newlen;{/* * XXX - This event cannot currently occur: the ip_sysctl() routine * is only called by the Unix sysctl command which is not supported * by VxWorks#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /@ WV_NET_INFO event @/ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_INFO, 9, 19, WV_NETEVENT_IPCTRL_START, name[0])#endif /@ INCLUDE_WVNET @/#endif * XXX - end of unused event */ /* All sysctl names at this level are terminal. */ if (namelen != 1) {/* * XXX - This event cannot currently occur: the ip_sysctl() routine * is only called by the Unix sysctl command which is not supported * by VxWorks#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /@ WV_NET_ERROR event @/ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_ERROR, 20, 11, WV_NETEVENT_IPCTRL_BADCMDLEN, namelen)#endif /@ INCLUDE_WVNET @/#endif * XXX - end of unused event */ return (ENOTDIR); } switch (name[0]) { case IPCTL_FORWARDING: return (sysctl_int(oldp, oldlenp, newp, newlen, &ipforwarding)); case IPCTL_SENDREDIRECTS: return (sysctl_int(oldp, oldlenp, newp, newlen, &ipsendredirects)); case IPCTL_DEFTTL: return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_defttl));#ifdef notyet case IPCTL_DEFMTU: return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtu));#endif default:/* * XXX - This event cannot currently occur: the ip_sysctl() routine * is only called by the Unix sysctl command which is not supported * by VxWorks#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /@ WV_NET_ERROR event @/ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_ERROR, 21, 12, WV_NETEVENT_IPCTRL_BADCMD, name[0])#endif /@ INCLUDE_WVNET @/#endif * XXX - end of unused event */ return (EOPNOTSUPP); } /* NOTREACHED */}#endif /* SYSCTL_SUPPORT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -