Index: lib/libpfctl/libpfctl.c =================================================================== --- lib/libpfctl/libpfctl.c +++ lib/libpfctl/libpfctl.c @@ -709,19 +709,42 @@ pfctl_get_states(int dev, struct pfctl_states *states) { struct pfioc_nv nv; - nvlist_t *nvl = NULL; + nvlist_t *nvl = NULL, *nvl_req = NULL; + void *nvlpacked; const nvlist_t * const *slist; size_t found_count; int error = 0; + uint64_t start_row, row_count, stride; + size_t sr; + + start_row = 0; + sr = sizeof(row_count); + if (sysctlbyname("net.pf.states_hashsize", &row_count, &sr, NULL, 0) == + -1) + return (errno); + + /* Grab a tenth of the table at a time. */ + stride = row_count / 10; bzero(states, sizeof(*states)); TAILQ_INIT(&states->states); /* Just enough to get a number, and we'll grow from there. */ - nv.data = malloc(64); - nv.len = nv.size = 64; + nv.data = malloc(128); + nv.len = nv.size = 128; for (;;) { + nvl_req = nvlist_create(0); + nvlist_add_number(nvl_req, "start_row", start_row); + nvlist_add_number(nvl_req, "end_row", MIN(start_row + stride, + row_count - 1)); + + nvlpacked = nvlist_pack(nvl_req, &nv.len); + assert(nv.len <= nv.size); + memcpy(nv.data, nvlpacked, nv.len); + nvlist_destroy(nvl_req); + free(nvlpacked); + if (ioctl(dev, DIOCGETSTATESNV, &nv)) { error = errno; goto out; @@ -737,10 +760,11 @@ /* Are there any states? */ if (states->count == 0) - break; + goto next_row; if (nvlist_exists_nvlist_array(nvl, "states")) - slist = nvlist_get_nvlist_array(nvl, "states", &found_count); + slist = nvlist_get_nvlist_array(nvl, "states", + &found_count); else found_count = 0; @@ -776,7 +800,15 @@ pf_nvstate_to_state(slist[i], s); TAILQ_INSERT_TAIL(&states->states, s, entry); } - break; + +next_row: + assert(nvlist_get_number(nvl, "start_row") == start_row); + /* It's possible the kernel didn't give us as many rows as we + * asked for, if we didn't give it a big enough buffer. */ + start_row = nvlist_get_number(nvl, "end_row") + 1; + + if (start_row >= row_count) + break; } out: