Deleted Added
full compact
ip_divert.c (180851) ip_divert.c (181803)
1/*-
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 14 unchanged lines hidden (view full) ---

23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1982, 1986, 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 14 unchanged lines hidden (view full) ---

23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/netinet/ip_divert.c 180851 2008-07-27 20:48:22Z mav $");
31__FBSDID("$FreeBSD: head/sys/netinet/ip_divert.c 181803 2008-08-17 23:27:27Z bz $");
32
33#if !defined(KLD_MODULE)
34#include "opt_inet.h"
35#include "opt_ipfw.h"
36#include "opt_mac.h"
37#ifndef INET
38#error "IPDIVERT requires INET."
39#endif

--- 13 unchanged lines hidden (view full) ---

53#include <sys/proc.h>
54#include <sys/protosw.h>
55#include <sys/signalvar.h>
56#include <sys/socket.h>
57#include <sys/socketvar.h>
58#include <sys/sx.h>
59#include <sys/sysctl.h>
60#include <sys/systm.h>
32
33#if !defined(KLD_MODULE)
34#include "opt_inet.h"
35#include "opt_ipfw.h"
36#include "opt_mac.h"
37#ifndef INET
38#error "IPDIVERT requires INET."
39#endif

--- 13 unchanged lines hidden (view full) ---

53#include <sys/proc.h>
54#include <sys/protosw.h>
55#include <sys/signalvar.h>
56#include <sys/socket.h>
57#include <sys/socketvar.h>
58#include <sys/sx.h>
59#include <sys/sysctl.h>
60#include <sys/systm.h>
61#include <sys/vimage.h>
61
62#include <vm/uma.h>
63
64#include <net/if.h>
65#include <net/netisr.h>
66#include <net/route.h>
67
68#include <netinet/in.h>

--- 50 unchanged lines hidden (view full) ---

119
120/*
121 * Initialize divert connection block queue.
122 */
123static void
124div_zone_change(void *tag)
125{
126
62
63#include <vm/uma.h>
64
65#include <net/if.h>
66#include <net/netisr.h>
67#include <net/route.h>
68
69#include <netinet/in.h>

--- 50 unchanged lines hidden (view full) ---

120
121/*
122 * Initialize divert connection block queue.
123 */
124static void
125div_zone_change(void *tag)
126{
127
127 uma_zone_set_max(divcbinfo.ipi_zone, maxsockets);
128 uma_zone_set_max(V_divcbinfo.ipi_zone, maxsockets);
128}
129
130static int
131div_inpcb_init(void *mem, int size, int flags)
132{
133 struct inpcb *inp = mem;
134
135 INP_LOCK_INIT(inp, "inp", "divinp");

--- 7 unchanged lines hidden (view full) ---

143
144 INP_LOCK_DESTROY(inp);
145}
146
147void
148div_init(void)
149{
150
129}
130
131static int
132div_inpcb_init(void *mem, int size, int flags)
133{
134 struct inpcb *inp = mem;
135
136 INP_LOCK_INIT(inp, "inp", "divinp");

--- 7 unchanged lines hidden (view full) ---

144
145 INP_LOCK_DESTROY(inp);
146}
147
148void
149div_init(void)
150{
151
151 INP_INFO_LOCK_INIT(&divcbinfo, "div");
152 LIST_INIT(&divcb);
153 divcbinfo.ipi_listhead = &divcb;
152 INP_INFO_LOCK_INIT(&V_divcbinfo, "div");
153 LIST_INIT(&V_divcb);
154 V_divcbinfo.ipi_listhead = &V_divcb;
154 /*
155 * XXX We don't use the hash list for divert IP, but it's easier
156 * to allocate a one entry hash list than it is to check all
157 * over the place for hashbase == NULL.
158 */
155 /*
156 * XXX We don't use the hash list for divert IP, but it's easier
157 * to allocate a one entry hash list than it is to check all
158 * over the place for hashbase == NULL.
159 */
159 divcbinfo.ipi_hashbase = hashinit(1, M_PCB, &divcbinfo.ipi_hashmask);
160 divcbinfo.ipi_porthashbase = hashinit(1, M_PCB,
161 &divcbinfo.ipi_porthashmask);
162 divcbinfo.ipi_zone = uma_zcreate("divcb", sizeof(struct inpcb),
160 V_divcbinfo.ipi_hashbase = hashinit(1, M_PCB, &V_divcbinfo.ipi_hashmask);
161 V_divcbinfo.ipi_porthashbase = hashinit(1, M_PCB,
162 &V_divcbinfo.ipi_porthashmask);
163 V_divcbinfo.ipi_zone = uma_zcreate("divcb", sizeof(struct inpcb),
163 NULL, NULL, div_inpcb_init, div_inpcb_fini, UMA_ALIGN_PTR,
164 UMA_ZONE_NOFREE);
165 uma_zone_set_max(divcbinfo.ipi_zone, maxsockets);
166 EVENTHANDLER_REGISTER(maxsockets_change, div_zone_change,
167 NULL, EVENTHANDLER_PRI_ANY);
168}
169
170/*
171 * IPPROTO_DIVERT is not in the real IP protocol number space; this
172 * function should never be called. Just in case, drop any packets.
173 */
174void
175div_input(struct mbuf *m, int off)
176{
164 NULL, NULL, div_inpcb_init, div_inpcb_fini, UMA_ALIGN_PTR,
165 UMA_ZONE_NOFREE);
166 uma_zone_set_max(divcbinfo.ipi_zone, maxsockets);
167 EVENTHANDLER_REGISTER(maxsockets_change, div_zone_change,
168 NULL, EVENTHANDLER_PRI_ANY);
169}
170
171/*
172 * IPPROTO_DIVERT is not in the real IP protocol number space; this
173 * function should never be called. Just in case, drop any packets.
174 */
175void
176div_input(struct mbuf *m, int off)
177{
177 ipstat.ips_noproto++;
178 V_ipstat.ips_noproto++;
178 m_freem(m);
179}
180
181/*
182 * Divert a packet by passing it up to the divert socket at port 'port'.
183 *
184 * Setup generic address and protocol structures for div_input routine,
185 * then pass them along with mbuf chain.

--- 75 unchanged lines hidden (view full) ---

261 */
262 strlcpy(divsrc.sin_zero, m->m_pkthdr.rcvif->if_xname,
263 sizeof(divsrc.sin_zero));
264 }
265
266 /* Put packet on socket queue, if any */
267 sa = NULL;
268 nport = htons((u_int16_t)divert_info(mtag));
179 m_freem(m);
180}
181
182/*
183 * Divert a packet by passing it up to the divert socket at port 'port'.
184 *
185 * Setup generic address and protocol structures for div_input routine,
186 * then pass them along with mbuf chain.

--- 75 unchanged lines hidden (view full) ---

262 */
263 strlcpy(divsrc.sin_zero, m->m_pkthdr.rcvif->if_xname,
264 sizeof(divsrc.sin_zero));
265 }
266
267 /* Put packet on socket queue, if any */
268 sa = NULL;
269 nport = htons((u_int16_t)divert_info(mtag));
269 INP_INFO_RLOCK(&divcbinfo);
270 LIST_FOREACH(inp, &divcb, inp_list) {
270 INP_INFO_RLOCK(&V_divcbinfo);
271 LIST_FOREACH(inp, &V_divcb, inp_list) {
271 /* XXX why does only one socket match? */
272 if (inp->inp_lport == nport) {
273 INP_RLOCK(inp);
274 sa = inp->inp_socket;
275 SOCKBUF_LOCK(&sa->so_rcv);
276 if (sbappendaddr_locked(&sa->so_rcv,
277 (struct sockaddr *)&divsrc, m,
278 (struct mbuf *)0) == 0) {
279 SOCKBUF_UNLOCK(&sa->so_rcv);
280 sa = NULL; /* force mbuf reclaim below */
281 } else
282 sorwakeup_locked(sa);
283 INP_RUNLOCK(inp);
284 break;
285 }
286 }
272 /* XXX why does only one socket match? */
273 if (inp->inp_lport == nport) {
274 INP_RLOCK(inp);
275 sa = inp->inp_socket;
276 SOCKBUF_LOCK(&sa->so_rcv);
277 if (sbappendaddr_locked(&sa->so_rcv,
278 (struct sockaddr *)&divsrc, m,
279 (struct mbuf *)0) == 0) {
280 SOCKBUF_UNLOCK(&sa->so_rcv);
281 sa = NULL; /* force mbuf reclaim below */
282 } else
283 sorwakeup_locked(sa);
284 INP_RUNLOCK(inp);
285 break;
286 }
287 }
287 INP_INFO_RUNLOCK(&divcbinfo);
288 INP_INFO_RUNLOCK(&V_divcbinfo);
288 if (sa == NULL) {
289 m_freem(m);
289 if (sa == NULL) {
290 m_freem(m);
290 ipstat.ips_noproto++;
291 ipstat.ips_delivered--;
291 V_ipstat.ips_noproto++;
292 V_ipstat.ips_delivered--;
292 }
293}
294
295/*
296 * Deliver packet back into the IP processing machinery.
297 *
298 * If no address specified, or address is 0.0.0.0, send to ip_output();
299 * otherwise, send to ip_input() and mark as having been received on

--- 48 unchanged lines hidden (view full) ---

348 }
349
350 /* Reinject packet into the system as incoming or outgoing */
351 if (!sin || sin->sin_addr.s_addr == 0) {
352 struct ip *const ip = mtod(m, struct ip *);
353 struct inpcb *inp;
354
355 dt->info |= IP_FW_DIVERT_OUTPUT_FLAG;
293 }
294}
295
296/*
297 * Deliver packet back into the IP processing machinery.
298 *
299 * If no address specified, or address is 0.0.0.0, send to ip_output();
300 * otherwise, send to ip_input() and mark as having been received on

--- 48 unchanged lines hidden (view full) ---

349 }
350
351 /* Reinject packet into the system as incoming or outgoing */
352 if (!sin || sin->sin_addr.s_addr == 0) {
353 struct ip *const ip = mtod(m, struct ip *);
354 struct inpcb *inp;
355
356 dt->info |= IP_FW_DIVERT_OUTPUT_FLAG;
356 INP_INFO_WLOCK(&divcbinfo);
357 INP_INFO_WLOCK(&V_divcbinfo);
357 inp = sotoinpcb(so);
358 INP_RLOCK(inp);
359 /*
360 * Don't allow both user specified and setsockopt options,
361 * and don't allow packet length sizes that will crash
362 */
363 if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) ||
364 ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) {
365 error = EINVAL;
366 INP_RUNLOCK(inp);
358 inp = sotoinpcb(so);
359 INP_RLOCK(inp);
360 /*
361 * Don't allow both user specified and setsockopt options,
362 * and don't allow packet length sizes that will crash
363 */
364 if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) ||
365 ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) {
366 error = EINVAL;
367 INP_RUNLOCK(inp);
367 INP_INFO_WUNLOCK(&divcbinfo);
368 INP_INFO_WUNLOCK(&V_divcbinfo);
368 m_freem(m);
369 } else {
370 /* Convert fields to host order for ip_output() */
371 ip->ip_len = ntohs(ip->ip_len);
372 ip->ip_off = ntohs(ip->ip_off);
373
374 /* Send packet to output processing */
369 m_freem(m);
370 } else {
371 /* Convert fields to host order for ip_output() */
372 ip->ip_len = ntohs(ip->ip_len);
373 ip->ip_off = ntohs(ip->ip_off);
374
375 /* Send packet to output processing */
375 ipstat.ips_rawout++; /* XXX */
376 V_ipstat.ips_rawout++; /* XXX */
376
377#ifdef MAC
378 mac_inpcb_create_mbuf(inp, m);
379#endif
380 /*
381 * Get ready to inject the packet into ip_output().
382 * Just in case socket options were specified on the
383 * divert socket, we duplicate them. This is done

--- 16 unchanged lines hidden (view full) ---

400 * requring a reference to the pcb.
401 */
402 if (inp->inp_options != NULL) {
403 options = m_dup(inp->inp_options, M_DONTWAIT);
404 if (options == NULL)
405 error = ENOBUFS;
406 }
407 INP_RUNLOCK(inp);
377
378#ifdef MAC
379 mac_inpcb_create_mbuf(inp, m);
380#endif
381 /*
382 * Get ready to inject the packet into ip_output().
383 * Just in case socket options were specified on the
384 * divert socket, we duplicate them. This is done

--- 16 unchanged lines hidden (view full) ---

401 * requring a reference to the pcb.
402 */
403 if (inp->inp_options != NULL) {
404 options = m_dup(inp->inp_options, M_DONTWAIT);
405 if (options == NULL)
406 error = ENOBUFS;
407 }
408 INP_RUNLOCK(inp);
408 INP_INFO_WUNLOCK(&divcbinfo);
409 INP_INFO_WUNLOCK(&V_divcbinfo);
409 if (error == ENOBUFS) {
410 m_freem(m);
411 return (error);
412 }
413 error = ip_output(m, options, NULL,
414 ((so->so_options & SO_DONTROUTE) ?
415 IP_ROUTETOIF : 0) | IP_ALLOWBROADCAST |
416 IP_RAWOUTPUT, NULL, NULL);

--- 46 unchanged lines hidden (view full) ---

463 if (td != NULL) {
464 error = priv_check(td, PRIV_NETINET_DIVERT);
465 if (error)
466 return (error);
467 }
468 error = soreserve(so, div_sendspace, div_recvspace);
469 if (error)
470 return error;
410 if (error == ENOBUFS) {
411 m_freem(m);
412 return (error);
413 }
414 error = ip_output(m, options, NULL,
415 ((so->so_options & SO_DONTROUTE) ?
416 IP_ROUTETOIF : 0) | IP_ALLOWBROADCAST |
417 IP_RAWOUTPUT, NULL, NULL);

--- 46 unchanged lines hidden (view full) ---

464 if (td != NULL) {
465 error = priv_check(td, PRIV_NETINET_DIVERT);
466 if (error)
467 return (error);
468 }
469 error = soreserve(so, div_sendspace, div_recvspace);
470 if (error)
471 return error;
471 INP_INFO_WLOCK(&divcbinfo);
472 error = in_pcballoc(so, &divcbinfo);
472 INP_INFO_WLOCK(&V_divcbinfo);
473 error = in_pcballoc(so, &V_divcbinfo);
473 if (error) {
474 if (error) {
474 INP_INFO_WUNLOCK(&divcbinfo);
475 INP_INFO_WUNLOCK(&V_divcbinfo);
475 return error;
476 }
477 inp = (struct inpcb *)so->so_pcb;
476 return error;
477 }
478 inp = (struct inpcb *)so->so_pcb;
478 INP_INFO_WUNLOCK(&divcbinfo);
479 INP_INFO_WUNLOCK(&V_divcbinfo);
479 inp->inp_ip_p = proto;
480 inp->inp_vflag |= INP_IPV4;
481 inp->inp_flags |= INP_HDRINCL;
482 INP_WUNLOCK(inp);
483 return 0;
484}
485
486static void
487div_detach(struct socket *so)
488{
489 struct inpcb *inp;
490
491 inp = sotoinpcb(so);
492 KASSERT(inp != NULL, ("div_detach: inp == NULL"));
480 inp->inp_ip_p = proto;
481 inp->inp_vflag |= INP_IPV4;
482 inp->inp_flags |= INP_HDRINCL;
483 INP_WUNLOCK(inp);
484 return 0;
485}
486
487static void
488div_detach(struct socket *so)
489{
490 struct inpcb *inp;
491
492 inp = sotoinpcb(so);
493 KASSERT(inp != NULL, ("div_detach: inp == NULL"));
493 INP_INFO_WLOCK(&divcbinfo);
494 INP_INFO_WLOCK(&V_divcbinfo);
494 INP_WLOCK(inp);
495 in_pcbdetach(inp);
496 in_pcbfree(inp);
495 INP_WLOCK(inp);
496 in_pcbdetach(inp);
497 in_pcbfree(inp);
497 INP_INFO_WUNLOCK(&divcbinfo);
498 INP_INFO_WUNLOCK(&V_divcbinfo);
498}
499
500static int
501div_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
502{
503 struct inpcb *inp;
504 int error;
505

--- 4 unchanged lines hidden (view full) ---

510 * sockets don't we need to make sure the address is
511 * filled in properly.
512 * XXX -- divert should not be abusing in_pcbind
513 * and should probably have its own family.
514 */
515 if (nam->sa_family != AF_INET)
516 return EAFNOSUPPORT;
517 ((struct sockaddr_in *)nam)->sin_addr.s_addr = INADDR_ANY;
499}
500
501static int
502div_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
503{
504 struct inpcb *inp;
505 int error;
506

--- 4 unchanged lines hidden (view full) ---

511 * sockets don't we need to make sure the address is
512 * filled in properly.
513 * XXX -- divert should not be abusing in_pcbind
514 * and should probably have its own family.
515 */
516 if (nam->sa_family != AF_INET)
517 return EAFNOSUPPORT;
518 ((struct sockaddr_in *)nam)->sin_addr.s_addr = INADDR_ANY;
518 INP_INFO_WLOCK(&divcbinfo);
519 INP_INFO_WLOCK(&V_divcbinfo);
519 INP_WLOCK(inp);
520 error = in_pcbbind(inp, nam, td->td_ucred);
521 INP_WUNLOCK(inp);
520 INP_WLOCK(inp);
521 error = in_pcbbind(inp, nam, td->td_ucred);
522 INP_WUNLOCK(inp);
522 INP_INFO_WUNLOCK(&divcbinfo);
523 INP_INFO_WUNLOCK(&V_divcbinfo);
523 return error;
524}
525
526static int
527div_shutdown(struct socket *so)
528{
529 struct inpcb *inp;
530

--- 7 unchanged lines hidden (view full) ---

538
539static int
540div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
541 struct mbuf *control, struct thread *td)
542{
543 /* Packet must have a header (but that's about it) */
544 if (m->m_len < sizeof (struct ip) &&
545 (m = m_pullup(m, sizeof (struct ip))) == 0) {
524 return error;
525}
526
527static int
528div_shutdown(struct socket *so)
529{
530 struct inpcb *inp;
531

--- 7 unchanged lines hidden (view full) ---

539
540static int
541div_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
542 struct mbuf *control, struct thread *td)
543{
544 /* Packet must have a header (but that's about it) */
545 if (m->m_len < sizeof (struct ip) &&
546 (m = m_pullup(m, sizeof (struct ip))) == 0) {
546 ipstat.ips_toosmall++;
547 V_ipstat.ips_toosmall++;
547 m_freem(m);
548 return EINVAL;
549 }
550
551 /* Send packet */
552 return div_output(so, m, (struct sockaddr_in *)nam, control);
553}
554

--- 17 unchanged lines hidden (view full) ---

572 inp_gen_t gencnt;
573 struct xinpgen xig;
574
575 /*
576 * The process of preparing the TCB list is too time-consuming and
577 * resource-intensive to repeat twice on every request.
578 */
579 if (req->oldptr == 0) {
548 m_freem(m);
549 return EINVAL;
550 }
551
552 /* Send packet */
553 return div_output(so, m, (struct sockaddr_in *)nam, control);
554}
555

