Hide struct inpcb, struct tcpcb from the userland.

This is a painful change, but it is needed.  On the one hand, we avoid
modifying them, and this slows down some ideas, on the other hand we still
eventually modify them and tools like netstat(1) never work on next version of
FreeBSD.  We maintain a ton of spares in them, and we already got some ifdef
hell at the end of tcpcb.

Details:
- Hide struct inpcb, struct tcpcb under _KERNEL || _WANT_FOO.
- Make struct xinpcb, struct xtcpcb pure API structures, not including
  kernel structures inpcb and tcpcb inside.  Export into these structures
  the fields from inpcb and tcpcb that are known to be used, and put there
  a ton of spare space.
- Make kernel and userland utilities compilable after these changes.
- Bump __FreeBSD_version.

Reviewed by:	rrs, gnn
Differential Revision:	D10018
This commit is contained in:
Gleb Smirnoff 2017-03-21 06:39:49 +00:00
parent 5a33a2afb3
commit cc65eb4e79
22 changed files with 384 additions and 471 deletions

View File

@ -310,7 +310,7 @@ op_tcpconn(struct snmp_context *ctx __unused, struct snmp_value *value,
switch (value->var.subs[sub - 1]) {
case LEAF_tcpConnState:
switch (tcpoids[i].tp->xt_tp.t_state) {
switch (tcpoids[i].tp->t_state) {
case TCPS_CLOSED:
value->v.integer = 1;

View File

@ -105,8 +105,8 @@ fetch_udp(void)
ptr->xig_len > sizeof(struct xinpgen);
ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
inp = (struct xinpcb *)ptr;
if (inp->xi_inp.inp_gencnt > xinpgen->xig_gen ||
(inp->xi_inp.inp_vflag & INP_IPV4) == 0)
if (inp->inp_gencnt > xinpgen->xig_gen ||
(inp->inp_vflag & INP_IPV4) == 0)
continue;
udp_total++;
@ -128,17 +128,17 @@ fetch_udp(void)
ptr->xig_len > sizeof(struct xinpgen);
ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
inp = (struct xinpcb *)ptr;
if (inp->xi_inp.inp_gencnt > xinpgen->xig_gen ||
(inp->xi_inp.inp_vflag & INP_IPV4) == 0)
if (inp->inp_gencnt > xinpgen->xig_gen ||
(inp->inp_vflag & INP_IPV4) == 0)
continue;
oid->inp = inp;
oid->index.len = 5;
inaddr = ntohl(inp->xi_inp.inp_laddr.s_addr);
inaddr = ntohl(inp->inp_laddr.s_addr);
oid->index.subs[0] = (inaddr >> 24) & 0xff;
oid->index.subs[1] = (inaddr >> 16) & 0xff;
oid->index.subs[2] = (inaddr >> 8) & 0xff;
oid->index.subs[3] = (inaddr >> 0) & 0xff;
oid->index.subs[4] = ntohs(inp->xi_inp.inp_lport);
oid->index.subs[4] = ntohs(inp->inp_lport);
oid++;
}

View File

@ -78,8 +78,10 @@ typedef int boolean_t;
# include <net/route.h>
#endif
#include <netinet/ip_var.h>
#define _WANT_INPCB
#include <netinet/in_pcb.h>
#include <netinet/tcp_timer.h>
#define _WANT_TCPCB
#include <netinet/tcp_var.h>
#include <stdio.h>
#include <unistd.h>

View File

@ -82,6 +82,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#define _WANT_INPCB
#include <netinet/in_pcb.h>
#include <assert.h>

View File

@ -2434,6 +2434,41 @@ so_sototcpcb(struct socket *so)
return (sototcpcb(so));
}
/*
* Create an external-format (``xinpcb'') structure using the information in
* the kernel-format in_pcb structure pointed to by inp. This is done to
* reduce the spew of irrelevant information over this interface, to isolate
* user code from changes in the kernel structure, and potentially to provide
* information-hiding if we decide that some of this information should be
* hidden from users.
*/
void
in_pcbtoxinpcb(const struct inpcb *inp, struct xinpcb *xi)
{
xi->xi_len = sizeof(struct xinpcb);
if (inp->inp_socket)
sotoxsocket(inp->inp_socket, &xi->xi_socket);
else
bzero(&xi->xi_socket, sizeof(struct xsocket));
bcopy(&inp->inp_inc, &xi->inp_inc, sizeof(struct in_conninfo));
xi->inp_gencnt = inp->inp_gencnt;
xi->inp_ppcb = inp->inp_ppcb;
xi->inp_flow = inp->inp_flow;
xi->inp_flowid = inp->inp_flowid;
xi->inp_flowtype = inp->inp_flowtype;
xi->inp_flags = inp->inp_flags;
xi->inp_flags2 = inp->inp_flags2;
xi->inp_rss_listen_bucket = inp->inp_rss_listen_bucket;
xi->in6p_cksum = inp->in6p_cksum;
xi->in6p_hops = inp->in6p_hops;
xi->inp_ip_tos = inp->inp_ip_tos;
xi->inp_vflag = inp->inp_vflag;
xi->inp_ip_ttl = inp->inp_ip_ttl;
xi->inp_ip_p = inp->inp_ip_p;
xi->inp_ip_minttl = inp->inp_ip_minttl;
}
#ifdef DDB
static void
db_print_indent(int indent)

View File

@ -53,7 +53,6 @@
#define in6pcb inpcb /* for KAME src sync over BSD*'s */
#define in6p_sp inp_sp /* for KAME src sync over BSD*'s */
struct inpcbpolicy;
/*
* struct inpcb is the common protocol control block structure used in most
@ -65,7 +64,7 @@ struct inpcbpolicy;
*/
LIST_HEAD(inpcbhead, inpcb);
LIST_HEAD(inpcbporthead, inpcbport);
typedef u_quad_t inp_gen_t;
typedef uint64_t inp_gen_t;
/*
* PCB with AF_INET6 null bind'ed laddr can receive AF_INET input packet.
@ -130,9 +129,8 @@ struct in_conninfo {
#define inc6_laddr inc_ie.ie6_laddr
#define inc6_zoneid inc_ie.ie6_zoneid
struct icmp6_filter;
/*-
#if defined(_KERNEL) || defined(_WANT_INPCB)
/*
* struct inpcb captures the network layer state for TCP, UDP, and raw IPv4 and
* IPv6 sockets. In the case of TCP and UDP, further per-connection state is
* hung off of inp_ppcb most of the time. Almost all fields of struct inpcb
@ -181,6 +179,8 @@ struct icmp6_filter;
* read-lock usage during modification, this model can be applied to other
* protocols (especially SCTP).
*/
struct icmp6_filter;
struct inpcbpolicy;
struct m_snd_tag;
struct inpcb {
LIST_ENTRY(inpcb) inp_hash; /* (h/i) hash list */
@ -204,10 +204,8 @@ struct inpcb {
uint32_t inp_flowid; /* (x) flow id / queue id */
u_int inp_refcount; /* (i) refcount */
struct m_snd_tag *inp_snd_tag; /* (i) send tag for outgoing mbufs */
void *inp_pspare[4]; /* (x) general use */
uint32_t inp_flowtype; /* (x) M_HASHTYPE value */
uint32_t inp_rss_listen_bucket; /* (x) overridden RSS listen bucket */
u_int inp_ispare[4]; /* (x) user cookie / general use */
/* Local and foreign ports, local and foreign addr. */
struct in_conninfo inp_inc; /* (i) list for PCB's local port */
@ -218,23 +216,23 @@ struct inpcb {
/* Protocol-dependent part; options. */
struct {
u_char inp4_ip_tos; /* (i) type of service proto */
struct mbuf *inp4_options; /* (i) IP options */
struct ip_moptions *inp4_moptions; /* (i) IP mcast options */
} inp_depend4;
u_char inp_ip_tos; /* (i) type of service proto */
struct mbuf *inp_options; /* (i) IP options */
struct ip_moptions *inp_moptions; /* (i) mcast options */
};
struct {
/* (i) IP options */
struct mbuf *inp6_options;
struct mbuf *in6p_options;
/* (i) IP6 options for outgoing packets */
struct ip6_pktopts *inp6_outputopts;
struct ip6_pktopts *in6p_outputopts;
/* (i) IP multicast options */
struct ip6_moptions *inp6_moptions;
struct ip6_moptions *in6p_moptions;
/* (i) ICMPv6 code type filter */
struct icmp6_filter *inp6_icmp6filt;
struct icmp6_filter *in6p_icmp6filt;
/* (i) IPV6_CHECKSUM setsockopt */
int inp6_cksum;
short inp6_hops;
} inp_depend6;
int in6p_cksum;
short in6p_hops;
};
LIST_ENTRY(inpcb) inp_portlist; /* (i/h) */
struct inpcbport *inp_phd; /* (i/h) head of this list */
#define inp_zero_size offsetof(struct inpcb, inp_gencnt)
@ -249,24 +247,17 @@ struct inpcb {
#define inp_route inp_rtu.inpu_route
#define inp_route6 inp_rtu.inpu_route6
};
#endif /* _KERNEL */
#define inp_fport inp_inc.inc_fport
#define inp_lport inp_inc.inc_lport
#define inp_faddr inp_inc.inc_faddr
#define inp_laddr inp_inc.inc_laddr
#define inp_ip_tos inp_depend4.inp4_ip_tos
#define inp_options inp_depend4.inp4_options
#define inp_moptions inp_depend4.inp4_moptions
#define in6p_faddr inp_inc.inc6_faddr
#define in6p_laddr inp_inc.inc6_laddr
#define in6p_zoneid inp_inc.inc6_zoneid
#define in6p_hops inp_depend6.inp6_hops /* default hop limit */
#define in6p_flowinfo inp_flow
#define in6p_options inp_depend6.inp6_options
#define in6p_outputopts inp_depend6.inp6_outputopts
#define in6p_moptions inp_depend6.inp6_moptions
#define in6p_icmp6filt inp_depend6.inp6_icmp6filt
#define in6p_cksum inp_depend6.inp6_cksum
#define inp_vnet inp_pcbinfo->ipi_vnet
@ -280,21 +271,53 @@ struct inpcb {
/*
* Interface exported to userland by various protocols which use inpcbs. Hack
* alert -- only define if struct xsocket is in scope.
* Fields prefixed with "xi_" are unique to this structure, and the rest
* match fields in the struct inpcb, to ease coding and porting.
*
* Legend:
* (s) - used by userland utilities in src
* (p) - used by utilities in ports
* (3) - is known to be used by third party software not in ports
* (n) - no known usage
*/
#ifdef _SYS_SOCKETVAR_H_
struct xinpcb {
size_t xi_len; /* length of this structure */
struct inpcb xi_inp;
struct xsocket xi_socket;
u_quad_t xi_alignment_hack;
};
struct xinpcb {
size_t xi_len; /* length of this structure */
struct xsocket xi_socket; /* (s,p) */
struct in_conninfo inp_inc; /* (s,p) */
uint64_t inp_gencnt; /* (s,p) */
union {
void *inp_ppcb; /* (s) netstat(1) */
int64_t ph_ppcb;
};
int64_t inp_spare64[4];
uint32_t inp_flow; /* (s) */
uint32_t inp_flowid; /* (s) */
uint32_t inp_flowtype; /* (s) */
int32_t inp_flags; /* (s,p) */
int32_t inp_flags2; /* (s) */
int32_t inp_rss_listen_bucket; /* (n) */
int32_t in6p_cksum; /* (n) */
int32_t inp_spare32[4];
uint16_t in6p_hops; /* (n) */
uint8_t inp_ip_tos; /* (n) */
int8_t pad8;
uint8_t inp_vflag; /* (s,p) */
uint8_t inp_ip_ttl; /* (n) */
uint8_t inp_ip_p; /* (n) */
uint8_t inp_ip_minttl; /* (n) */
int8_t inp_spare8[4];
} __aligned(8);
struct xinpgen {
size_t xig_len; /* length of this structure */
u_int xig_count; /* number of PCBs at this time */
inp_gen_t xig_gen; /* generation count at this time */
so_gen_t xig_sogen; /* socket generation count at this time */
struct xinpgen {
size_t xig_len; /* length of this structure */
u_int xig_count; /* number of PCBs at this time */
inp_gen_t xig_gen; /* generation count at this time */
so_gen_t xig_sogen; /* socket generation count this time */
};
#ifdef _KERNEL
void in_pcbtoxinpcb(const struct inpcb *, struct xinpcb *);
#endif
#endif /* _SYS_SOCKETVAR_H_ */
struct inpcbport {

View File

@ -691,12 +691,8 @@ div_pcblist(SYSCTL_HANDLER_ARGS)
INP_RLOCK(inp);
if (inp->inp_gencnt <= gencnt) {
struct xinpcb xi;
bzero(&xi, sizeof(xi));
xi.xi_len = sizeof xi;
/* XXX should avoid extra copy */
bcopy(inp, &xi.xi_inp, sizeof *inp);
if (inp->inp_socket)
sotoxsocket(inp->inp_socket, &xi.xi_socket);
in_pcbtoxinpcb(inp, &xi);
INP_RUNLOCK(inp);
error = SYSCTL_OUT(req, &xi, sizeof xi);
} else

View File

@ -1077,12 +1077,7 @@ rip_pcblist(SYSCTL_HANDLER_ARGS)
if (inp->inp_gencnt <= gencnt) {
struct xinpcb xi;
bzero(&xi, sizeof(xi));
xi.xi_len = sizeof xi;
/* XXX should avoid extra copy */
bcopy(inp, &xi.xi_inp, sizeof *inp);
if (inp->inp_socket)
sotoxsocket(inp->inp_socket, &xi.xi_socket);
in_pcbtoxinpcb(inp, &xi);
INP_RUNLOCK(inp);
error = SYSCTL_OUT(req, &xi, sizeof xi);
} else

View File

@ -1773,30 +1773,8 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS)
INP_RLOCK(inp);
if (inp->inp_gencnt <= gencnt) {
struct xtcpcb xt;
void *inp_ppcb;
bzero(&xt, sizeof(xt));
xt.xt_len = sizeof xt;
/* XXX should avoid extra copy */
bcopy(inp, &xt.xt_inp, sizeof *inp);
inp_ppcb = inp->inp_ppcb;
if (inp_ppcb == NULL)
bzero((char *) &xt.xt_tp, sizeof xt.xt_tp);
else if (inp->inp_flags & INP_TIMEWAIT) {
bzero((char *) &xt.xt_tp, sizeof xt.xt_tp);
xt.xt_tp.t_state = TCPS_TIME_WAIT;
} else {
bcopy(inp_ppcb, &xt.xt_tp, sizeof xt.xt_tp);
if (xt.xt_tp.t_timers)
tcp_timer_to_xtimer(&xt.xt_tp, xt.xt_tp.t_timers, &xt.xt_timer);
}
if (inp->inp_socket != NULL)
sotoxsocket(inp->inp_socket, &xt.xt_socket);
else {
bzero(&xt.xt_socket, sizeof xt.xt_socket);
xt.xt_socket.xso_protocol = IPPROTO_TCP;
}
xt.xt_inp.inp_gencnt = inp->inp_gencnt;
tcp_inptoxtp(inp, &xt);
INP_RUNLOCK(inp);
error = SYSCTL_OUT(req, &xt, sizeof xt);
} else
@ -2765,3 +2743,53 @@ tcp_state_change(struct tcpcb *tp, int newstate)
tp->t_state = newstate;
TCP_PROBE6(state__change, NULL, tp, NULL, tp, NULL, pstate);
}
/*
* Create an external-format (``xtcpcb'') structure using the information in
* the kernel-format tcpcb structure pointed to by tp. This is done to
* reduce the spew of irrelevant information over this interface, to isolate
* user code from changes in the kernel structure, and potentially to provide
* information-hiding if we decide that some of this information should be
* hidden from users.
*/
void
tcp_inptoxtp(const struct inpcb *inp, struct xtcpcb *xt)
{
struct tcpcb *tp = intotcpcb(inp);
sbintime_t now;
if (inp->inp_flags & INP_TIMEWAIT) {
bzero(xt, sizeof(struct xtcpcb));
xt->t_state = TCPS_TIME_WAIT;
} else {
xt->t_state = tp->t_state;
xt->t_flags = tp->t_flags;
xt->t_sndzerowin = tp->t_sndzerowin;
xt->t_sndrexmitpack = tp->t_sndrexmitpack;
xt->t_rcvoopack = tp->t_rcvoopack;
now = getsbinuptime();
#define COPYTIMER(ttt) do { \
if (callout_active(&tp->t_timers->ttt)) \
xt->ttt = (tp->t_timers->ttt.c_time - now) / \
SBT_1MS; \
else \
xt->ttt = 0; \
} while (0)
COPYTIMER(tt_delack);
COPYTIMER(tt_rexmt);
COPYTIMER(tt_persist);
COPYTIMER(tt_keep);
COPYTIMER(tt_2msl);
#undef COPYTIMER
xt->t_rcvtime = 1000 * (ticks - tp->t_rcvtime) / hz;
bcopy(tp->t_fb->tfb_tcp_block_name, xt->xt_stack,
TCP_FUNCTION_NAME_LEN_MAX);
}
xt->xt_len = sizeof(struct xtcpcb);
in_pcbtoxinpcb(inp, &xt->xt_inp);
if (inp->inp_socket == NULL)
xt->xt_inp.xi_socket.xso_protocol = IPPROTO_TCP;
}

View File

@ -2217,13 +2217,13 @@ syncache_pcblist(struct sysctl_req *req, int max_pcbs, int *pcbs_exported)
xt.xt_inp.inp_vflag = INP_IPV6;
else
xt.xt_inp.inp_vflag = INP_IPV4;
bcopy(&sc->sc_inc, &xt.xt_inp.inp_inc, sizeof (struct in_conninfo));
xt.xt_tp.t_inpcb = &xt.xt_inp;
xt.xt_tp.t_state = TCPS_SYN_RECEIVED;
xt.xt_socket.xso_protocol = IPPROTO_TCP;
xt.xt_socket.xso_len = sizeof (struct xsocket);
xt.xt_socket.so_type = SOCK_STREAM;
xt.xt_socket.so_state = SS_ISCONNECTING;
bcopy(&sc->sc_inc, &xt.xt_inp.inp_inc,
sizeof (struct in_conninfo));
xt.t_state = TCPS_SYN_RECEIVED;
xt.xt_inp.xi_socket.xso_protocol = IPPROTO_TCP;
xt.xt_inp.xi_socket.xso_len = sizeof (struct xsocket);
xt.xt_inp.xi_socket.so_type = SOCK_STREAM;
xt.xt_inp.xi_socket.so_state = SS_ISCONNECTING;
error = SYSCTL_OUT(req, &xt, sizeof xt);
if (error) {
SCH_UNLOCK(sch);

View File

@ -1006,28 +1006,3 @@ tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type)
tp->t_timers->tt_draincnt++;
}
}
#define ticks_to_msecs(t) (1000*(t) / hz)
void
tcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer,
struct xtcp_timer *xtimer)
{
sbintime_t now;
bzero(xtimer, sizeof(*xtimer));
if (timer == NULL)
return;
now = getsbinuptime();
if (callout_active(&timer->tt_delack))
xtimer->tt_delack = (timer->tt_delack.c_time - now) / SBT_1MS;
if (callout_active(&timer->tt_rexmt))
xtimer->tt_rexmt = (timer->tt_rexmt.c_time - now) / SBT_1MS;
if (callout_active(&timer->tt_persist))
xtimer->tt_persist = (timer->tt_persist.c_time - now) / SBT_1MS;
if (callout_active(&timer->tt_keep))
xtimer->tt_keep = (timer->tt_keep.c_time - now) / SBT_1MS;
if (callout_active(&timer->tt_2msl))
xtimer->tt_2msl = (timer->tt_2msl.c_time - now) / SBT_1MS;
xtimer->t_rcvtime = ticks_to_msecs(ticks - tp->t_rcvtime);
}

