Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/frag6.c
Show First 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | |||||
#define IP6REASS_HMASK (IP6REASS_NHASH - 1) | #define IP6REASS_HMASK (IP6REASS_NHASH - 1) | ||||
static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *, | static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *, | ||||
uint32_t bucket __unused); | uint32_t bucket __unused); | ||||
static void frag6_deq(struct ip6asfrag *, uint32_t bucket __unused); | static void frag6_deq(struct ip6asfrag *, uint32_t bucket __unused); | ||||
static void frag6_insque_head(struct ip6q *, struct ip6q *, | static void frag6_insque_head(struct ip6q *, struct ip6q *, | ||||
uint32_t bucket); | uint32_t bucket); | ||||
static void frag6_remque(struct ip6q *, uint32_t bucket); | static void frag6_remque(struct ip6q *, uint32_t bucket); | ||||
static void frag6_freef(struct ip6q *, uint32_t bucket); | static void frag6_freef(struct ip6q *, uint32_t bucket, bool send_icmp); | ||||
bz: could be bool and then you could use true/false. | |||||
struct ip6qbucket { | struct ip6qbucket { | ||||
struct ip6q ip6q; | struct ip6q ip6q; | ||||
struct mtx lock; | struct mtx lock; | ||||
int count; | int count; | ||||
}; | }; | ||||
VNET_DEFINE_STATIC(volatile u_int, frag6_nfragpackets); | VNET_DEFINE_STATIC(volatile u_int, frag6_nfragpackets); | ||||
▲ Show 20 Lines • Show All 496 Lines • ▼ Show 20 Lines | #if 0 /* xxx */ | ||||
} | } | ||||
#endif | #endif | ||||
next = 0; | next = 0; | ||||
for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; | for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; | ||||
af6 = af6->ip6af_down) { | af6 = af6->ip6af_down) { | ||||
if (af6->ip6af_off != next) { | if (af6->ip6af_off != next) { | ||||
if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { | if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { | ||||
IP6STAT_ADD(ip6s_fragdropped, q6->ip6q_nfrag); | IP6STAT_ADD(ip6s_fragdropped, q6->ip6q_nfrag); | ||||
frag6_freef(q6, hash); | frag6_freef(q6, hash, true); | ||||
} | } | ||||
IP6Q_UNLOCK(hash); | IP6Q_UNLOCK(hash); | ||||
return IPPROTO_DONE; | return IPPROTO_DONE; | ||||
} | } | ||||
next += af6->ip6af_frglen; | next += af6->ip6af_frglen; | ||||
} | } | ||||
if (af6->ip6af_up->ip6af_mff) { | if (af6->ip6af_up->ip6af_mff) { | ||||
if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { | if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { | ||||
IP6STAT_ADD(ip6s_fragdropped, q6->ip6q_nfrag); | IP6STAT_ADD(ip6s_fragdropped, q6->ip6q_nfrag); | ||||
frag6_freef(q6, hash); | frag6_freef(q6, hash, true); | ||||
} | } | ||||
IP6Q_UNLOCK(hash); | IP6Q_UNLOCK(hash); | ||||
return IPPROTO_DONE; | return IPPROTO_DONE; | ||||
} | } | ||||
/* | /* | ||||
* Reassembly is complete; concatenate fragments. | * Reassembly is complete; concatenate fragments. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | dropfrag: | ||||
return IPPROTO_DONE; | return IPPROTO_DONE; | ||||
} | } | ||||
/* | /* | ||||
* Free a fragment reassembly header and all | * Free a fragment reassembly header and all | ||||
* associated datagrams. | * associated datagrams. | ||||
*/ | */ | ||||
static void | static void | ||||
frag6_freef(struct ip6q *q6, uint32_t bucket) | frag6_freef(struct ip6q *q6, uint32_t bucket, bool send_icmp) | ||||
{ | { | ||||
struct ip6asfrag *af6, *down6; | struct ip6asfrag *af6, *down6; | ||||
IP6Q_LOCK_ASSERT(bucket); | IP6Q_LOCK_ASSERT(bucket); | ||||
for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; | for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; | ||||
af6 = down6) { | af6 = down6) { | ||||
struct mbuf *m = IP6_REASS_MBUF(af6); | struct mbuf *m = IP6_REASS_MBUF(af6); | ||||
down6 = af6->ip6af_down; | down6 = af6->ip6af_down; | ||||
frag6_deq(af6, bucket); | frag6_deq(af6, bucket); | ||||
/* | /* | ||||
* Return ICMP time exceeded error for the 1st fragment. | * Return ICMP time exceeded error for the 1st fragment. | ||||
* Just free other fragments. | * Just free other fragments. | ||||
*/ | */ | ||||
if (af6->ip6af_off == 0) { | if (af6->ip6af_off == 0 && send_icmp != false) { | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
/* adjust pointer */ | /* adjust pointer */ | ||||
ip6 = mtod(m, struct ip6_hdr *); | ip6 = mtod(m, struct ip6_hdr *); | ||||
/* restore source and destination addresses */ | /* restore source and destination addresses */ | ||||
ip6->ip6_src = q6->ip6q_src; | ip6->ip6_src = q6->ip6q_src; | ||||
ip6->ip6_dst = q6->ip6q_dst; | ip6->ip6_dst = q6->ip6q_dst; | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | for (i = 0; i < IP6REASS_NHASH; i++) { | ||||
} | } | ||||
while (q6 != head) { | while (q6 != head) { | ||||
--q6->ip6q_ttl; | --q6->ip6q_ttl; | ||||
q6 = q6->ip6q_next; | q6 = q6->ip6q_next; | ||||
if (q6->ip6q_prev->ip6q_ttl == 0) { | if (q6->ip6q_prev->ip6q_ttl == 0) { | ||||
IP6STAT_ADD(ip6s_fragtimeout, | IP6STAT_ADD(ip6s_fragtimeout, | ||||
q6->ip6q_prev->ip6q_nfrag); | q6->ip6q_prev->ip6q_nfrag); | ||||
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | ||||
frag6_freef(q6->ip6q_prev, i); | frag6_freef(q6->ip6q_prev, i, true); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If we are over the maximum number of fragments | * If we are over the maximum number of fragments | ||||
* (due to the limit being lowered), drain off | * (due to the limit being lowered), drain off | ||||
* enough to get down to the new limit. | * enough to get down to the new limit. | ||||
* Note that we drain all reassembly queues if | * Note that we drain all reassembly queues if | ||||
* maxfragpackets is 0 (fragmentation is disabled), | * maxfragpackets is 0 (fragmentation is disabled), | ||||
* and don't enforce a limit when maxfragpackets | * and don't enforce a limit when maxfragpackets | ||||
* is negative. | * is negative. | ||||
*/ | */ | ||||
while ((V_ip6_maxfragpackets == 0 || | while ((V_ip6_maxfragpackets == 0 || | ||||
(V_ip6_maxfragpackets > 0 && | (V_ip6_maxfragpackets > 0 && | ||||
V_ip6q[i].count > V_ip6_maxfragbucketsize)) && | V_ip6q[i].count > V_ip6_maxfragbucketsize)) && | ||||
head->ip6q_prev != head) { | head->ip6q_prev != head) { | ||||
IP6STAT_ADD(ip6s_fragoverflow, | IP6STAT_ADD(ip6s_fragoverflow, | ||||
q6->ip6q_prev->ip6q_nfrag); | q6->ip6q_prev->ip6q_nfrag); | ||||
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | ||||
frag6_freef(head->ip6q_prev, i); | frag6_freef(head->ip6q_prev, i, true); | ||||
} | } | ||||
IP6Q_UNLOCK(i); | IP6Q_UNLOCK(i); | ||||
} | } | ||||
/* | /* | ||||
* If we are still over the maximum number of fragmented | * If we are still over the maximum number of fragmented | ||||
* packets, drain off enough to get down to the new limit. | * packets, drain off enough to get down to the new limit. | ||||
*/ | */ | ||||
i = 0; | i = 0; | ||||
while (V_ip6_maxfragpackets >= 0 && | while (V_ip6_maxfragpackets >= 0 && | ||||
atomic_load_int(&V_frag6_nfragpackets) > | atomic_load_int(&V_frag6_nfragpackets) > | ||||
(u_int)V_ip6_maxfragpackets) { | (u_int)V_ip6_maxfragpackets) { | ||||
IP6Q_LOCK(i); | IP6Q_LOCK(i); | ||||
head = IP6Q_HEAD(i); | head = IP6Q_HEAD(i); | ||||
if (head->ip6q_prev != head) { | if (head->ip6q_prev != head) { | ||||
IP6STAT_ADD(ip6s_fragoverflow, | IP6STAT_ADD(ip6s_fragoverflow, | ||||
q6->ip6q_prev->ip6q_nfrag); | q6->ip6q_prev->ip6q_nfrag); | ||||
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | ||||
frag6_freef(head->ip6q_prev, i); | frag6_freef(head->ip6q_prev, i, true); | ||||
} | } | ||||
IP6Q_UNLOCK(i); | IP6Q_UNLOCK(i); | ||||
i = (i + 1) % IP6REASS_NHASH; | i = (i + 1) % IP6REASS_NHASH; | ||||
} | } | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
VNET_LIST_RUNLOCK_NOSLEEP(); | VNET_LIST_RUNLOCK_NOSLEEP(); | ||||
} | } | ||||
Show All 13 Lines | VNET_FOREACH(vnet_iter) { | ||||
CURVNET_SET(vnet_iter); | CURVNET_SET(vnet_iter); | ||||
for (i = 0; i < IP6REASS_NHASH; i++) { | for (i = 0; i < IP6REASS_NHASH; i++) { | ||||
if (IP6Q_TRYLOCK(i) == 0) | if (IP6Q_TRYLOCK(i) == 0) | ||||
continue; | continue; | ||||
head = IP6Q_HEAD(i); | head = IP6Q_HEAD(i); | ||||
while (head->ip6q_next != head) { | while (head->ip6q_next != head) { | ||||
IP6STAT_INC(ip6s_fragdropped); | IP6STAT_INC(ip6s_fragdropped); | ||||
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ | ||||
frag6_freef(head->ip6q_next, i); | frag6_freef(head->ip6q_next, i, true); | ||||
} | } | ||||
IP6Q_UNLOCK(i); | IP6Q_UNLOCK(i); | ||||
} | } | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
} | } | ||||
VNET_LIST_RUNLOCK_NOSLEEP(); | VNET_LIST_RUNLOCK_NOSLEEP(); | ||||
} | } | ||||
/* | |||||
* Drain off all datagram fragments belonging to | |||||
* the given network interface. | |||||
*/ | |||||
static void | |||||
frag6_cleanup(void *arg __unused, struct ifnet *ifp) | |||||
{ | |||||
struct ip6q *q6, *q6n, *head; | |||||
struct ip6asfrag *af6; | |||||
struct mbuf *m; | |||||
int i; | |||||
Done Inline ActionsYou can fold these three into one line. bz: You can fold these three into one line. | |||||
KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); | |||||
Done Inline ActionsPlease add a KASSERT that ifp is not NULL bz: Please add a KASSERT that ifp is not NULL | |||||
#ifdef VIMAGE | |||||
if (ifp->if_vnet->vnet_state <= SI_SUB_PROTO_DOMAIN) { | |||||
/* the IPv6 reassembly hash has or will soon be destroyed */ | |||||
return; | |||||
} | |||||
Done Inline ActionsI'd remove the two blank lines (also above this one). bz: I'd remove the two blank lines (also above this one). | |||||
#endif | |||||
CURVNET_SET_QUIET(ifp->if_vnet); | |||||
for (i = 0; i < IP6REASS_NHASH; i++) { | |||||
IP6Q_LOCK(i); | |||||
head = IP6Q_HEAD(i); | |||||
/* Scan fragment list. */ | |||||
for (q6 = head->ip6q_next; q6 != head; q6 = q6n) { | |||||
q6n = q6->ip6q_next; | |||||
Done Inline ActionsAgain, please declare at the top and then you can just use it here without the blank line. bz: Again, please declare at the top and then you can just use it here without the blank line. | |||||
for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; | |||||
af6 = af6->ip6af_down) { | |||||
m = IP6_REASS_MBUF(af6); | |||||
if (m->m_pkthdr.rcvif == ifp) { | |||||
IP6STAT_INC(ip6s_fragdropped); | |||||
frag6_freef(q6, i, false); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
IP6Q_UNLOCK(i); | |||||
} | |||||
CURVNET_RESTORE(); | |||||
} | |||||
EVENTHANDLER_DEFINE(ifnet_departure_event, frag6_cleanup, NULL, 0); | |||||
int | int | ||||
ip6_deletefraghdr(struct mbuf *m, int offset, int wait) | ip6_deletefraghdr(struct mbuf *m, int offset, int wait) | ||||
{ | { | ||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); | ||||
struct mbuf *t; | struct mbuf *t; | ||||
/* Delete frag6 header. */ | /* Delete frag6 header. */ | ||||
Show All 17 Lines |
could be bool and then you could use true/false.