Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netpfil/pf/pf_norm.c
Show First 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | |||||
struct pf_fragment { | struct pf_fragment { | ||||
struct pf_fragment_cmp fr_key; | struct pf_fragment_cmp fr_key; | ||||
#define fr_src fr_key.frc_src | #define fr_src fr_key.frc_src | ||||
#define fr_dst fr_key.frc_dst | #define fr_dst fr_key.frc_dst | ||||
#define fr_id fr_key.frc_id | #define fr_id fr_key.frc_id | ||||
#define fr_af fr_key.frc_af | #define fr_af fr_key.frc_af | ||||
#define fr_proto fr_key.frc_proto | #define fr_proto fr_key.frc_proto | ||||
/* pointers to queue element */ | |||||
struct pf_frent *fr_firstoff[PF_FRAG_ENTRY_POINTS]; | struct pf_frent *fr_firstoff[PF_FRAG_ENTRY_POINTS]; | ||||
/* count entries between pointers */ | |||||
uint8_t fr_entries[PF_FRAG_ENTRY_POINTS]; | |||||
RB_ENTRY(pf_fragment) fr_entry; | RB_ENTRY(pf_fragment) fr_entry; | ||||
TAILQ_ENTRY(pf_fragment) frag_next; | TAILQ_ENTRY(pf_fragment) frag_next; | ||||
uint32_t fr_timeout; | uint32_t fr_timeout; | ||||
uint16_t fr_maxlen; /* maximum length of single fragment */ | uint16_t fr_maxlen; /* maximum length of single fragment */ | ||||
u_int16_t fr_holes; /* number of holes in the queue */ | u_int16_t fr_holes; /* number of holes in the queue */ | ||||
TAILQ_HEAD(pf_fragq, pf_frent) fr_queue; | TAILQ_HEAD(pf_fragq, pf_frent) fr_queue; | ||||
}; | }; | ||||
Show All 34 Lines | |||||
static void pf_remove_fragment(struct pf_fragment *); | static void pf_remove_fragment(struct pf_fragment *); | ||||
static int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *, | static int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *, | ||||
struct tcphdr *, int, sa_family_t); | struct tcphdr *, int, sa_family_t); | ||||
static struct pf_frent *pf_create_fragment(u_short *); | static struct pf_frent *pf_create_fragment(u_short *); | ||||
static int pf_frent_holes(struct pf_frent *frent); | static int pf_frent_holes(struct pf_frent *frent); | ||||
static struct pf_fragment *pf_find_fragment(struct pf_fragment_cmp *key, | static struct pf_fragment *pf_find_fragment(struct pf_fragment_cmp *key, | ||||
struct pf_frag_tree *tree); | struct pf_frag_tree *tree); | ||||
static inline int pf_frent_index(struct pf_frent *); | static inline int pf_frent_index(struct pf_frent *); | ||||
static void pf_frent_insert(struct pf_fragment *, | static int pf_frent_insert(struct pf_fragment *, | ||||
struct pf_frent *, struct pf_frent *); | struct pf_frent *, struct pf_frent *); | ||||
void pf_frent_remove(struct pf_fragment *, | void pf_frent_remove(struct pf_fragment *, | ||||
struct pf_frent *); | struct pf_frent *); | ||||
struct pf_frent *pf_frent_previous(struct pf_fragment *, | struct pf_frent *pf_frent_previous(struct pf_fragment *, | ||||
struct pf_frent *); | struct pf_frent *); | ||||
static struct pf_fragment *pf_fillup_fragment(struct pf_fragment_cmp *, | static struct pf_fragment *pf_fillup_fragment(struct pf_fragment_cmp *, | ||||
struct pf_frent *, u_short *); | struct pf_frent *, u_short *); | ||||
static struct mbuf *pf_join_fragment(struct pf_fragment *); | static struct mbuf *pf_join_fragment(struct pf_fragment *); | ||||
▲ Show 20 Lines • Show All 237 Lines • ▼ Show 20 Lines | pf_frent_index(struct pf_frent *frent) | ||||
*/ | */ | ||||
CTASSERT(((u_int16_t)0xffff &~ 7) / (0x10000 / PF_FRAG_ENTRY_POINTS) == | CTASSERT(((u_int16_t)0xffff &~ 7) / (0x10000 / PF_FRAG_ENTRY_POINTS) == | ||||
16 - 1); | 16 - 1); | ||||
CTASSERT(((u_int16_t)0xffff >> 3) / PF_FRAG_ENTRY_POINTS == 512 - 1); | CTASSERT(((u_int16_t)0xffff >> 3) / PF_FRAG_ENTRY_POINTS == 512 - 1); | ||||
return frent->fe_off / (0x10000 / PF_FRAG_ENTRY_POINTS); | return frent->fe_off / (0x10000 / PF_FRAG_ENTRY_POINTS); | ||||
} | } | ||||
static void | static int | ||||
pf_frent_insert(struct pf_fragment *frag, struct pf_frent *frent, | pf_frent_insert(struct pf_fragment *frag, struct pf_frent *frent, | ||||
struct pf_frent *prev) | struct pf_frent *prev) | ||||
{ | { | ||||
int index; | int index; | ||||
CTASSERT(PF_FRAG_ENTRY_LIMIT <= 0xff); | |||||
/* | |||||
* A packet has at most 65536 octets. With 16 entry points, each one | |||||
* spawns 4096 octets. We limit these to 64 fragments each, which | |||||
* means on average every fragment must have at least 64 octets. | |||||
*/ | |||||
index = pf_frent_index(frent); | |||||
if (frag->fr_entries[index] >= PF_FRAG_ENTRY_LIMIT) | |||||
return ENOBUFS; | |||||
frag->fr_entries[index]++; | |||||
if (prev == NULL) { | if (prev == NULL) { | ||||
TAILQ_INSERT_HEAD(&frag->fr_queue, frent, fr_next); | TAILQ_INSERT_HEAD(&frag->fr_queue, frent, fr_next); | ||||
} else { | } else { | ||||
KASSERT(prev->fe_off + prev->fe_len <= frent->fe_off, | KASSERT(prev->fe_off + prev->fe_len <= frent->fe_off, | ||||
("overlapping fragment")); | ("overlapping fragment")); | ||||
TAILQ_INSERT_AFTER(&frag->fr_queue, prev, frent, fr_next); | TAILQ_INSERT_AFTER(&frag->fr_queue, prev, frent, fr_next); | ||||
} | } | ||||
index = pf_frent_index(frent); | |||||
if (frag->fr_firstoff[index] == NULL) { | if (frag->fr_firstoff[index] == NULL) { | ||||
KASSERT(prev == NULL || pf_frent_index(prev) < index, | KASSERT(prev == NULL || pf_frent_index(prev) < index, | ||||
("prev == NULL || pf_frent_index(pref) < index")); | ("prev == NULL || pf_frent_index(pref) < index")); | ||||
frag->fr_firstoff[index] = frent; | frag->fr_firstoff[index] = frent; | ||||
} else { | } else { | ||||
if (frent->fe_off < frag->fr_firstoff[index]->fe_off) { | if (frent->fe_off < frag->fr_firstoff[index]->fe_off) { | ||||
KASSERT(prev == NULL || pf_frent_index(prev) < index, | KASSERT(prev == NULL || pf_frent_index(prev) < index, | ||||
("prev == NULL || pf_frent_index(pref) < index")); | ("prev == NULL || pf_frent_index(pref) < index")); | ||||
frag->fr_firstoff[index] = frent; | frag->fr_firstoff[index] = frent; | ||||
} else { | } else { | ||||
KASSERT(prev != NULL, ("prev != NULL")); | KASSERT(prev != NULL, ("prev != NULL")); | ||||
KASSERT(pf_frent_index(prev) == index, | KASSERT(pf_frent_index(prev) == index, | ||||
("pf_frent_index(prev) == index")); | ("pf_frent_index(prev) == index")); | ||||
} | } | ||||
} | } | ||||
frag->fr_holes += pf_frent_holes(frent); | frag->fr_holes += pf_frent_holes(frent); | ||||
return 0; | |||||
} | } | ||||
void | void | ||||
pf_frent_remove(struct pf_fragment *frag, struct pf_frent *frent) | pf_frent_remove(struct pf_fragment *frag, struct pf_frent *frent) | ||||
{ | { | ||||
struct pf_frent *prev = TAILQ_PREV(frent, pf_fragq, fr_next); | struct pf_frent *prev = TAILQ_PREV(frent, pf_fragq, fr_next); | ||||
struct pf_frent *next = TAILQ_NEXT(frent, fr_next); | struct pf_frent *next = TAILQ_NEXT(frent, fr_next); | ||||
int index; | int index; | ||||
Show All 20 Lines | if (frag->fr_firstoff[index]->fe_off == frent->fe_off) { | ||||
KASSERT(prev != NULL, ("prev != NULL")); | KASSERT(prev != NULL, ("prev != NULL")); | ||||
KASSERT(prev->fe_off + prev->fe_len <= frent->fe_off, | KASSERT(prev->fe_off + prev->fe_len <= frent->fe_off, | ||||
("overlapping fragment")); | ("overlapping fragment")); | ||||
KASSERT(pf_frent_index(prev) == index, | KASSERT(pf_frent_index(prev) == index, | ||||
("pf_frent_index(prev) == index")); | ("pf_frent_index(prev) == index")); | ||||
} | } | ||||
TAILQ_REMOVE(&frag->fr_queue, frent, fr_next); | TAILQ_REMOVE(&frag->fr_queue, frent, fr_next); | ||||
KASSERT(frag->fr_entries[index] > 0, ("No fragments remaining")); | |||||
frag->fr_entries[index]--; | |||||
} | } | ||||
struct pf_frent * | struct pf_frent * | ||||
pf_frent_previous(struct pf_fragment *frag, struct pf_frent *frent) | pf_frent_previous(struct pf_fragment *frag, struct pf_frent *frent) | ||||
{ | { | ||||
struct pf_frent *prev, *next; | struct pf_frent *prev, *next; | ||||
int index; | int index; | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | if (frag == NULL) { | ||||
if (frag == NULL) { | if (frag == NULL) { | ||||
REASON_SET(reason, PFRES_MEMORY); | REASON_SET(reason, PFRES_MEMORY); | ||||
goto drop_fragment; | goto drop_fragment; | ||||
} | } | ||||
} | } | ||||
*(struct pf_fragment_cmp *)frag = *key; | *(struct pf_fragment_cmp *)frag = *key; | ||||
memset(frag->fr_firstoff, 0, sizeof(frag->fr_firstoff)); | memset(frag->fr_firstoff, 0, sizeof(frag->fr_firstoff)); | ||||
memset(frag->fr_entries, 0, sizeof(frag->fr_entries)); | |||||
frag->fr_timeout = time_uptime; | frag->fr_timeout = time_uptime; | ||||
frag->fr_maxlen = frent->fe_len; | frag->fr_maxlen = frent->fe_len; | ||||
frag->fr_holes = 1; | frag->fr_holes = 1; | ||||
TAILQ_INIT(&frag->fr_queue); | TAILQ_INIT(&frag->fr_queue); | ||||
RB_INSERT(pf_frag_tree, &V_pf_frag_tree, frag); | RB_INSERT(pf_frag_tree, &V_pf_frag_tree, frag); | ||||
TAILQ_INSERT_HEAD(&V_pf_fragqueue, frag, frag_next); | TAILQ_INSERT_HEAD(&V_pf_fragqueue, frag, frag_next); | ||||
/* We do not have a previous fragment. */ | /* We do not have a previous fragment, cannot fail. */ | ||||
pf_frent_insert(frag, frent, NULL); | pf_frent_insert(frag, frent, NULL); | ||||
return (frag); | return (frag); | ||||
} | } | ||||
KASSERT(!TAILQ_EMPTY(&frag->fr_queue), ("!TAILQ_EMPTY()->fr_queue")); | KASSERT(!TAILQ_EMPTY(&frag->fr_queue), ("!TAILQ_EMPTY()->fr_queue")); | ||||
/* Remember maximum fragment len for refragmentation. */ | /* Remember maximum fragment len for refragmentation. */ | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | for (; after != NULL && frent->fe_off + frent->fe_len > after->fe_off; | ||||
/* This fragment is completely overlapped, lose it. */ | /* This fragment is completely overlapped, lose it. */ | ||||
next = TAILQ_NEXT(after, fr_next); | next = TAILQ_NEXT(after, fr_next); | ||||
pf_frent_remove(frag, after); | pf_frent_remove(frag, after); | ||||
m_freem(after->fe_m); | m_freem(after->fe_m); | ||||
uma_zfree(V_pf_frent_z, after); | uma_zfree(V_pf_frent_z, after); | ||||
} | } | ||||
pf_frent_insert(frag, frent, prev); | /* If part of the queue gets too long, there is not way to recover. */ | ||||
if (pf_frent_insert(frag, frent, prev)) { | |||||
DPFPRINTF(("fragment queue limit exceeded")); | |||||
goto bad_fragment; | |||||
} | |||||
return (frag); | return (frag); | ||||
bad_fragment: | bad_fragment: | ||||
REASON_SET(reason, PFRES_FRAG); | REASON_SET(reason, PFRES_FRAG); | ||||
drop_fragment: | drop_fragment: | ||||
uma_zfree(V_pf_frent_z, frent); | uma_zfree(V_pf_frent_z, frent); | ||||
return (NULL); | return (NULL); | ||||
▲ Show 20 Lines • Show All 1,346 Lines • Show Last 20 Lines |