View File

@ -210,8 +210,6 @@ void tcp_timer_keep(void *xtp);
void tcp_timer_persist(void *xtp);
void tcp_timer_rexmt(void *xtp);
void tcp_timer_delack(void *xtp);
void tcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer,
struct xtcp_timer *xtimer);
#endif /* _KERNEL */

View File

@ -39,15 +39,9 @@
#ifdef _KERNEL
#include <net/vnet.h>
#include <sys/mbuf.h>
#endif
/*
* Kernel variables for tcp.
*/
VNET_DECLARE(int, tcp_do_rfc1323);
#define V_tcp_do_rfc1323 VNET(tcp_do_rfc1323)
#endif /* _KERNEL */
#if defined(_KERNEL) || defined(_WANT_TCPCB)
/* TCP segment queue entry */
struct tseg_qent {
LIST_ENTRY(tseg_qent) tqe_q;
@ -83,90 +77,12 @@ struct sackhint {
uint64_t _pad[1]; /* TBD */
};
struct tcptemp {
u_char tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */
struct tcphdr tt_t;
};
#define tcp6cb tcpcb /* for KAME src sync over BSD*'s */
/*
* TODO: We yet need to brave plowing in
* to tcp_input() and the pru_usrreq() block.
* Right now these go to the old standards which
* are somewhat ok, but in the long term may
* need to be changed. If we do tackle tcp_input()
* then we need to get rid of the tcp_do_segment()
* function below.
*/
/* Flags for tcp functions */
#define TCP_FUNC_BEING_REMOVED 0x01 /* Can no longer be referenced */
struct tcpcb;
struct inpcb;
struct sockopt;
struct socket;
/*
* If defining the optional tcp_timers, in the
* tfb_tcp_timer_stop call you must use the
* callout_async_drain() function with the
* tcp_timer_discard callback. You should check
* the return of callout_async_drain() and if 0
* increment tt_draincnt. Since the timer sub-system
* does not know your callbacks you must provide a
* stop_all function that loops through and calls
* tcp_timer_stop() with each of your defined timers.
* Adding a tfb_tcp_handoff_ok function allows the socket
* option to change stacks to query you even if the
* connection is in a later stage. You return 0 to
* say you can take over and run your stack, you return
* non-zero (an error number) to say no you can't.
* If the function is undefined you can only change
* in the early states (before connect or listen).
* tfb_tcp_fb_fini is changed to add a flag to tell
* the old stack if the tcb is being destroyed or
* not. A one in the flag means the TCB is being
* destroyed, a zero indicates its transitioning to
* another stack (via socket option).
*/
struct tcp_function_block {
char tfb_tcp_block_name[TCP_FUNCTION_NAME_LEN_MAX];
int (*tfb_tcp_output)(struct tcpcb *);
void (*tfb_tcp_do_segment)(struct mbuf *, struct tcphdr *,
struct socket *, struct tcpcb *,
int, int, uint8_t,
int);
int (*tfb_tcp_ctloutput)(struct socket *so, struct sockopt *sopt,
struct inpcb *inp, struct tcpcb *tp);
/* Optional memory allocation/free routine */
void (*tfb_tcp_fb_init)(struct tcpcb *);
void (*tfb_tcp_fb_fini)(struct tcpcb *, int);
/* Optional timers, must define all if you define one */
int (*tfb_tcp_timer_stop_all)(struct tcpcb *);
void (*tfb_tcp_timer_activate)(struct tcpcb *,
uint32_t, u_int);
int (*tfb_tcp_timer_active)(struct tcpcb *, uint32_t);
void (*tfb_tcp_timer_stop)(struct tcpcb *, uint32_t);
void (*tfb_tcp_rexmit_tmr)(struct tcpcb *);
int (*tfb_tcp_handoff_ok)(struct tcpcb *);
volatile uint32_t tfb_refcnt;
uint32_t tfb_flags;
};
struct tcp_function {
TAILQ_ENTRY(tcp_function) tf_next;
struct tcp_function_block *tf_fb;
};
TAILQ_HEAD(tcp_funchead, tcp_function);
/*
* Tcp control block, one per tcp; fields:
* Organized for 16 byte cacheline efficiency.
*/
struct tcpcb {
struct tsegqe_head t_segq; /* segment reassembly queue */
void *t_pspare[2]; /* new reassembly queue */
int t_segqlen; /* segment reassembly queue length */
int t_dupacks; /* consecutive dup acks recd */
@ -197,12 +113,10 @@ struct tcpcb {
uint32_t snd_wnd; /* send window */
uint32_t snd_cwnd; /* congestion-controlled window */
u_long snd_spare1; /* unused */
uint32_t snd_ssthresh; /* snd_cwnd size threshold for
* for slow start exponential to
* linear switch
*/
u_long snd_spare2; /* unused */
tcp_seq snd_recover; /* for use in NewReno Fast Recovery */
u_int t_rcvtime; /* inactivity time */
@ -210,9 +124,6 @@ struct tcpcb {
u_int t_rtttime; /* RTT measurement start time */
tcp_seq t_rtseq; /* sequence number being timed */
u_int t_bw_spare1; /* unused */
tcp_seq t_bw_spare2; /* unused */
int t_rxtcur; /* current retransmit value (ticks) */
u_int t_maxseg; /* maximum segment size */
u_int t_pmtud_saved_maxseg; /* pre-blackhole MSS */
@ -276,32 +187,97 @@ struct tcpcb {
u_int t_tsomaxsegcount; /* TSO maximum segment count */
u_int t_tsomaxsegsize; /* TSO maximum segment size in bytes */
u_int t_flags2; /* More tcpcb flags storage */
#if defined(_KERNEL) && defined(TCP_RFC7413)
uint32_t t_ispare[6]; /* 5 UTO, 1 TBD */
uint64_t t_tfo_cookie; /* TCP Fast Open cookie */
#else
uint32_t t_ispare[8]; /* 5 UTO, 3 TBD */
#endif
struct tcp_function_block *t_fb;/* TCP function call block */
void *t_fb_ptr; /* Pointer to t_fb specific data */
#if defined(_KERNEL) && defined(TCP_RFC7413)
#ifdef TCP_RFC7413
uint64_t t_tfo_cookie; /* TCP Fast Open cookie */
unsigned int *t_tfo_pending; /* TCP Fast Open pending counter */
void *t_pspare2[1]; /* 1 TCP_SIGNATURE */
#else
void *t_pspare2[2]; /* 1 TCP_SIGNATURE, 1 TBD */
#endif
#if defined(_KERNEL) && defined(TCPPCAP)
#ifdef TCPPCAP
struct mbufq t_inpkts; /* List of saved input packets. */
struct mbufq t_outpkts; /* List of saved output packets. */
#ifdef _LP64
uint64_t _pad[0]; /* all used! */
#else
uint64_t _pad[2]; /* 2 are available */
#endif /* _LP64 */
#else
uint64_t _pad[6];
#endif /* defined(_KERNEL) && defined(TCPPCAP) */
#endif
};
#endif /* _KERNEL || _WANT_TCPCB */
#ifdef _KERNEL
/*
* Kernel variables for tcp.
*/
VNET_DECLARE(int, tcp_do_rfc1323);
#define V_tcp_do_rfc1323 VNET(tcp_do_rfc1323)
struct tcptemp {
u_char tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */
struct tcphdr tt_t;
};
/*
* TODO: We yet need to brave plowing in
* to tcp_input() and the pru_usrreq() block.
* Right now these go to the old standards which
* are somewhat ok, but in the long term may
* need to be changed. If we do tackle tcp_input()
* then we need to get rid of the tcp_do_segment()
* function below.
*/
/* Flags for tcp functions */
#define TCP_FUNC_BEING_REMOVED 0x01 /* Can no longer be referenced */
/*
* If defining the optional tcp_timers, in the
* tfb_tcp_timer_stop call you must use the
* callout_async_drain() function with the
* tcp_timer_discard callback. You should check
* the return of callout_async_drain() and if 0
* increment tt_draincnt. Since the timer sub-system
* does not know your callbacks you must provide a
* stop_all function that loops through and calls
* tcp_timer_stop() with each of your defined timers.
* Adding a tfb_tcp_handoff_ok function allows the socket
* option to change stacks to query you even if the
* connection is in a later stage. You return 0 to
* say you can take over and run your stack, you return
* non-zero (an error number) to say no you can't.
* If the function is undefined you can only change
* in the early states (before connect or listen).
* tfb_tcp_fb_fini is changed to add a flag to tell
* the old stack if the tcb is being destroyed or
* not. A one in the flag means the TCB is being
* destroyed, a zero indicates its transitioning to
* another stack (via socket option).
*/
struct tcp_function_block {
char tfb_tcp_block_name[TCP_FUNCTION_NAME_LEN_MAX];
int (*tfb_tcp_output)(struct tcpcb *);
void (*tfb_tcp_do_segment)(struct mbuf *, struct tcphdr *,
struct socket *, struct tcpcb *,
int, int, uint8_t,
int);
int (*tfb_tcp_ctloutput)(struct socket *so, struct sockopt *sopt,
struct inpcb *inp, struct tcpcb *tp);
/* Optional memory allocation/free routine */
void (*tfb_tcp_fb_init)(struct tcpcb *);
void (*tfb_tcp_fb_fini)(struct tcpcb *, int);
/* Optional timers, must define all if you define one */
int (*tfb_tcp_timer_stop_all)(struct tcpcb *);
void (*tfb_tcp_timer_activate)(struct tcpcb *,
uint32_t, u_int);
int (*tfb_tcp_timer_active)(struct tcpcb *, uint32_t);
void (*tfb_tcp_timer_stop)(struct tcpcb *, uint32_t);
void (*tfb_tcp_rexmit_tmr)(struct tcpcb *);
int (*tfb_tcp_handoff_ok)(struct tcpcb *);
volatile uint32_t tfb_refcnt;
uint32_t tfb_flags;
};
struct tcp_function {
TAILQ_ENTRY(tcp_function) tf_next;
struct tcp_function_block *tf_fb;
};
TAILQ_HEAD(tcp_funchead, tcp_function);
#endif /* _KERNEL */
/*
* Flags and utility macros for the t_flags field.
@ -656,26 +632,41 @@ struct tcp_hhook_data {
/*
* TCB structure exported to user-land via sysctl(3).
*
* Fields prefixed with "xt_" are unique to the export structure, and fields
* with "t_" or other prefixes match corresponding fields of 'struct tcpcb'.
*
* Legend:
* (s) - used by userland utilities in src
* (p) - used by utilities in ports
* (3) - is known to be used by third party software not in ports
* (n) - no known usage
*
* Evil hack: declare only if in_pcb.h and sys/socketvar.h have been
* included. Not all of our clients do.
*/
#if defined(_NETINET_IN_PCB_H_) && defined(_SYS_SOCKETVAR_H_)
struct xtcp_timer {
int tt_rexmt; /* retransmit timer */
int tt_persist; /* retransmit persistence */
int tt_keep; /* keepalive */
int tt_2msl; /* 2*msl TIME_WAIT timer */
int tt_delack; /* delayed ACK timer */
int t_rcvtime; /* Time since last packet received */
};
struct xtcpcb {
size_t xt_len;
struct inpcb xt_inp;
struct tcpcb xt_tp;
struct xsocket xt_socket;
struct xtcp_timer xt_timer;
u_quad_t xt_alignment_hack;
};
struct xtcpcb {
size_t xt_len; /* length of this structure */
struct xinpcb xt_inp;
char xt_stack[TCP_FUNCTION_NAME_LEN_MAX]; /* (n) */
int64_t spare64[8];
int32_t t_state; /* (s,p) */
uint32_t t_flags; /* (s,p) */
int32_t t_sndzerowin; /* (s) */
int32_t t_sndrexmitpack; /* (s) */
int32_t t_rcvoopack; /* (s) */
int32_t t_rcvtime; /* (s) */
int32_t tt_rexmt; /* (s) */
int32_t tt_persist; /* (s) */
int32_t tt_keep; /* (s) */
int32_t tt_2msl; /* (s) */
int32_t tt_delack; /* (s) */
int32_t spare32[32];
} __aligned(8);
#ifdef _KERNEL
void tcp_inptoxtp(const struct inpcb *, struct xtcpcb *);
#endif
#endif
/*

View File

@ -905,13 +905,7 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
if (inp->inp_gencnt <= gencnt) {
struct xinpcb xi;
bzero(&xi, sizeof(xi));
xi.xi_len = sizeof xi;
/* XXX should avoid extra copy */
bcopy(inp, &xi.xi_inp, sizeof *inp);
if (inp->inp_socket)
sotoxsocket(inp->inp_socket, &xi.xi_socket);
xi.xi_inp.inp_gencnt = inp->inp_gencnt;
in_pcbtoxinpcb(inp, &xi);
INP_RUNLOCK(inp);
error = SYSCTL_OUT(req, &xi, sizeof xi);
} else

View File

@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
#define __FreeBSD_version 1200025 /* Master, propagated to newvers */
#define __FreeBSD_version 1200026 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,

View File

@ -91,7 +91,7 @@ static int udp_done, tcp_done, sdp_done;
#endif /* INET6 */
static int
pcblist_sysctl(int proto, const char *name, char **bufp, int istcp __unused)
pcblist_sysctl(int proto, const char *name, char **bufp)
{
const char *mibvar;
char *buf;
@ -181,120 +181,6 @@ sotoxsocket(struct socket *so, struct xsocket *xso)
return (0);
}
static int
pcblist_kvm(u_long off, char **bufp, int istcp)
{
struct inpcbinfo pcbinfo;
struct inpcbhead listhead;
struct inpcb *inp;
struct xinpcb xi;
struct xinpgen xig;
struct xtcpcb xt;
struct socket so;
struct xsocket *xso;
char *buf, *p;
size_t len;
if (off == 0)
return (0);
kread(off, &pcbinfo, sizeof(pcbinfo));
if (istcp)
len = 2 * sizeof(xig) +
(pcbinfo.ipi_count + pcbinfo.ipi_count / 8) *
sizeof(struct xtcpcb);
else
len = 2 * sizeof(xig) +
(pcbinfo.ipi_count + pcbinfo.ipi_count / 8) *
sizeof(struct xinpcb);
if ((buf = malloc(len)) == NULL) {
xo_warnx("malloc %lu bytes", (u_long)len);
return (0);
}
p = buf;
#define COPYOUT(obj, size) do { \
if (len < (size)) { \
xo_warnx("buffer size exceeded"); \
goto fail; \
} \
bcopy((obj), p, (size)); \
len -= (size); \
p += (size); \
} while (0)
#define KREAD(off, buf, len) do { \
if (kread((uintptr_t)(off), (buf), (len)) != 0) \
goto fail; \
} while (0)
/* Write out header. */
xig.xig_len = sizeof xig;
xig.xig_count = pcbinfo.ipi_count;
xig.xig_gen = pcbinfo.ipi_gencnt;
xig.xig_sogen = 0;
COPYOUT(&xig, sizeof xig);
/* Walk the PCB list. */
xt.xt_len = sizeof xt;
xi.xi_len = sizeof xi;
if (istcp)
xso = &xt.xt_socket;
else
xso = &xi.xi_socket;
KREAD(pcbinfo.ipi_listhead, &listhead, sizeof(listhead));
LIST_FOREACH(inp, &listhead, inp_list) {
if (istcp) {
KREAD(inp, &xt.xt_inp, sizeof(*inp));
inp = &xt.xt_inp;
} else {
KREAD(inp, &xi.xi_inp, sizeof(*inp));
inp = &xi.xi_inp;
}
if (inp->inp_gencnt > pcbinfo.ipi_gencnt)
continue;
if (istcp) {
if (inp->inp_ppcb == NULL)
bzero(&xt.xt_tp, sizeof xt.xt_tp);
else if (inp->inp_flags & INP_TIMEWAIT) {
bzero(&xt.xt_tp, sizeof xt.xt_tp);
xt.xt_tp.t_state = TCPS_TIME_WAIT;
} else
KREAD(inp->inp_ppcb, &xt.xt_tp,
sizeof xt.xt_tp);
}
if (inp->inp_socket) {
KREAD(inp->inp_socket, &so, sizeof(so));
if (sotoxsocket(&so, xso) != 0)
goto fail;
} else {
bzero(xso, sizeof(*xso));
if (istcp)
xso->xso_protocol = IPPROTO_TCP;
}
if (istcp)
COPYOUT(&xt, sizeof xt);
else
COPYOUT(&xi, sizeof xi);
}
/* Reread the pcbinfo and write out the footer. */
kread(off, &pcbinfo, sizeof(pcbinfo));
xig.xig_count = pcbinfo.ipi_count;
xig.xig_gen = pcbinfo.ipi_gencnt;
COPYOUT(&xig, sizeof xig);
*bufp = buf;
return (1);
fail:
free(buf);
return (0);
#undef COPYOUT
#undef KREAD
}
/*
* Print a summary of connections related to an Internet
* protocol. For TCP, also give state of connection.
@ -304,15 +190,14 @@ fail:
void
protopr(u_long off, const char *name, int af1, int proto)
{
int istcp;
static int first = 1;
int istcp;
char *buf;
const char *vchar;
struct tcpcb *tp = NULL;
struct inpcb *inp;
struct xtcpcb *tp;
struct xinpcb *inp;
struct xinpgen *xig, *oxig;
struct xsocket *so;
struct xtcp_timer *timer;
istcp = 0;
switch (proto) {
@ -341,28 +226,21 @@ protopr(u_long off, const char *name, int af1, int proto)
#endif
break;
}
if (live) {
if (!pcblist_sysctl(proto, name, &buf, istcp))
return;
} else {
if (!pcblist_kvm(off, &buf, istcp))
return;
}
if (!pcblist_sysctl(proto, name, &buf))
return;
oxig = xig = (struct xinpgen *)buf;
for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
xig->xig_len > sizeof(struct xinpgen);
xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
if (istcp) {
timer = &((struct xtcpcb *)xig)->xt_timer;
tp = &((struct xtcpcb *)xig)->xt_tp;
inp = &((struct xtcpcb *)xig)->xt_inp;
so = &((struct xtcpcb *)xig)->xt_socket;
tp = (struct xtcpcb *)xig;
inp = &tp->xt_inp;
} else {
inp = &((struct xinpcb *)xig)->xi_inp;
so = &((struct xinpcb *)xig)->xi_socket;
timer = NULL;
inp = (struct xinpcb *)xig;
}
so = &inp->xi_socket;
/* Ignore sockets for protocols other than the desired one. */
if (so->xso_protocol != proto)
@ -574,25 +452,25 @@ protopr(u_long off, const char *name, int af1, int proto)
so->so_rcv.sb_lowat, so->so_snd.sb_lowat,
so->so_rcv.sb_mbcnt, so->so_snd.sb_mbcnt,
so->so_rcv.sb_mbmax, so->so_snd.sb_mbmax);
if (timer != NULL)
if (istcp)
xo_emit(" {:retransmit-timer/%4d.%02d} "
"{:persist-timer/%4d.%02d} "
"{:keepalive-timer/%4d.%02d} "
"{:msl2-timer/%4d.%02d} "
"{:delay-ack-timer/%4d.%02d} "
"{:inactivity-timer/%4d.%02d}",
timer->tt_rexmt / 1000,
(timer->tt_rexmt % 1000) / 10,
timer->tt_persist / 1000,
(timer->tt_persist % 1000) / 10,
timer->tt_keep / 1000,
(timer->tt_keep % 1000) / 10,
timer->tt_2msl / 1000,
(timer->tt_2msl % 1000) / 10,
timer->tt_delack / 1000,
(timer->tt_delack % 1000) / 10,
timer->t_rcvtime / 1000,
(timer->t_rcvtime % 1000) / 10);
tp->tt_rexmt / 1000,
(tp->tt_rexmt % 1000) / 10,
tp->tt_persist / 1000,
(tp->tt_persist % 1000) / 10,
tp->tt_keep / 1000,
(tp->tt_keep % 1000) / 10,
tp->tt_2msl / 1000,
(tp->tt_2msl % 1000) / 10,
tp->tt_delack / 1000,
(tp->tt_delack % 1000) / 10,
tp->t_rcvtime / 1000,
(tp->t_rcvtime % 1000) / 10);
}
if (istcp && !Lflag && !xflag && !Tflag && !Rflag) {
if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)