--- 17 unchanged lines hidden (view full) ---

573 inp_gen_t gencnt;
574 struct xinpgen xig;
575
576 /*
577 * The process of preparing the TCB list is too time-consuming and
578 * resource-intensive to repeat twice on every request.
579 */
580 if (req->oldptr == 0) {
580 n = divcbinfo.ipi_count;
581 n = V_divcbinfo.ipi_count;
581 req->oldidx = 2 * (sizeof xig)
582 + (n + n/8) * sizeof(struct xinpcb);
583 return 0;
584 }
585
586 if (req->newptr != 0)
587 return EPERM;
588
589 /*
590 * OK, now we're committed to doing something.
591 */
582 req->oldidx = 2 * (sizeof xig)
583 + (n + n/8) * sizeof(struct xinpcb);
584 return 0;
585 }
586
587 if (req->newptr != 0)
588 return EPERM;
589
590 /*
591 * OK, now we're committed to doing something.
592 */
592 INP_INFO_RLOCK(&divcbinfo);
593 gencnt = divcbinfo.ipi_gencnt;
594 n = divcbinfo.ipi_count;
595 INP_INFO_RUNLOCK(&divcbinfo);
593 INP_INFO_RLOCK(&V_divcbinfo);
594 gencnt = V_divcbinfo.ipi_gencnt;
595 n = V_divcbinfo.ipi_count;
596 INP_INFO_RUNLOCK(&V_divcbinfo);
596
597 error = sysctl_wire_old_buffer(req,
598 2 * sizeof(xig) + n*sizeof(struct xinpcb));
599 if (error != 0)
600 return (error);
601
602 xig.xig_len = sizeof xig;
603 xig.xig_count = n;
604 xig.xig_gen = gencnt;
605 xig.xig_sogen = so_gencnt;
606 error = SYSCTL_OUT(req, &xig, sizeof xig);
607 if (error)
608 return error;
609
610 inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
611 if (inp_list == 0)
612 return ENOMEM;
613
597
598 error = sysctl_wire_old_buffer(req,
599 2 * sizeof(xig) + n*sizeof(struct xinpcb));
600 if (error != 0)
601 return (error);
602
603 xig.xig_len = sizeof xig;
604 xig.xig_count = n;
605 xig.xig_gen = gencnt;
606 xig.xig_sogen = so_gencnt;
607 error = SYSCTL_OUT(req, &xig, sizeof xig);
608 if (error)
609 return error;
610
611 inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
612 if (inp_list == 0)
613 return ENOMEM;
614
614 INP_INFO_RLOCK(&divcbinfo);
615 for (inp = LIST_FIRST(divcbinfo.ipi_listhead), i = 0; inp && i < n;
615 INP_INFO_RLOCK(&V_divcbinfo);
616 for (inp = LIST_FIRST(V_divcbinfo.ipi_listhead), i = 0; inp && i < n;
616 inp = LIST_NEXT(inp, inp_list)) {
617 INP_RLOCK(inp);
618 if (inp->inp_gencnt <= gencnt &&
619 cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0)
620 inp_list[i++] = inp;
621 INP_RUNLOCK(inp);
622 }
617 inp = LIST_NEXT(inp, inp_list)) {
618 INP_RLOCK(inp);
619 if (inp->inp_gencnt <= gencnt &&
620 cr_canseesocket(req->td->td_ucred, inp->inp_socket) == 0)
621 inp_list[i++] = inp;
622 INP_RUNLOCK(inp);
623 }
623 INP_INFO_RUNLOCK(&divcbinfo);
624 INP_INFO_RUNLOCK(&V_divcbinfo);
624 n = i;
625
626 error = 0;
627 for (i = 0; i < n; i++) {
628 inp = inp_list[i];
629 INP_RLOCK(inp);
630 if (inp->inp_gencnt <= gencnt) {
631 struct xinpcb xi;

--- 11 unchanged lines hidden (view full) ---

643 if (!error) {
644 /*
645 * Give the user an updated idea of our state.
646 * If the generation differs from what we told
647 * her before, she knows that something happened
648 * while we were processing this request, and it
649 * might be necessary to retry.
650 */
625 n = i;
626
627 error = 0;
628 for (i = 0; i < n; i++) {
629 inp = inp_list[i];
630 INP_RLOCK(inp);
631 if (inp->inp_gencnt <= gencnt) {
632 struct xinpcb xi;

--- 11 unchanged lines hidden (view full) ---

644 if (!error) {
645 /*
646 * Give the user an updated idea of our state.
647 * If the generation differs from what we told
648 * her before, she knows that something happened
649 * while we were processing this request, and it
650 * might be necessary to retry.
651 */
651 INP_INFO_RLOCK(&divcbinfo);
652 xig.xig_gen = divcbinfo.ipi_gencnt;
652 INP_INFO_RLOCK(&V_divcbinfo);
653 xig.xig_gen = V_divcbinfo.ipi_gencnt;
653 xig.xig_sogen = so_gencnt;
654 xig.xig_sogen = so_gencnt;
654 xig.xig_count = divcbinfo.ipi_count;
655 INP_INFO_RUNLOCK(&divcbinfo);
655 xig.xig_count = V_divcbinfo.ipi_count;
656 INP_INFO_RUNLOCK(&V_divcbinfo);
656 error = SYSCTL_OUT(req, &xig, sizeof xig);
657 }
658 free(inp_list, M_TEMP);
659 return error;
660}
661
662#ifdef SYSCTL_NODE
663SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, divert, CTLFLAG_RW, 0, "IPDIVERT");

--- 55 unchanged lines hidden (view full) ---

719 * Module ipdivert can only be unloaded if no sockets are
720 * connected. Maybe this can be changed later to forcefully
721 * disconnect any open sockets.
722 *
723 * XXXRW: Note that there is a slight race here, as a new
724 * socket open request could be spinning on the lock and then
725 * we destroy the lock.
726 */
657 error = SYSCTL_OUT(req, &xig, sizeof xig);
658 }
659 free(inp_list, M_TEMP);
660 return error;
661}
662
663#ifdef SYSCTL_NODE
664SYSCTL_NODE(_net_inet, IPPROTO_DIVERT, divert, CTLFLAG_RW, 0, "IPDIVERT");

--- 55 unchanged lines hidden (view full) ---

720 * Module ipdivert can only be unloaded if no sockets are
721 * connected. Maybe this can be changed later to forcefully
722 * disconnect any open sockets.
723 *
724 * XXXRW: Note that there is a slight race here, as a new
725 * socket open request could be spinning on the lock and then
726 * we destroy the lock.
727 */
727 INP_INFO_WLOCK(&divcbinfo);
728 n = divcbinfo.ipi_count;
728 INP_INFO_WLOCK(&V_divcbinfo);
729 n = V_divcbinfo.ipi_count;
729 if (n != 0) {
730 err = EBUSY;
730 if (n != 0) {
731 err = EBUSY;
731 INP_INFO_WUNLOCK(&divcbinfo);
732 INP_INFO_WUNLOCK(&V_divcbinfo);
732 break;
733 }
734 ip_divert_ptr = NULL;
735 err = pf_proto_unregister(PF_INET, IPPROTO_DIVERT, SOCK_RAW);
733 break;
734 }
735 ip_divert_ptr = NULL;
736 err = pf_proto_unregister(PF_INET, IPPROTO_DIVERT, SOCK_RAW);
736 INP_INFO_WUNLOCK(&divcbinfo);
737 INP_INFO_LOCK_DESTROY(&divcbinfo);
738 uma_zdestroy(divcbinfo.ipi_zone);
737 INP_INFO_WUNLOCK(&V_divcbinfo);
738 INP_INFO_LOCK_DESTROY(&V_divcbinfo);
739 uma_zdestroy(V_divcbinfo.ipi_zone);
739 break;
740 default:
741 err = EOPNOTSUPP;
742 break;
743 }
744 return err;
745}
746
747static moduledata_t ipdivertmod = {
748 "ipdivert",
749 div_modevent,
750 0
751};
752
753DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
754MODULE_DEPEND(dummynet, ipfw, 2, 2, 2);
755MODULE_VERSION(ipdivert, 1);
740 break;
741 default:
742 err = EOPNOTSUPP;
743 break;
744 }
745 return err;
746}
747
748static moduledata_t ipdivertmod = {
749 "ipdivert",
750 div_modevent,
751 0
752};
753
754DECLARE_MODULE(ipdivert, ipdivertmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
755MODULE_DEPEND(dummynet, ipfw, 2, 2, 2);
756MODULE_VERSION(ipdivert, 1);