Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/pf/pf_ioctl.c
Show First 20 Lines • Show All 5,048 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
pf_getstates(struct pfioc_nv *nv) | pf_getstates(struct pfioc_nv *nv) | ||||
{ | { | ||||
nvlist_t *nvl = NULL, *nvls; | nvlist_t *nvl = NULL, *nvls; | ||||
void *nvlpacked = NULL; | void *nvlpacked = NULL; | ||||
struct pf_state *s = NULL; | struct pf_state *s = NULL; | ||||
int error = 0; | |||||
uint64_t count = 0; | uint64_t count = 0; | ||||
uint64_t start_row, token; | |||||
int error = 0; | |||||
int i; | |||||
#define ERROUT(x) ERROUT_FUNCTION(errout, x) | #define ERROUT(x) ERROUT_FUNCTION(errout, x) | ||||
start_row = 0; | |||||
/* Optional paging support. */ | |||||
if (nv->len > 0) { | |||||
if (nv->len > pf_ioctl_maxcount) | |||||
ERROUT(ENOMEM); | |||||
nvlpacked = malloc(nv->len, M_NVLIST, M_WAITOK); | |||||
error = copyin(nv->data, nvlpacked, nv->len); | |||||
if (error) | |||||
ERROUT(error); | |||||
nvl = nvlist_unpack(nvlpacked, nv->len, 0); | |||||
if (nvl != NULL) | |||||
start_row = nvlist_get_number(nvl, "token"); | |||||
nvlist_destroy(nvl); | |||||
nvl = NULL; | |||||
if (start_row > pf_hashmask) | |||||
ERROUT(EINVAL); | |||||
} | |||||
nvl = nvlist_create(0); | nvl = nvlist_create(0); | ||||
if (nvl == NULL) | if (nvl == NULL) | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
nvlist_add_number(nvl, "count", uma_zone_get_cur(V_pf_state_z)); | token = start_row; | ||||
for (i = start_row; i < pf_hashmask; i++) { | |||||
for (int i = 0; i < pf_hashmask; i++) { | |||||
struct pf_idhash *ih = &V_pf_idhash[i]; | struct pf_idhash *ih = &V_pf_idhash[i]; | ||||
int elements = 0; | |||||
/* Avoid taking the lock if there are no states in the row. */ | /* Avoid taking the lock if there are no states in the row. */ | ||||
if (LIST_EMPTY(&ih->states)) | if (LIST_EMPTY(&ih->states)) { | ||||
token = i + 1; | |||||
continue; | continue; | ||||
} | |||||
PF_HASHROW_LOCK(ih); | PF_HASHROW_LOCK(ih); | ||||
/* Count the states and estimate if we can fit this in the | |||||
* remaining space. */ | |||||
LIST_FOREACH(s, &ih->states, entry) | |||||
elements++; | |||||
/* If the next entire row wouldn't fit stop here. */ | |||||
if ((nvlist_size(nvl) + (2048 * elements)) > nv->size) { | |||||
PF_HASHROW_UNLOCK(ih); | |||||
count += elements; | |||||
break; | |||||
} | |||||
LIST_FOREACH(s, &ih->states, entry) { | LIST_FOREACH(s, &ih->states, entry) { | ||||
if (s->timeout == PFTM_UNLINKED) | if (s->timeout == PFTM_UNLINKED) | ||||
continue; | continue; | ||||
if (SIGPENDING(curthread)) { | if (SIGPENDING(curthread)) { | ||||
PF_HASHROW_UNLOCK(ih); | PF_HASHROW_UNLOCK(ih); | ||||
ERROUT(EINTR); | ERROUT(EINTR); | ||||
} | } | ||||
nvls = pf_state_to_nvstate(s); | nvls = pf_state_to_nvstate(s); | ||||
if (nvls == NULL) { | if (nvls == NULL) { | ||||
PF_HASHROW_UNLOCK(ih); | PF_HASHROW_UNLOCK(ih); | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
} | } | ||||
if ((nvlist_size(nvl) + nvlist_size(nvls)) > nv->size) { | MPASS(nvlist_size(nvls) < 2048); | ||||
/* We've run out of room for more states. */ | MPASS(nv->size >= (nvlist_size(nvl) + | ||||
nvlist_destroy(nvls); | nvlist_size(nvls))); | ||||
PF_HASHROW_UNLOCK(ih); | |||||
goto DIOCGETSTATESNV_full; | |||||
} | |||||
nvlist_append_nvlist_array(nvl, "states", nvls); | nvlist_append_nvlist_array(nvl, "states", nvls); | ||||
nvlist_destroy(nvls); | nvlist_destroy(nvls); | ||||
count++; | count++; | ||||
} | } | ||||
PF_HASHROW_UNLOCK(ih); | PF_HASHROW_UNLOCK(ih); | ||||
token = i + 1; | |||||
} | } | ||||
/* We've managed to put them all the available space. Let's make sure | nvlist_add_bool(nvl, "done", token == pf_hashmask); | ||||
* 'count' matches our array (that's racy, because we don't hold a lock | nvlist_add_number(nvl, "token", token); | ||||
* over all states, only over each row individually. */ | |||||
(void)nvlist_take_number(nvl, "count"); | |||||
nvlist_add_number(nvl, "count", count); | nvlist_add_number(nvl, "count", count); | ||||
DIOCGETSTATESNV_full: | free(nvlpacked, M_NVLIST); | ||||
nvlpacked = nvlist_pack(nvl, &nv->len); | nvlpacked = nvlist_pack(nvl, &nv->len); | ||||
if (nvlpacked == NULL) | if (nvlpacked == NULL) | ||||
ERROUT(ENOMEM); | ERROUT(ENOMEM); | ||||
if (nv->size == 0) | if (nv->size == 0) | ||||
ERROUT(0); | ERROUT(0); | ||||
else if (nv->size < nv->len) | else if (nv->size < nv->len) | ||||
ERROUT(ENOSPC); | ERROUT(ENOSPC); | ||||
▲ Show 20 Lines • Show All 453 Lines • Show Last 20 Lines |