View File

@ -562,7 +562,6 @@ gather_inet(int proto)
struct xinpgen *xig, *exig;
struct xinpcb *xip;
struct xtcpcb *xtp;
struct inpcb *inp;
struct xsocket *so;
struct sock *sock;
struct addr *laddr, *faddr;
@ -625,54 +624,52 @@ gather_inet(int proto)
xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
if (xig >= exig)
break;
xip = (struct xinpcb *)xig;
xtp = (struct xtcpcb *)xig;
switch (proto) {
case IPPROTO_TCP:
xtp = (struct xtcpcb *)xig;
xip = &xtp->xt_inp;
if (xtp->xt_len != sizeof(*xtp)) {
warnx("struct xtcpcb size mismatch");
goto out;
}
inp = &xtp->xt_inp;
so = &xtp->xt_socket;
protoname = xtp->xt_tp.t_flags & TF_TOE ? "toe" : "tcp";
protoname = xtp->t_flags & TF_TOE ? "toe" : "tcp";
break;
case IPPROTO_UDP:
case IPPROTO_DIVERT:
xip = (struct xinpcb *)xig;
if (xip->xi_len != sizeof(*xip)) {
warnx("struct xinpcb size mismatch");
goto out;
}
inp = &xip->xi_inp;
so = &xip->xi_socket;
break;
default:
errx(1, "protocol %d not supported", proto);
}
if ((inp->inp_vflag & vflag) == 0)
so = &xip->xi_socket;
if ((xip->inp_vflag & vflag) == 0)
continue;
if (inp->inp_vflag & INP_IPV4) {
if ((inp->inp_fport == 0 && !opt_l) ||
(inp->inp_fport != 0 && !opt_c))
if (xip->inp_vflag & INP_IPV4) {
if ((xip->inp_fport == 0 && !opt_l) ||
(xip->inp_fport != 0 && !opt_c))
continue;
#define __IN_IS_ADDR_LOOPBACK(pina) \
((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
if (opt_L &&
(__IN_IS_ADDR_LOOPBACK(&inp->inp_faddr) ||
__IN_IS_ADDR_LOOPBACK(&inp->inp_laddr)))
(__IN_IS_ADDR_LOOPBACK(&xip->inp_faddr) ||
__IN_IS_ADDR_LOOPBACK(&xip->inp_laddr)))
continue;
#undef __IN_IS_ADDR_LOOPBACK
} else if (inp->inp_vflag & INP_IPV6) {
if ((inp->inp_fport == 0 && !opt_l) ||
(inp->inp_fport != 0 && !opt_c))
} else if (xip->inp_vflag & INP_IPV6) {
if ((xip->inp_fport == 0 && !opt_l) ||
(xip->inp_fport != 0 && !opt_c))
continue;
if (opt_L &&
(IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr) ||
IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr)))
(IN6_IS_ADDR_LOOPBACK(&xip->in6p_faddr) ||
IN6_IS_ADDR_LOOPBACK(&xip->in6p_laddr)))
continue;
} else {
if (opt_v)
warnx("invalid vflag 0x%x", inp->inp_vflag);
warnx("invalid vflag 0x%x", xip->inp_vflag);
continue;
}
if ((sock = calloc(1, sizeof(*sock))) == NULL)
@ -683,26 +680,26 @@ gather_inet(int proto)
err(1, "malloc()");
sock->socket = so->xso_so;
sock->proto = proto;
if (inp->inp_vflag & INP_IPV4) {
if (xip->inp_vflag & INP_IPV4) {
sock->family = AF_INET;
sockaddr(&laddr->address, sock->family,
&inp->inp_laddr, inp->inp_lport);
&xip->inp_laddr, xip->inp_lport);
sockaddr(&faddr->address, sock->family,
&inp->inp_faddr, inp->inp_fport);
} else if (inp->inp_vflag & INP_IPV6) {
&xip->inp_faddr, xip->inp_fport);
} else if (xip->inp_vflag & INP_IPV6) {
sock->family = AF_INET6;
sockaddr(&laddr->address, sock->family,
&inp->in6p_laddr, inp->inp_lport);
&xip->in6p_laddr, xip->inp_lport);
sockaddr(&faddr->address, sock->family,
&inp->in6p_faddr, inp->inp_fport);
&xip->in6p_faddr, xip->inp_fport);
}
laddr->next = NULL;
faddr->next = NULL;
sock->laddr = laddr;
sock->faddr = faddr;
sock->vflag = inp->inp_vflag;
sock->vflag = xip->inp_vflag;
if (proto == IPPROTO_TCP)
sock->state = xtp->xt_tp.t_state;
sock->state = xtp->t_state;
sock->protoname = protoname;
hash = (int)((uintptr_t)sock->socket % HASHSIZE);
sock->next = sockhash[hash];

