📄 ip_icmp.c
字号:
icmpsrc.sin_addr = ip->ip_src; if (ia == (struct in_ifaddr *)0) ia = (struct in_ifaddr *)ifaof_ifpforaddr( (struct sockaddr *)&icmpsrc, m->m_pkthdr.rcvif); /* * The following happens if the packet was not addressed to us, * and was received on an interface with no IP address. */ if (ia == (struct in_ifaddr *)0)#ifdef VIRTUAL_STACK ia = _in_ifaddr;#else ia = in_ifaddr;#endif /* VIRTUAL_STACK */ t = IA_SIN(ia)->sin_addr; ip->ip_src = t; ip->ip_ttl = ipTimeToLive; if (optlen > 0) { register u_char *cp; int opt, cnt; u_int len; /* * Retrieve any source routing from the incoming packet; * add on any record-route or timestamp options. */ cp = (u_char *) (ip + 1);#ifdef SRCRT if ((opts = ip_srcroute()) == 0 && (opts = mHdrClGet(M_DONTWAIT, MT_HEADER, CL_SIZE_128, TRUE))) { opts->m_len = sizeof(struct in_addr); mtod(opts, struct in_addr *)->s_addr = 0; }#endif /* SRCRT */ if (opts) {#ifdef ICMPPRINTFS if (icmpprintfs) printf("icmp_reflect optlen %d rt %d => ", optlen, opts->m_len);#endif for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { opt = cp[IPOPT_OPTVAL]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) len = 1; else { len = cp[IPOPT_OLEN]; if (len <= 0 || len > cnt) break; } /* * Should check for overflow, but it "can't happen" */ if (opt == IPOPT_RR || opt == IPOPT_TS || opt == IPOPT_SECURITY) { bcopy((caddr_t)cp, mtod(opts, caddr_t) + opts->m_len, len); opts->m_len += len; } } /* Terminate & pad, if necessary */ if ((cnt = opts->m_len % 4)) { for (; cnt < 4; cnt++) { *(mtod(opts, caddr_t) + opts->m_len) = IPOPT_EOL; opts->m_len++; } }#ifdef ICMPPRINTFS if (icmpprintfs) printf("%d\n", opts->m_len);#endif } /* * Now strip out original options by copying rest of first * mbuf's data back, and adjust the IP length. */ ip->ip_len -= optlen; ip->ip_hl = sizeof(struct ip) >> 2; m->m_len -= optlen; if (m->m_flags & M_PKTHDR) m->m_pkthdr.len -= optlen; optlen += sizeof(struct ip); bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), (unsigned)(m->m_len - sizeof(struct ip))); } m->m_flags &= ~(M_BCAST|M_MCAST); icmp_send(m, opts);done: if (opts) (void)m_free(opts);}/* * Send an icmp packet back to the ip level, * after supplying a checksum. */static voidicmp_send(m, opts) register struct mbuf *m; struct mbuf *opts;{ register struct ip *ip = mtod(m, struct ip *); register int hlen; register struct icmp *icp;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_NOTICE event */ WV_NET_ADDROUT_EVENT_2 (NET_CORE_EVENT, WV_NET_NOTICE, 9, 10, ip->ip_src.s_addr, ip->ip_dst.s_addr, WV_NETEVENT_ICMPSEND_START, WV_NET_SEND, ip->ip_src.s_addr, ip->ip_dst.s_addr)#endif /* INCLUDE_WVNET */#endif hlen = ip->ip_hl << 2; m->m_data += hlen; m->m_len -= hlen; icp = mtod(m, struct icmp *); icp->icmp_cksum = 0; icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); m->m_data -= hlen; m->m_len += hlen;#ifdef ICMPPRINTFS if (icmpprintfs) printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);#endif (void) ip_output(m, opts, NULL, 0, NULL);} /* * This routine handles the ICMP "need fragmentation" error which * triggers the selection of a new MTU value for the path MTU discovery * process. The new MTU value is equal to the suggested value from the * ICMP error message (if any) or the next value from the current path * MTU table. If the new MTU value is less than the acceptable minimum, * the routine marks the corresponding route to disable the path MTU * discovery process. */LOCAL void ip_next_mtu ( struct sockaddr * pDstAddr, /* destination of original IP packet */ int nextmtu ) { struct rtentry * pDestRoute; u_long oldmtu = 0; u_long newmtu; int loop; pDestRoute = rtalloc1 (pDstAddr, 0); if (pDestRoute && (pDestRoute->rt_flags & RTF_HOST) && !(pDestRoute->rt_rmx.rmx_locks & RTV_MTU)) { oldmtu = pDestRoute->rt_rmx.rmx_mtu; if (oldmtu == 0) { /* Current estimate unavailable - end discovery process. */ newmtu = 0; } else if (nextmtu == 0) { /* No value included in ICMP message. Use entry from table. */ for (loop = 0; loop < mtuTableSize; loop++) if (oldmtu > mtuTable [ (mtuTableSize - 1) - loop]) break; if (loop != mtuTableSize) { /* Set the new MTU value. */ newmtu = mtuTable [loop]; } else newmtu = 0; /* Match not found - disable MTU discovery. */ } else newmtu = nextmtu; /* Use value from ICMP message. */ if (newmtu < PATHMTU_MIN) { /* Set lock to disable path MTU discovery for this destination. */ pDestRoute->rt_rmx.rmx_locks |= RTV_MTU; } else if (oldmtu > newmtu) { /* * Decrease the estimated MTU size to the new value. The test * handles the (illegal) case where a downstream router sends * a larger MTU size in the "need fragment" message. */ pDestRoute->rt_rmx.rmx_mtu = newmtu; } } if (pDestRoute) { RTFREE (pDestRoute) } return; }/* ICMP socket option processing. */int icmp_ctloutput ( int op, struct socket *so, int level, int optname, struct mbuf **mp ) { register struct mbuf *m = *mp;#if 0 /* For timer options (not yet supported). */ int optval;#endif int optlen; int error = 0; switch (op) { case PRCO_SETOPT: optlen = m->m_len; switch (optname) { case SO_PATHMTU_TBL: if (m->m_len % sizeof (u_short)) error = EINVAL; else { bcopy ((char *)mtod (m, u_short *), (char *)mtuTable, m->m_len); mtuTableSize = m->m_len / sizeof (u_short); } break;#if 0 /* Timers for increasing path MTU value (not yet supported). */ case SO_PATHMTU_LIFETIME: if (m->m_len != sizeof (int)) error = EINVAL; else optval = *mtod (m, int *); break; case SO_PATHMTU_TIMEOUT: break;#endif default: error = ENOPROTOOPT; break; } if (m) (void)m_free(m); break; case PRCO_GETOPT: *mp = m = mBufClGet (M_WAIT, MT_SOOPTS, CL_SIZE_128, TRUE); if (m == (struct mbuf *) NULL) { error = ENOBUFS; break; } switch (optname) { case SO_PATHMTU_TBL: m->m_len = mtuTableSize * sizeof (u_short); bcopy ((char *)mtuTable, (char *)mtod(m, u_short *), (unsigned)m->m_len); break;#if 0 /* Timers for increasing path MTU value (not yet supported). */ case SO_PATHMTU_LIFETIME: m->m_len = sizeof (u_int); /* optval = lifetime; */ *mtod (m, u_int *) = optval; break; case SO_PATHMTU_TIMEOUT: break;#endif default: error = ENOPROTOOPT; break; } break; } return (error); }#ifdef SYSCTL_SUPPORTinticmp_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 icmp_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, 5, 11, WV_NETEVENT_ICMPCTRL_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 icmp_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, 18, 6, WV_NETEVENT_ICMPCTRL_BADLEN, namelen)#endif /@ INCLUDE_WVNET @/#endif * XXX - end of unused event */ return (ENOTDIR); } switch (name[0]) { case ICMPCTL_MASKREPL: return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl)); default:/* * XXX - This event cannot currently occur: the icmp_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, 19, 7, WV_NETEVENT_ICMPCTRL_BADCMD, name[0]) #endif /@ INCLUDE_WVNET @/#endif * XXX - end of unused event */ return (ENOPROTOOPT); } /* NOTREACHED */}#endif /* SYSCTL_SUPPORT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -