Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/frag6.c
Show First 20 Lines • Show All 74 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); | ||||
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; | ||||
}; | }; | ||||
static MALLOC_DEFINE(M_FRAG6, "frag6", "IPv6 fragment reassembly header"); | static MALLOC_DEFINE(M_FRAG6, "frag6", "IPv6 fragment reassembly header"); | ||||
▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; | ||||
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 && m->m_pkthdr.rcvif != NULL) { | ||||
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 All 9 Lines | |||||
#ifdef MAC | #ifdef MAC | ||||
mac_ip6q_destroy(q6); | mac_ip6q_destroy(q6); | ||||
#endif | #endif | ||||
free(q6, M_FRAG6); | free(q6, M_FRAG6); | ||||
atomic_subtract_int(&V_frag6_nfragpackets, 1); | atomic_subtract_int(&V_frag6_nfragpackets, 1); | ||||
} | } | ||||
/* | /* | ||||
* 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; | |||||
KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); | |||||
#ifdef VIMAGE | |||||
if (!vnet_is_running(ifp->if_vnet)) { | |||||
/* the IPv6 reassembly hash is destroyed */ | |||||
return; | |||||
} | |||||
#endif | |||||
CURVNET_SET_QUIET(ifp->if_vnet); | |||||
for (i = 0; i < IP6REASS_NHASH; i++) { | |||||
IP6QB_LOCK(i); | |||||
head = IP6QB_HEAD(i); | |||||
/* Scan fragment list. */ | |||||
for (q6 = head->ip6q_next; q6 != head; q6 = q6n) { | |||||
q6n = q6->ip6q_next; | |||||
for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; | |||||
af6 = af6->ip6af_down) { | |||||
m = IP6_REASS_MBUF(af6); | |||||
/* clear no longer valid rcvif pointer */ | |||||
if (m->m_pkthdr.rcvif == ifp) | |||||
m->m_pkthdr.rcvif = NULL; | |||||
} | |||||
} | |||||
IP6QB_UNLOCK(i); | |||||
} | |||||
CURVNET_RESTORE(); | |||||
} | |||||
EVENTHANDLER_DEFINE(ifnet_departure_event, frag6_cleanup, NULL, 0); | |||||
/* | |||||
* In RFC2460, fragment and reassembly rule do not agree with each other, | * In RFC2460, fragment and reassembly rule do not agree with each other, | ||||
* in terms of next header field handling in fragment header. | * in terms of next header field handling in fragment header. | ||||
* While the sender will use the same value for all of the fragmented packets, | * While the sender will use the same value for all of the fragmented packets, | ||||
* receiver is suggested not to check the consistency. | * receiver is suggested not to check the consistency. | ||||
* | * | ||||
* fragment rule (p20): | * fragment rule (p20): | ||||
* (2) A Fragment header containing: | * (2) A Fragment header containing: | ||||
* The Next Header value that identifies the first header of | * The Next Header value that identifies the first header of | ||||
Show All 31 Lines | frag6_input(struct mbuf **mp, int *offp, int proto) | ||||
struct in6_ifaddr *ia; | struct in6_ifaddr *ia; | ||||
int offset = *offp, nxt, i, next; | int offset = *offp, nxt, i, next; | ||||
int first_frag = 0; | int first_frag = 0; | ||||
int fragoff, frgpartlen; /* must be larger than u_int16_t */ | int fragoff, frgpartlen; /* must be larger than u_int16_t */ | ||||
uint32_t hashkey[(sizeof(struct in6_addr) * 2 + | uint32_t hashkey[(sizeof(struct in6_addr) * 2 + | ||||
sizeof(ip6f->ip6f_ident)) / sizeof(uint32_t)]; | sizeof(ip6f->ip6f_ident)) / sizeof(uint32_t)]; | ||||
uint32_t bucket, *hashkeyp; | uint32_t bucket, *hashkeyp; | ||||
struct ifnet *dstifp; | struct ifnet *dstifp; | ||||
struct ifnet *srcifp; | |||||
u_int8_t ecn, ecn0; | u_int8_t ecn, ecn0; | ||||
#ifdef RSS | #ifdef RSS | ||||
struct m_tag *mtag; | struct m_tag *mtag; | ||||
struct ip6_direct_ctx *ip6dc; | struct ip6_direct_ctx *ip6dc; | ||||
#endif | #endif | ||||
ip6 = mtod(m, struct ip6_hdr *); | ip6 = mtod(m, struct ip6_hdr *); | ||||
#ifndef PULLDOWN_TEST | #ifndef PULLDOWN_TEST | ||||
IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE); | IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE); | ||||
ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset); | ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset); | ||||
#else | #else | ||||
IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f)); | IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f)); | ||||
if (ip6f == NULL) | if (ip6f == NULL) | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
#endif | #endif | ||||
/* | |||||
* Store receive network interface pointer for later. | |||||
*/ | |||||
srcifp = m->m_pkthdr.rcvif; | |||||
dstifp = NULL; | dstifp = NULL; | ||||
/* find the destination interface of the packet. */ | /* find the destination interface of the packet. */ | ||||
ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); | ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); | ||||
if (ia != NULL) { | if (ia != NULL) { | ||||
dstifp = ia->ia_ifp; | dstifp = ia->ia_ifp; | ||||
ifa_free(&ia->ia_ifa); | ifa_free(&ia->ia_ifa); | ||||
} | } | ||||
/* jumbo payload can't contain a fragment header */ | /* jumbo payload can't contain a fragment header */ | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; | ||||
struct mbuf *merr = IP6_REASS_MBUF(af6); | struct mbuf *merr = IP6_REASS_MBUF(af6); | ||||
struct ip6_hdr *ip6err; | struct ip6_hdr *ip6err; | ||||
int erroff = af6->ip6af_offset; | int erroff = af6->ip6af_offset; | ||||
/* dequeue the fragment. */ | /* dequeue the fragment. */ | ||||
frag6_deq(af6, bucket); | frag6_deq(af6, bucket); | ||||
free(af6, M_FRAG6); | free(af6, M_FRAG6); | ||||
/* set valid receive interface pointer */ | |||||
merr->m_pkthdr.rcvif = srcifp; | |||||
/* adjust pointer. */ | /* adjust pointer. */ | ||||
ip6err = mtod(merr, struct ip6_hdr *); | ip6err = mtod(merr, struct ip6_hdr *); | ||||
/* | /* | ||||
* Restore source and destination addresses | * Restore source and destination addresses | ||||
* in the erroneous IPv6 header. | * in the erroneous IPv6 header. | ||||
*/ | */ | ||||
ip6err->ip6_src = q6->ip6q_src; | ip6err->ip6_src = q6->ip6q_src; | ||||
▲ Show 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | #endif | ||||
free(q6, M_FRAG6); | free(q6, M_FRAG6); | ||||
atomic_subtract_int(&V_frag6_nfragpackets, 1); | atomic_subtract_int(&V_frag6_nfragpackets, 1); | ||||
if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */ | if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */ | ||||
int plen = 0; | int plen = 0; | ||||
for (t = m; t; t = t->m_next) | for (t = m; t; t = t->m_next) | ||||
plen += t->m_len; | plen += t->m_len; | ||||
m->m_pkthdr.len = plen; | m->m_pkthdr.len = plen; | ||||
/* set valid receive interface pointer */ | |||||
m->m_pkthdr.rcvif = srcifp; | |||||
} | } | ||||
#ifdef RSS | #ifdef RSS | ||||
mtag = m_tag_alloc(MTAG_ABI_IPV6, IPV6_TAG_DIRECT, sizeof(*ip6dc), | mtag = m_tag_alloc(MTAG_ABI_IPV6, IPV6_TAG_DIRECT, sizeof(*ip6dc), | ||||
M_NOWAIT); | M_NOWAIT); | ||||
if (mtag == NULL) | if (mtag == NULL) | ||||
goto dropfrag; | goto dropfrag; | ||||
▲ Show 20 Lines • Show All 191 Lines • ▼ Show 20 Lines | |||||
* Like insque, but pointers in middle of structure. | * Like insque, but pointers in middle of structure. | ||||
*/ | */ | ||||
static void | static void | ||||
frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6, | frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6, | ||||
uint32_t bucket __unused) | uint32_t bucket __unused) | ||||
{ | { | ||||
IP6QB_LOCK_ASSERT(bucket); | IP6QB_LOCK_ASSERT(bucket); | ||||
Done Inline ActionsYou can fold these three into one line. bz: You can fold these three into one line. | |||||
af6->ip6af_up = up6; | af6->ip6af_up = up6; | ||||
af6->ip6af_down = up6->ip6af_down; | af6->ip6af_down = up6->ip6af_down; | ||||
Done Inline ActionsPlease add a KASSERT that ifp is not NULL bz: Please add a KASSERT that ifp is not NULL | |||||
up6->ip6af_down->ip6af_up = af6; | up6->ip6af_down->ip6af_up = af6; | ||||
up6->ip6af_down = af6; | up6->ip6af_down = af6; | ||||
} | } | ||||
/* | /* | ||||
* To frag6_enq as remque is to insque. | * To frag6_enq as remque is to insque. | ||||
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). | |||||
*/ | */ | ||||
static void | static void | ||||
frag6_deq(struct ip6asfrag *af6, uint32_t bucket __unused) | frag6_deq(struct ip6asfrag *af6, uint32_t bucket __unused) | ||||
{ | { | ||||
IP6QB_LOCK_ASSERT(bucket); | IP6QB_LOCK_ASSERT(bucket); | ||||
af6->ip6af_up->ip6af_down = af6->ip6af_down; | af6->ip6af_up->ip6af_down = af6->ip6af_down; | ||||
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. | |||||
af6->ip6af_down->ip6af_up = af6->ip6af_up; | af6->ip6af_down->ip6af_up = af6->ip6af_up; | ||||
} | } | ||||
static void | static void | ||||
frag6_insque_head(struct ip6q *new, struct ip6q *old, uint32_t bucket) | frag6_insque_head(struct ip6q *new, struct ip6q *old, uint32_t bucket) | ||||
{ | { | ||||
IP6QB_LOCK_ASSERT(bucket); | IP6QB_LOCK_ASSERT(bucket); | ||||
Show All 21 Lines |
could be bool and then you could use true/false.