View File

@ -56,7 +56,7 @@ extern int protos;
extern int verbose;
extern unsigned int delay;
struct inpcb;
struct in_conninfo;
extern struct device_selection *dev_select;
extern long generation;
@ -67,8 +67,8 @@ extern long select_generation;
extern struct nlist namelist[];
int checkhost(struct inpcb *);
int checkport(struct inpcb *);
int checkhost(struct in_conninfo *);
int checkport(struct in_conninfo *);
void closeicmp(WINDOW *);
void closeicmp6(WINDOW *);
void closeifstat(WINDOW *);

View File

@ -224,13 +224,13 @@ selectport(long port, int onoff)
}
int
checkport(struct inpcb *inp)
checkport(struct in_conninfo *inc)
{
struct pitem *p;
if (ports)
for (p = ports; p < ports+nports; p++)
if (p->port == inp->inp_lport || p->port == inp->inp_fport)
if (p->port == inc->inc_lport || p->port == inc->inc_fport)
return (p->onoff);
return (1);
}
@ -281,14 +281,14 @@ selecthost(struct in_addr *in, int onoff)
}
int
checkhost(struct inpcb *inp)
checkhost(struct in_conninfo *inc)
{
struct hitem *p;
if (hosts)
for (p = hosts; p < hosts+nhosts; p++)
if (p->addr.s_addr == inp->inp_laddr.s_addr ||
p->addr.s_addr == inp->inp_faddr.s_addr)
if (p->addr.s_addr == inc->inc_laddr.s_addr ||
p->addr.s_addr == inc->inc_faddr.s_addr)
return (p->onoff);
return (1);
}

