Changeset View
Standalone View
sys/netinet/ip_output.c
Show First 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | |||||
#include <net/route.h> | #include <net/route.h> | ||||
#ifdef RADIX_MPATH | #ifdef RADIX_MPATH | ||||
#include <net/radix_mpath.h> | #include <net/radix_mpath.h> | ||||
#endif | #endif | ||||
#include <net/rss_config.h> | #include <net/rss_config.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/in_fib.h> | |||||
#include <netinet/in_kdtrace.h> | #include <netinet/in_kdtrace.h> | ||||
#include <netinet/in_systm.h> | #include <netinet/in_systm.h> | ||||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||||
#include <netinet/in_pcb.h> | #include <netinet/in_pcb.h> | ||||
#include <netinet/in_rss.h> | #include <netinet/in_rss.h> | ||||
#include <netinet/in_var.h> | #include <netinet/in_var.h> | ||||
#include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||||
#include <netinet/ip_options.h> | #include <netinet/ip_options.h> | ||||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags, | ||||
struct rm_priotracker in_ifa_tracker; | struct rm_priotracker in_ifa_tracker; | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct ip *ip; | struct ip *ip; | ||||
struct ifnet *ifp = NULL; /* keep compiler happy */ | struct ifnet *ifp = NULL; /* keep compiler happy */ | ||||
struct mbuf *m0; | struct mbuf *m0; | ||||
int hlen = sizeof (struct ip); | int hlen = sizeof (struct ip); | ||||
int mtu; | int mtu; | ||||
int error = 0; | int error = 0; | ||||
struct sockaddr_in *dst; | struct sockaddr_in *dst, sin; | ||||
const struct sockaddr_in *gw; | const struct sockaddr_in *gw; | ||||
struct in_ifaddr *ia; | struct in_ifaddr *ia; | ||||
struct in_addr src; | |||||
int isbroadcast; | int isbroadcast; | ||||
uint16_t ip_len, ip_off; | uint16_t ip_len, ip_off; | ||||
struct route iproute; | |||||
struct rtentry *rte; /* cache for ro->ro_rt */ | |||||
uint32_t fibnum; | uint32_t fibnum; | ||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
int no_route_but_check_spd = 0; | int no_route_but_check_spd = 0; | ||||
#endif | #endif | ||||
M_ASSERTPKTHDR(m); | M_ASSERTPKTHDR(m); | ||||
if (inp != NULL) { | if (inp != NULL) { | ||||
INP_LOCK_ASSERT(inp); | INP_LOCK_ASSERT(inp); | ||||
M_SETFIB(m, inp->inp_inc.inc_fibnum); | M_SETFIB(m, inp->inp_inc.inc_fibnum); | ||||
if ((flags & IP_NODEFAULTFLOWID) == 0) { | if ((flags & IP_NODEFAULTFLOWID) == 0) { | ||||
m->m_pkthdr.flowid = inp->inp_flowid; | m->m_pkthdr.flowid = inp->inp_flowid; | ||||
M_HASHTYPE_SET(m, inp->inp_flowtype); | M_HASHTYPE_SET(m, inp->inp_flowtype); | ||||
} | } | ||||
} | } | ||||
if (ro == NULL) { | |||||
ro = &iproute; | |||||
bzero(ro, sizeof (*ro)); | |||||
} | |||||
if (opt) { | if (opt) { | ||||
int len = 0; | int len = 0; | ||||
m = ip_insertoptions(m, opt, &len); | m = ip_insertoptions(m, opt, &len); | ||||
if (len != 0) | if (len != 0) | ||||
hlen = len; /* ip->ip_hl is updated above */ | hlen = len; /* ip->ip_hl is updated above */ | ||||
} | } | ||||
ip = mtod(m, struct ip *); | ip = mtod(m, struct ip *); | ||||
ip_len = ntohs(ip->ip_len); | ip_len = ntohs(ip->ip_len); | ||||
ip_off = ntohs(ip->ip_off); | ip_off = ntohs(ip->ip_off); | ||||
if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { | if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { | ||||
ip->ip_v = IPVERSION; | ip->ip_v = IPVERSION; | ||||
ip->ip_hl = hlen >> 2; | ip->ip_hl = hlen >> 2; | ||||
ip_fillid(ip); | ip_fillid(ip); | ||||
} else { | } else { | ||||
/* Header already set, fetch hlen from there */ | /* Header already set, fetch hlen from there */ | ||||
hlen = ip->ip_hl << 2; | hlen = ip->ip_hl << 2; | ||||
} | } | ||||
if ((flags & IP_FORWARDING) == 0) | if ((flags & IP_FORWARDING) == 0) | ||||
IPSTAT_INC(ips_localout); | IPSTAT_INC(ips_localout); | ||||
/* | /* | ||||
* dst/gw handling: | * dst/gw handling: | ||||
* | * | ||||
* dst can be rewritten but always points to &ro->ro_dst. | |||||
* gw is readonly but can point either to dst OR rt_gateway, | * gw is readonly but can point either to dst OR rt_gateway, | ||||
* therefore we need restore gw if we're redoing lookup. | * therefore we need restore gw if we're redoing lookup. | ||||
*/ | */ | ||||
gw = dst = (struct sockaddr_in *)&ro->ro_dst; | |||||
fibnum = (inp != NULL) ? inp->inp_inc.inc_fibnum : M_GETFIB(m); | fibnum = (inp != NULL) ? inp->inp_inc.inc_fibnum : M_GETFIB(m); | ||||
rte = ro->ro_rt; | if (ro != NULL) | ||||
if (rte == NULL) { | dst = (struct sockaddr_in *)&ro->ro_dst; | ||||
else | |||||
dst = &sin; | |||||
if (ro == NULL || ro->ro_rt == NULL) { | |||||
bzero(dst, sizeof(*dst)); | bzero(dst, sizeof(*dst)); | ||||
dst->sin_family = AF_INET; | dst->sin_family = AF_INET; | ||||
dst->sin_len = sizeof(*dst); | dst->sin_len = sizeof(*dst); | ||||
dst->sin_addr = ip->ip_dst; | dst->sin_addr = ip->ip_dst; | ||||
} | } | ||||
gw = dst; | |||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
again: | again: | ||||
/* | /* | ||||
* Validate route against routing table additions; | * Validate route against routing table additions; | ||||
* a better/more specific route might have been added. | * a better/more specific route might have been added. | ||||
*/ | */ | ||||
if (inp) | if (inp != NULL && ro != NULL && ro->ro_rt != NULL) | ||||
RT_VALIDATE(ro, &inp->inp_rt_cookie, fibnum); | RT_VALIDATE(ro, &inp->inp_rt_cookie, fibnum); | ||||
/* | /* | ||||
* If there is a cached route, | * If there is a cached route, | ||||
* check that it is to the same destination | * check that it is to the same destination | ||||
* and is still up. If not, free it and try again. | * and is still up. If not, free it and try again. | ||||
* The address family should also be checked in case of sharing the | * The address family should also be checked in case of sharing the | ||||
* cache with IPv6. | * cache with IPv6. | ||||
* Also check whether routing cache needs invalidation. | * Also check whether routing cache needs invalidation. | ||||
*/ | */ | ||||
rte = ro->ro_rt; | if (ro != NULL && ro->ro_rt != NULL && | ||||
if (rte && ((rte->rt_flags & RTF_UP) == 0 || | ((ro->ro_rt->rt_flags & RTF_UP) == 0 || | ||||
rte->rt_ifp == NULL || | ro->ro_rt->rt_ifp == NULL || !RT_LINK_IS_UP(ro->ro_rt->rt_ifp) || | ||||
!RT_LINK_IS_UP(rte->rt_ifp) || | |||||
dst->sin_family != AF_INET || | dst->sin_family != AF_INET || | ||||
dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { | dst->sin_addr.s_addr != ip->ip_dst.s_addr)) | ||||
melifaro: Nitpick: if we're revisiting this fancy condition, would it be possible to consider replace its… | |||||
Done Inline ActionsDo we have RTE_IS_INVALID? But we always first need to check that ro->ro_rt isn't NULL anyway. glebius: Do we have RTE_IS_INVALID? But we always first need to check that ro->ro_rt isn't NULL anyway. | |||||
Not Done Inline ActionsNo, we don't. I was suggesting adding it as we have these checks repeated at least twice in the ip_output() melifaro: No, we don't. I was suggesting adding it as we have these checks repeated at least twice in the… | |||||
RO_INVALIDATE_CACHE(ro); | RO_INVALIDATE_CACHE(ro); | ||||
rte = NULL; | |||||
} | |||||
ia = NULL; | ia = NULL; | ||||
/* | /* | ||||
* If routing to interface only, short circuit routing lookup. | * If routing to interface only, short circuit routing lookup. | ||||
* The use of an all-ones broadcast address implies this; an | * The use of an all-ones broadcast address implies this; an | ||||
* interface is specified by the broadcast address of an interface, | * interface is specified by the broadcast address of an interface, | ||||
* or the destination address of a ptp interface. | * or the destination address of a ptp interface. | ||||
*/ | */ | ||||
if (flags & IP_SENDONES) { | if (flags & IP_SENDONES) { | ||||
if ((ia = ifatoia(ifa_ifwithbroadaddr(sintosa(dst), | if ((ia = ifatoia(ifa_ifwithbroadaddr(sintosa(dst), | ||||
M_GETFIB(m)))) == NULL && | M_GETFIB(m)))) == NULL && | ||||
(ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst), | (ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst), | ||||
M_GETFIB(m)))) == NULL) { | M_GETFIB(m)))) == NULL) { | ||||
IPSTAT_INC(ips_noroute); | IPSTAT_INC(ips_noroute); | ||||
error = ENETUNREACH; | error = ENETUNREACH; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
ip->ip_dst.s_addr = INADDR_BROADCAST; | ip->ip_dst.s_addr = INADDR_BROADCAST; | ||||
dst->sin_addr = ip->ip_dst; | dst->sin_addr = ip->ip_dst; | ||||
ifp = ia->ia_ifp; | ifp = ia->ia_ifp; | ||||
mtu = ifp->if_mtu; | |||||
ip->ip_ttl = 1; | ip->ip_ttl = 1; | ||||
isbroadcast = 1; | isbroadcast = 1; | ||||
src = IA_SIN(ia)->sin_addr; | |||||
} else if (flags & IP_ROUTETOIF) { | } else if (flags & IP_ROUTETOIF) { | ||||
if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst), | if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst), | ||||
M_GETFIB(m)))) == NULL && | M_GETFIB(m)))) == NULL && | ||||
(ia = ifatoia(ifa_ifwithnet(sintosa(dst), 0, | (ia = ifatoia(ifa_ifwithnet(sintosa(dst), 0, | ||||
M_GETFIB(m)))) == NULL) { | M_GETFIB(m)))) == NULL) { | ||||
IPSTAT_INC(ips_noroute); | IPSTAT_INC(ips_noroute); | ||||
error = ENETUNREACH; | error = ENETUNREACH; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
ifp = ia->ia_ifp; | ifp = ia->ia_ifp; | ||||
mtu = ifp->if_mtu; | |||||
ip->ip_ttl = 1; | ip->ip_ttl = 1; | ||||
isbroadcast = ifp->if_flags & IFF_BROADCAST ? | isbroadcast = ifp->if_flags & IFF_BROADCAST ? | ||||
in_ifaddr_broadcast(dst->sin_addr, ia) : 0; | in_ifaddr_broadcast(dst->sin_addr, ia) : 0; | ||||
src = IA_SIN(ia)->sin_addr; | |||||
} else if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && | } else if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && | ||||
imo != NULL && imo->imo_multicast_ifp != NULL) { | imo != NULL && imo->imo_multicast_ifp != NULL) { | ||||
/* | /* | ||||
* Bypass the normal routing lookup for multicast | * Bypass the normal routing lookup for multicast | ||||
* packets if the interface is specified. | * packets if the interface is specified. | ||||
*/ | */ | ||||
ifp = imo->imo_multicast_ifp; | ifp = imo->imo_multicast_ifp; | ||||
mtu = ifp->if_mtu; | |||||
IFP_TO_IA(ifp, ia, &in_ifa_tracker); | IFP_TO_IA(ifp, ia, &in_ifa_tracker); | ||||
isbroadcast = 0; /* fool gcc */ | isbroadcast = 0; /* fool gcc */ | ||||
} else { | src = IA_SIN(ia)->sin_addr; | ||||
} else if (ro != NULL) { | |||||
if (ro->ro_rt == NULL) { | |||||
/* | /* | ||||
* We want to do any cloning requested by the link layer, | * We want to do any cloning requested by the link | ||||
* as this is probably required in all cases for correct | * layer, as this is probably required in all cases | ||||
* operation (as it is for ARP). | * for correct operation (as it is for ARP). | ||||
*/ | */ | ||||
if (rte == NULL) { | |||||
#ifdef RADIX_MPATH | #ifdef RADIX_MPATH | ||||
rtalloc_mpath_fib(ro, | rtalloc_mpath_fib(ro, | ||||
ntohl(ip->ip_src.s_addr ^ ip->ip_dst.s_addr), | ntohl(ip->ip_src.s_addr ^ ip->ip_dst.s_addr), | ||||
fibnum); | fibnum); | ||||
#else | #else | ||||
in_rtalloc_ign(ro, 0, fibnum); | in_rtalloc_ign(ro, 0, fibnum); | ||||
#endif | #endif | ||||
rte = ro->ro_rt; | if (ro->ro_rt == NULL || | ||||
} | (ro->ro_rt->rt_flags & RTF_UP) == 0 || | ||||
if (rte == NULL || | ro->ro_rt->rt_ifp == NULL || | ||||
(rte->rt_flags & RTF_UP) == 0 || | !RT_LINK_IS_UP(ro->ro_rt->rt_ifp)) { | ||||
rte->rt_ifp == NULL || | |||||
!RT_LINK_IS_UP(rte->rt_ifp)) { | |||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | #if defined(IPSEC) || defined(IPSEC_SUPPORT) | ||||
/* | /* | ||||
* There is no route for this packet, but it is | * There is no route for this packet, but it is | ||||
* possible that a matching SPD entry exists. | * possible that a matching SPD entry exists. | ||||
*/ | */ | ||||
no_route_but_check_spd = 1; | no_route_but_check_spd = 1; | ||||
mtu = 0; /* Silence GCC warning. */ | mtu = 0; /* Silence GCC warning. */ | ||||
goto sendit; | goto sendit; | ||||
#endif | #endif | ||||
IPSTAT_INC(ips_noroute); | IPSTAT_INC(ips_noroute); | ||||
error = EHOSTUNREACH; | error = EHOSTUNREACH; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
ia = ifatoia(rte->rt_ifa); | } | ||||
ifp = rte->rt_ifp; | ia = ifatoia(ro->ro_rt->rt_ifa); | ||||
counter_u64_add(rte->rt_pksent, 1); | ifp = ro->ro_rt->rt_ifp; | ||||
counter_u64_add(ro->ro_rt->rt_pksent, 1); | |||||
rt_update_ro_flags(ro); | rt_update_ro_flags(ro); | ||||
if (rte->rt_flags & RTF_GATEWAY) | if (ro->ro_rt->rt_flags & RTF_GATEWAY) | ||||
gw = (struct sockaddr_in *)rte->rt_gateway; | gw = (struct sockaddr_in *)ro->ro_rt->rt_gateway; | ||||
if (rte->rt_flags & RTF_HOST) | if (ro->ro_rt->rt_flags & RTF_HOST) | ||||
isbroadcast = (rte->rt_flags & RTF_BROADCAST); | isbroadcast = (ro->ro_rt->rt_flags & RTF_BROADCAST); | ||||
else if (ifp->if_flags & IFF_BROADCAST) | else if (ifp->if_flags & IFF_BROADCAST) | ||||
isbroadcast = in_ifaddr_broadcast(gw->sin_addr, ia); | isbroadcast = in_ifaddr_broadcast(gw->sin_addr, ia); | ||||
else | else | ||||
isbroadcast = 0; | isbroadcast = 0; | ||||
} | if (ro->ro_rt->rt_flags & RTF_HOST) | ||||
mtu = ro->ro_rt->rt_mtu; | |||||
else | |||||
mtu = ifp->if_mtu; | |||||
src = IA_SIN(ia)->sin_addr; | |||||
} else { | |||||
struct nhop4_extended nh; | |||||
bzero(&nh, sizeof(nh)); | |||||
if (fib4_lookup_nh_ext(M_GETFIB(m), ip->ip_dst, 0, 0, &nh) != | |||||
0) { | |||||
#if defined(IPSEC) || defined(IPSEC_SUPPORT) | |||||
/* | /* | ||||
* Calculate MTU. If we have a route that is up, use that, | * There is no route for this packet, but it is | ||||
* otherwise use the interface's MTU. | * possible that a matching SPD entry exists. | ||||
*/ | */ | ||||
if (rte != NULL && (rte->rt_flags & (RTF_UP|RTF_HOST))) | no_route_but_check_spd = 1; | ||||
mtu = rte->rt_mtu; | mtu = 0; /* Silence GCC warning. */ | ||||
else | goto sendit; | ||||
mtu = ifp->if_mtu; | #endif | ||||
IPSTAT_INC(ips_noroute); | |||||
error = EHOSTUNREACH; | |||||
goto bad; | |||||
} | |||||
ifp = nh.nh_ifp; | |||||
mtu = nh.nh_mtu; | |||||
/* | |||||
* We are rewriting here dst to be gw actually, contradicting | |||||
* comment at the beginning of the function. However, in this | |||||
* case we are always dealing with on stack dst. | |||||
* In case if pfil(9) sends us back to beginning of the | |||||
* function, the dst would be rewritten by ip_output_pfil(). | |||||
*/ | |||||
MPASS(dst == &sin); | |||||
dst->sin_addr = nh.nh_addr; | |||||
ia = nh.nh_ia; | |||||
src = nh.nh_src; | |||||
isbroadcast = (((nh.nh_flags & (NHF_HOST | NHF_BROADCAST)) == | |||||
Not Done Inline ActionsSeem to always fallback to the in_ifaddr_broadcast() check. Originally RTF_BROADCAST flag was added 22 years ago in r15652 to avoid calling in_ifaddr_broadcast(). We had route cloning back then, so it was a fair assumption - if the lookup result was a host route (and it almost always was), then we could trust its broadcast flag, as it was set in the in_addroute() after verificaton. Currently we don't have route cloning and the only way of having RTF_BROADCAST set on the route is to explicitly add host route to the broadcast address: route add -host 10.0.0.255 -iface vtnet0 assuming 10.0.0.0/24 belongs to vtnet0 Given that, the check here and in line 400 (if (ro->ro_rt->rt_flags & RTF_HOST)) will aways failback to in_ifaddr_broadcast(). Maybe it's worth just eliminating this condition and always check for in_ifaddr_broadcast(). melifaro: Seem to always fallback to the in_ifaddr_broadcast() check.
Originally RTF_BROADCAST flag was… | |||||
Done Inline ActionsBut as long as we allow adding such routes manually, we should support them, shouldn't we? glebius: But as long as we allow adding such routes manually, we should support them, shouldn't we? | |||||
(NHF_HOST | NHF_BROADCAST)) || | |||||
((ifp->if_flags & IFF_BROADCAST) && | |||||
in_ifaddr_broadcast(dst->sin_addr, ia))); | |||||
} | |||||
/* Catch a possible divide by zero later. */ | /* Catch a possible divide by zero later. */ | ||||
KASSERT(mtu > 0, ("%s: mtu %d <= 0, rte=%p (rt_flags=0x%08x) ifp=%p", | KASSERT(mtu > 0, ("%s: mtu %d <= 0, ro=%p (rt_flags=0x%08x) ifp=%p", | ||||
__func__, mtu, rte, (rte != NULL) ? rte->rt_flags : 0, ifp)); | __func__, mtu, ro, | ||||
(ro != NULL && ro->ro_rt != NULL) ? ro->ro_rt->rt_flags : 0, ifp)); | |||||
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { | if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { | ||||
m->m_flags |= M_MCAST; | m->m_flags |= M_MCAST; | ||||
/* | /* | ||||
* IP destination address is multicast. Make sure "gw" | * IP destination address is multicast. Make sure "gw" | ||||
* still points to the address in "ro". (It may have been | * still points to the address in "ro". (It may have been | ||||
* changed to point to a gateway address, above.) | * changed to point to a gateway address, above.) | ||||
*/ | */ | ||||
Show All 19 Lines | if ((imo == NULL) || (imo->imo_multicast_vif == -1)) { | ||||
error = ENETUNREACH; | error = ENETUNREACH; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If source address not specified yet, use address | * If source address not specified yet, use address | ||||
* of outgoing interface. | * of outgoing interface. | ||||
*/ | */ | ||||
if (ip->ip_src.s_addr == INADDR_ANY) { | if (ip->ip_src.s_addr == INADDR_ANY) | ||||
/* Interface may have no addresses. */ | ip->ip_src = src; | ||||
if (ia != NULL) | |||||
ip->ip_src = IA_SIN(ia)->sin_addr; | |||||
} | |||||
if ((imo == NULL && in_mcast_loop) || | if ((imo == NULL && in_mcast_loop) || | ||||
(imo && imo->imo_multicast_loop)) { | (imo && imo->imo_multicast_loop)) { | ||||
/* | /* | ||||
* Loop back multicast datagram if not expressly | * Loop back multicast datagram if not expressly | ||||
* forbidden to do so, even if we are not a member | * forbidden to do so, even if we are not a member | ||||
* of the group; ip_input() will filter it later, | * of the group; ip_input() will filter it later, | ||||
* thus deferring a hash lookup and mutex acquisition | * thus deferring a hash lookup and mutex acquisition | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { | ||||
goto sendit; | goto sendit; | ||||
} | } | ||||
/* | /* | ||||
* If the source address is not specified yet, use the address | * If the source address is not specified yet, use the address | ||||
* of the outoing interface. | * of the outoing interface. | ||||
*/ | */ | ||||
if (ip->ip_src.s_addr == INADDR_ANY) { | if (ip->ip_src.s_addr == INADDR_ANY) | ||||
/* Interface may have no addresses. */ | ip->ip_src = src; | ||||
if (ia != NULL) { | |||||
ip->ip_src = IA_SIN(ia)->sin_addr; | |||||
} | |||||
} | |||||
/* | /* | ||||
* Look for broadcast address and | * Look for broadcast address and | ||||
* verify user is allowed to send | * verify user is allowed to send | ||||
* such a packet. | * such a packet. | ||||
*/ | */ | ||||
if (isbroadcast) { | if (isbroadcast) { | ||||
if ((ifp->if_flags & IFF_BROADCAST) == 0) { | if ((ifp->if_flags & IFF_BROADCAST) == 0) { | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | case 1: /* Finished */ | ||||
goto done; | goto done; | ||||
case 0: /* Continue normally */ | case 0: /* Continue normally */ | ||||
ip = mtod(m, struct ip *); | ip = mtod(m, struct ip *); | ||||
break; | break; | ||||
case -1: /* Need to try again */ | case -1: /* Need to try again */ | ||||
/* Reset everything for a new round */ | /* Reset everything for a new round */ | ||||
if (ro != NULL) { | |||||
RO_RTFREE(ro); | RO_RTFREE(ro); | ||||
ro->ro_prepend = NULL; | ro->ro_prepend = NULL; | ||||
rte = NULL; | } | ||||
gw = dst; | gw = dst; | ||||
ip = mtod(m, struct ip *); | ip = mtod(m, struct ip *); | ||||
goto again; | goto again; | ||||
} | } | ||||
} | } | ||||
/* 127/8 must not appear on wire - RFC1122. */ | /* 127/8 must not appear on wire - RFC1122. */ | ||||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | #endif | ||||
} else | } else | ||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
if (error == 0) | if (error == 0) | ||||
IPSTAT_INC(ips_fragmented); | IPSTAT_INC(ips_fragmented); | ||||
done: | done: | ||||
if (ro == &iproute) | |||||
RO_RTFREE(ro); | |||||
else if (rte == NULL) | |||||
/* | |||||
* If the caller supplied a route but somehow the reference | |||||
* to it has been released need to prevent the caller | |||||
* calling RTFREE on it again. | |||||
*/ | |||||
ro->ro_rt = NULL; | |||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
return (error); | return (error); | ||||
bad: | bad: | ||||
m_freem(m); | m_freem(m); | ||||
goto done; | goto done; | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 720 Lines • Show Last 20 Lines |
Nitpick: if we're revisiting this fancy condition, would it be possible to consider replace its occurrence with something like
?