| 2246 | } |
| 2247 | |
| 2248 | static int |
| 2249 | tcp_pcblist(SYSCTL_HANDLER_ARGS) |
| 2250 | { |
| 2251 | struct epoch_tracker et; |
| 2252 | struct inpcb *inp; |
| 2253 | struct xinpgen xig; |
| 2254 | int error; |
| 2255 | |
| 2256 | if (req->newptr != NULL) |
| 2257 | return (EPERM); |
| 2258 | |
| 2259 | if (req->oldptr == NULL) { |
| 2260 | int n; |
| 2261 | |
| 2262 | n = V_tcbinfo.ipi_count + |
| 2263 | counter_u64_fetch(V_tcps_states[TCPS_SYN_RECEIVED]); |
| 2264 | n += imax(n / 8, 10); |
| 2265 | req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xtcpcb); |
| 2266 | return (0); |
| 2267 | } |
| 2268 | |
| 2269 | if ((error = sysctl_wire_old_buffer(req, 0)) != 0) |
| 2270 | return (error); |
| 2271 | |
| 2272 | bzero(&xig, sizeof(xig)); |
| 2273 | xig.xig_len = sizeof xig; |
| 2274 | xig.xig_count = V_tcbinfo.ipi_count + |
| 2275 | counter_u64_fetch(V_tcps_states[TCPS_SYN_RECEIVED]); |
| 2276 | xig.xig_gen = V_tcbinfo.ipi_gencnt; |
| 2277 | xig.xig_sogen = so_gencnt; |
| 2278 | error = SYSCTL_OUT(req, &xig, sizeof xig); |
| 2279 | if (error) |
| 2280 | return (error); |
| 2281 | |
| 2282 | error = syncache_pcblist(req); |
| 2283 | if (error) |
| 2284 | return (error); |
| 2285 | |
| 2286 | NET_EPOCH_ENTER(et); |
| 2287 | for (inp = CK_LIST_FIRST(V_tcbinfo.ipi_listhead); |
| 2288 | inp != NULL; |
| 2289 | inp = CK_LIST_NEXT(inp, inp_list)) { |
| 2290 | INP_RLOCK(inp); |
| 2291 | if (inp->inp_gencnt <= xig.xig_gen) { |
| 2292 | int crerr; |
| 2293 | |
| 2294 | /* |
| 2295 | * XXX: This use of cr_cansee(), introduced with |
| 2296 | * TCP state changes, is not quite right, but for |
| 2297 | * now, better than nothing. |
| 2298 | */ |
| 2299 | if (inp->inp_flags & INP_TIMEWAIT) { |
| 2300 | if (intotw(inp) != NULL) |
| 2301 | crerr = cr_cansee(req->td->td_ucred, |
| 2302 | intotw(inp)->tw_cred); |
| 2303 | else |
| 2304 | crerr = EINVAL; /* Skip this inp. */ |
| 2305 | } else |
nothing calls this directly
no test coverage detected