View File

@ -52,6 +52,7 @@ static const char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93";
#ifdef INET6
#include <netinet/ip6.h>
#endif
#define _WANT_INPCB
#include <netinet/in_pcb.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
@ -62,6 +63,7 @@ static const char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93";
#define TCPSTATES
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_timer.h>
#define _WANT_TCPCB
#include <netinet/tcp_var.h>
#include <netinet/tcp_debug.h>
#include <netinet/udp.h>
@ -76,9 +78,9 @@ static const char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93";
#include "systat.h"
#include "extern.h"
static struct netinfo *enter(struct inpcb *, int, const char *);
static struct netinfo *enter(struct in_conninfo *, uint8_t, int, const char *);
static void enter_kvm(struct inpcb *, struct socket *, int, const char *);
static void enter_sysctl(struct inpcb *, struct xsocket *, int, const char *);
static void enter_sysctl(struct xinpcb *, struct xsocket *, int, const char *);
static void fetchnetstat_kvm(void);
static void fetchnetstat_sysctl(void);
static char *inetname(struct sockaddr *);
@ -212,9 +214,9 @@ again:
}
#endif
}
if (nhosts && !checkhost(&inpcb))
if (nhosts && !checkhost(&inpcb.inp_inc))
continue;
if (nports && !checkport(&inpcb))
if (nports && !checkport(&inpcb.inp_inc))
continue;
if (istcp) {
if (inpcb.inp_flags & INP_TIMEWAIT) {
@ -245,7 +247,6 @@ fetchnetstat_sysctl(void)
int idx;
struct xinpgen *inpg;
char *cur, *end;
struct inpcb *inpcb;
struct xinpcb *xip = NULL;
struct xtcpcb *xtp = NULL;
int plen;
@ -291,37 +292,36 @@ fetchnetstat_sysctl(void)
while (cur + plen <= end) {
if (idx == 0) { /* TCP */
xtp = (struct xtcpcb *)cur;
inpcb = &xtp->xt_inp;
xip = &xtp->xt_inp;
} else {
xip = (struct xinpcb *)cur;
inpcb = &xip->xi_inp;
}
cur += plen;
if (!aflag) {
if (inpcb->inp_vflag & INP_IPV4) {
if (inet_lnaof(inpcb->inp_laddr) ==
if (xip->inp_vflag & INP_IPV4) {
if (inet_lnaof(xip->inp_laddr) ==
INADDR_ANY)
continue;
}
#ifdef INET6
else if (inpcb->inp_vflag & INP_IPV6) {
if (memcmp(&inpcb->in6p_laddr,
else if (xip->inp_vflag & INP_IPV6) {
if (memcmp(&xip->in6p_laddr,
&in6addr_any, sizeof(in6addr_any))
== 0)
continue;
}
#endif
}
if (nhosts && !checkhost(inpcb))
if (nhosts && !checkhost(&xip->inp_inc))
continue;
if (nports && !checkport(inpcb))
if (nports && !checkport(&xip->inp_inc))
continue;
if (idx == 0) /* TCP */
enter_sysctl(inpcb, &xtp->xt_socket,
xtp->xt_tp.t_state, "tcp");
else /* UDP */
enter_sysctl(inpcb, &xip->xi_socket, 0, "udp");
if (idx == 0)
enter_sysctl(xip, &xip->xi_socket,
xtp->t_state, "tcp");
else
enter_sysctl(xip, &xip->xi_socket, 0, "udp");
}
free(inpg);
}
@ -332,25 +332,26 @@ enter_kvm(struct inpcb *inp, struct socket *so, int state, const char *proto)
{
struct netinfo *p;
if ((p = enter(inp, state, proto)) != NULL) {
if ((p = enter(&inp->inp_inc, inp->inp_vflag, state, proto)) != NULL) {
p->ni_rcvcc = so->so_rcv.sb_ccc;
p->ni_sndcc = so->so_snd.sb_ccc;
}
}
static void
enter_sysctl(struct inpcb *inp, struct xsocket *so, int state, const char *proto)
enter_sysctl(struct xinpcb *xip, struct xsocket *so, int state,
const char *proto)
{
struct netinfo *p;
if ((p = enter(inp, state, proto)) != NULL) {
if ((p = enter(&xip->inp_inc, xip->inp_vflag, state, proto)) != NULL) {
p->ni_rcvcc = so->so_rcv.sb_cc;
p->ni_sndcc = so->so_snd.sb_cc;
}
}
static struct netinfo *
enter(struct inpcb *inp, int state, const char *proto)
enter(struct in_conninfo *inc, uint8_t vflag, int state, const char *proto)
{
struct netinfo *p;
struct sockaddr_storage lsa, fsa;
@ -361,32 +362,32 @@ enter(struct inpcb *inp, int state, const char *proto)
memset(&lsa, 0, sizeof(lsa));
memset(&fsa, 0, sizeof(fsa));
if (inp->inp_vflag & INP_IPV4) {
if (vflag & INP_IPV4) {
sa4 = (struct sockaddr_in *)&lsa;
sa4->sin_addr = inp->inp_laddr;
sa4->sin_port = inp->inp_lport;
sa4->sin_addr = inc->inc_laddr;
sa4->sin_port = inc->inc_lport;
sa4->sin_family = AF_INET;
sa4->sin_len = sizeof(struct sockaddr_in);
sa4 = (struct sockaddr_in *)&fsa;
sa4->sin_addr = inp->inp_faddr;
sa4->sin_port = inp->inp_fport;
sa4->sin_addr = inc->inc_faddr;
sa4->sin_port = inc->inc_fport;
sa4->sin_family = AF_INET;
sa4->sin_len = sizeof(struct sockaddr_in);
}
#ifdef INET6
else if (inp->inp_vflag & INP_IPV6) {
else if (vflag & INP_IPV6) {
sa6 = (struct sockaddr_in6 *)&lsa;
memcpy(&sa6->sin6_addr, &inp->in6p_laddr,
memcpy(&sa6->sin6_addr, &inc->inc6_laddr,
sizeof(struct in6_addr));
sa6->sin6_port = inp->inp_lport;
sa6->sin6_port = inc->inc_lport;
sa6->sin6_family = AF_INET6;
sa6->sin6_len = sizeof(struct sockaddr_in6);
sa6 = (struct sockaddr_in6 *)&fsa;
memcpy(&sa6->sin6_addr, &inp->in6p_faddr,
memcpy(&sa6->sin6_addr, &inc->inc6_faddr,
sizeof(struct in6_addr));
sa6->sin6_port = inp->inp_fport;
sa6->sin6_port = inc->inc_fport;
sa6->sin6_family = AF_INET6;
sa6->sin6_len = sizeof(struct sockaddr_in6);
}

View File

@ -205,9 +205,8 @@ static bool
tcpdropall(void)
{
struct xinpgen *head, *xinp;
struct xtcpcb *xpcb;
struct tcpcb *tp;
struct inpcb *inp;
struct xtcpcb *xtp;
struct xinpcb *xip;
bool ok;
ok = true;
@ -219,9 +218,8 @@ tcpdropall(void)
for (xinp = XINP_NEXT(head); xinp->xig_len > sizeof *xinp;
xinp = XINP_NEXT(xinp)) {
xpcb = (struct xtcpcb *)xinp;
tp = &xpcb->xt_tp;
inp = &xpcb->xt_inp;
xtp = (struct xtcpcb *)xinp;
xip = &xtp->xt_inp;
/*
* XXX
@ -229,14 +227,14 @@ tcpdropall(void)
*/
/* Ignore PCBs which were freed during copyout. */
if (inp->inp_gencnt > head->xig_gen)
if (xip->inp_gencnt > head->xig_gen)
continue;
/* Skip listening sockets. */
if (tp->t_state == TCPS_LISTEN)
if (xtp->t_state == TCPS_LISTEN)
continue;
if (!tcpdropconn(&inp->inp_inc))
if (!tcpdropconn(&xip->inp_inc))
ok = false;
}
free(head);

View File

@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/tcp_seq.h>
#define TCPTIMERS
#include <netinet/tcp_timer.h>
#define _WANT_TCPCB
#include <netinet/tcp_var.h>
#include <netinet/tcpip.h>
#define TANAMES