2 * nsiproxy.sys tcp module
4 * Copyright 2003, 2006, 2011 Juan Lang
5 * Copyright 2007 TransGaming Technologies Inc.
6 * Copyright 2021 Huw Davies
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #ifdef HAVE_SYS_PARAM_H
26 #include <sys/param.h>
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
41 #ifdef HAVE_SYS_SOCKET_H
42 #include <sys/socket.h>
45 #ifdef HAVE_SYS_SOCKETVAR_H
46 #include <sys/socketvar.h>
49 #ifdef HAVE_NETINET_IN_H
50 #include <netinet/in.h>
53 #ifdef HAVE_NETINET_IN_PCB_H
54 #include <netinet/in_pcb.h>
57 #ifdef HAVE_NETINET_IP_VAR_H
58 #include <netinet/ip_var.h>
61 #ifdef HAVE_SYS_QUEUE_H
62 #include <sys/queue.h>
65 #ifdef HAVE_NETINET_TCP_VAR_H
66 #include <netinet/tcp_var.h>
69 #ifdef HAVE_NETINET_TCP_FSM_H
70 #include <netinet/tcp_fsm.h>
73 #ifdef HAVE_SYS_SYSCTL_H
74 #include <sys/sysctl.h>
81 #ifdef HAVE_LIBPROCSTAT_H
82 #include <libprocstat.h>
90 #define WIN32_NO_STATUS
100 #include "wine/heap.h"
101 #include "wine/nsi.h"
102 #include "wine/debug.h"
103 #include "wine/server.h"
105 #include "nsiproxy_private.h"
107 #ifndef HAVE_NETINET_TCP_FSM_H
108 #define TCPS_ESTABLISHED 1
109 #define TCPS_SYN_SENT 2
110 #define TCPS_SYN_RECEIVED 3
111 #define TCPS_FIN_WAIT_1 4
112 #define TCPS_FIN_WAIT_2 5
113 #define TCPS_TIME_WAIT 6
114 #define TCPS_CLOSED 7
115 #define TCPS_CLOSE_WAIT 8
116 #define TCPS_LAST_ACK 9
117 #define TCPS_LISTEN 10
118 #define TCPS_CLOSING 11
121 WINE_DEFAULT_DEBUG_CHANNEL(nsi
);
123 static NTSTATUS
tcp_stats_get_all_parameters( const void *key
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
124 void *dynamic_data
, DWORD dynamic_size
, void *static_data
, DWORD static_size
)
126 struct nsi_tcp_stats_dynamic dyn
;
127 struct nsi_tcp_stats_static stat
;
128 const USHORT
*family
= key
;
130 TRACE( "%p %d %p %d %p %d %p %d\n", key
, key_size
, rw_data
, rw_size
, dynamic_data
, dynamic_size
,
131 static_data
, static_size
);
133 if (*family
!= WS_AF_INET
&& *family
!= WS_AF_INET6
) return STATUS_NOT_SUPPORTED
;
135 memset( &dyn
, 0, sizeof(dyn
) );
136 memset( &stat
, 0, sizeof(stat
) );
140 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
141 static const char hdr
[] = "Tcp:";
145 /* linux merges tcp4 and tcp6 stats, so simply supply that for either family */
146 if (!(fp
= fopen( "/proc/net/snmp", "r" ))) return STATUS_NOT_SUPPORTED
;
148 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
150 if (_strnicmp( buf
, hdr
, sizeof(hdr
) - 1 )) continue;
151 /* last line was a header, get another */
152 if (!(ptr
= fgets( buf
, sizeof(buf
), fp
))) break;
153 if (!_strnicmp( buf
, hdr
, sizeof(hdr
) - 1 ))
155 DWORD in_segs
, out_segs
;
157 sscanf( ptr
, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u",
172 dyn
.in_segs
= in_segs
;
173 dyn
.out_segs
= out_segs
;
174 if (dynamic_data
) *(struct nsi_tcp_stats_dynamic
*)dynamic_data
= dyn
;
175 if (static_data
) *(struct nsi_tcp_stats_static
*)static_data
= stat
;
176 status
= STATUS_SUCCESS
;
183 #elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_STATS) && (defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT) || defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT))
185 #ifndef TCPTV_MIN /* got removed in Mac OS X for some reason */
187 #define TCPTV_REXMTMAX 128
189 int mib
[] = { CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_STATS
};
191 #if defined(HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT)
192 struct tcpstat tcp_stat
;
193 #elif defined(HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT)
194 struct tcp_stats tcp_stat
;
196 size_t needed
= sizeof(tcp_stat
);
198 if (sysctl( mib
, ARRAY_SIZE(mib
), &tcp_stat
, &needed
, NULL
, 0 ) == -1) return STATUS_NOT_SUPPORTED
;
200 stat
.rto_algo
= MIB_TCP_RTO_VANJ
;
201 stat
.rto_min
= TCPTV_MIN
;
202 stat
.rto_max
= TCPTV_REXMTMAX
;
204 dyn
.active_opens
= tcp_stat
.tcps_connattempt
;
205 dyn
.passive_opens
= tcp_stat
.tcps_accepts
;
206 dyn
.attempt_fails
= tcp_stat
.tcps_conndrops
;
207 dyn
.est_rsts
= tcp_stat
.tcps_drops
;
210 dyn
.in_segs
= tcp_stat
.tcps_rcvtotal
;
211 dyn
.out_segs
= tcp_stat
.tcps_sndtotal
- tcp_stat
.tcps_sndrexmitpack
;
212 dyn
.retrans_segs
= tcp_stat
.tcps_sndrexmitpack
;
213 dyn
.out_rsts
= tcp_stat
.tcps_sndctrl
- tcp_stat
.tcps_closed
;
214 dyn
.in_errs
= tcp_stat
.tcps_rcvbadsum
+ tcp_stat
.tcps_rcvbadoff
+ tcp_stat
.tcps_rcvmemdrop
+ tcp_stat
.tcps_rcvshort
;
215 dyn
.num_conns
= tcp_stat
.tcps_connects
;
216 if (dynamic_data
) *(struct nsi_tcp_stats_dynamic
*)dynamic_data
= dyn
;
217 if (static_data
) *(struct nsi_tcp_stats_static
*)static_data
= stat
;
218 return STATUS_SUCCESS
;
221 FIXME( "not implemented\n" );
222 return STATUS_NOT_IMPLEMENTED
;
226 static inline MIB_TCP_STATE
tcp_state_to_mib_state( int state
)
230 case TCPS_ESTABLISHED
: return MIB_TCP_STATE_ESTAB
;
231 case TCPS_SYN_SENT
: return MIB_TCP_STATE_SYN_SENT
;
232 case TCPS_SYN_RECEIVED
: return MIB_TCP_STATE_SYN_RCVD
;
233 case TCPS_FIN_WAIT_1
: return MIB_TCP_STATE_FIN_WAIT1
;
234 case TCPS_FIN_WAIT_2
: return MIB_TCP_STATE_FIN_WAIT2
;
235 case TCPS_TIME_WAIT
: return MIB_TCP_STATE_TIME_WAIT
;
236 case TCPS_CLOSE_WAIT
: return MIB_TCP_STATE_CLOSE_WAIT
;
237 case TCPS_LAST_ACK
: return MIB_TCP_STATE_LAST_ACK
;
238 case TCPS_LISTEN
: return MIB_TCP_STATE_LISTEN
;
239 case TCPS_CLOSING
: return MIB_TCP_STATE_CLOSING
;
241 case TCPS_CLOSED
: return MIB_TCP_STATE_CLOSED
;
245 struct ipv6_addr_scope
*get_ipv6_addr_scope_table( unsigned int *size
)
247 struct ipv6_addr_scope
*table
= NULL
;
248 unsigned int table_size
= 0, num
= 0;
255 if (!(fp
= fopen( "/proc/net/if_inet6", "r" ))) goto failed
;
257 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
261 struct ipv6_addr_scope
*entry
;
264 if (sscanf( ptr
, "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx %*s %*s %x",
265 a
, a
+ 1, a
+ 2, a
+ 3, a
+ 4, a
+ 5, a
+ 6, a
+ 7, &scope
) != 9)
268 if (++num
> table_size
)
270 if (!table_size
) table_size
= 4;
271 else table_size
*= 2;
272 if (!(table
= heap_realloc( table
, table_size
* sizeof(table
[0]) )))
279 entry
= table
+ num
- 1;
280 for (i
= 0; i
< 8; i
++)
281 entry
->addr
.u
.Word
[i
] = htons( a
[i
] );
282 entry
->scope
= htons( scope
);
287 #elif defined(HAVE_GETIFADDRS)
289 struct ifaddrs
*addrs
, *cur
;
291 if (getifaddrs( &addrs
) == -1) goto failed
;
293 for (cur
= addrs
; cur
; cur
= cur
->ifa_next
)
295 struct sockaddr_in6
*sin6
;
296 struct ipv6_addr_scope
*entry
;
298 if (cur
->ifa_addr
->sa_family
!= AF_INET6
) continue;
300 if (++num
> table_size
)
302 if (!table_size
) table_size
= 4;
303 else table_size
*= 2;
304 if (!(table
= heap_realloc( table
, table_size
* sizeof(table
[0]) )))
306 freeifaddrs( addrs
);
311 sin6
= (struct sockaddr_in6
*)cur
->ifa_addr
;
312 entry
= table
+ num
- 1;
313 memcpy( &entry
->addr
, &sin6
->sin6_addr
, sizeof(entry
->addr
) );
314 entry
->scope
= sin6
->sin6_scope_id
;
317 freeifaddrs( addrs
);
320 FIXME( "not implemented\n" );
332 DWORD
find_ipv6_addr_scope( const IN6_ADDR
*addr
, const struct ipv6_addr_scope
*table
, unsigned int size
)
334 const BYTE multicast_scope_mask
= 0x0F;
335 const BYTE multicast_scope_shift
= 0;
338 if (WS_IN6_IS_ADDR_UNSPECIFIED( addr
)) return 0;
340 if (WS_IN6_IS_ADDR_MULTICAST( addr
))
341 return htons( (addr
->u
.Byte
[1] & multicast_scope_mask
) >> multicast_scope_shift
);
343 if (!table
) return -1;
345 for (i
= 0; i
< size
; i
++)
346 if (!memcmp( &table
[i
].addr
, addr
, sizeof(table
[i
].addr
) ))
347 return table
[i
].scope
;
352 struct pid_map
*get_pid_map( unsigned int *num_entries
)
355 unsigned int i
= 0, buffer_len
= 4096, process_count
, pos
= 0;
357 char *buffer
= NULL
, *new_buffer
;
359 if (!(buffer
= heap_alloc( buffer_len
))) return NULL
;
363 SERVER_START_REQ( list_processes
)
365 wine_server_set_reply( req
, buffer
, buffer_len
);
366 ret
= wine_server_call( req
);
367 buffer_len
= reply
->info_size
;
368 process_count
= reply
->process_count
;
372 if (ret
!= STATUS_INFO_LENGTH_MISMATCH
) break;
374 if (!(new_buffer
= heap_realloc( buffer
, buffer_len
)))
382 if (!(map
= heap_alloc( process_count
* sizeof(*map
) )))
388 for (i
= 0; i
< process_count
; ++i
)
390 const struct process_info
*process
;
392 pos
= (pos
+ 7) & ~7;
393 process
= (const struct process_info
*)(buffer
+ pos
);
395 map
[i
].pid
= process
->pid
;
396 map
[i
].unix_pid
= process
->unix_pid
;
398 pos
+= sizeof(struct process_info
) + process
->name_len
;
399 pos
= (pos
+ 7) & ~7;
400 pos
+= process
->thread_count
* sizeof(struct thread_info
);
404 *num_entries
= process_count
;
408 unsigned int find_owning_pid( struct pid_map
*map
, unsigned int num_entries
, UINT_PTR inode
)
411 unsigned int i
, len_socket
;
414 sprintf( socket
, "socket:[%lu]", inode
);
415 len_socket
= strlen( socket
);
416 for (i
= 0; i
< num_entries
; i
++)
419 struct dirent
*dirent
;
422 sprintf( dir
, "/proc/%u/fd", map
[i
].unix_pid
);
423 if ((dirfd
= opendir( dir
)))
425 while ((dirent
= readdir( dirfd
)))
427 char link
[sizeof(dirent
->d_name
) + 32], name
[32];
430 sprintf( link
, "/proc/%u/fd/%s", map
[i
].unix_pid
, dirent
->d_name
);
431 if ((len
= readlink( link
, name
, sizeof(name
) - 1 )) > 0) name
[len
] = 0;
432 if (len
== len_socket
&& !strcmp( socket
, name
))
442 #elif defined(HAVE_LIBPROCSTAT)
443 struct procstat
*pstat
;
444 struct kinfo_proc
*proc
;
445 struct filestat_list
*fds
;
447 struct sockstat sock
;
448 unsigned int i
, proc_count
;
450 pstat
= procstat_open_sysctl();
451 if (!pstat
) return 0;
453 for (i
= 0; i
< num_entries
; i
++)
455 proc
= procstat_getprocs( pstat
, KERN_PROC_PID
, map
[i
].unix_pid
, &proc_count
);
456 if (!proc
|| proc_count
< 1) continue;
458 fds
= procstat_getfiles( pstat
, proc
, 0 );
461 procstat_freeprocs( pstat
, proc
);
465 STAILQ_FOREACH( fd
, fds
, next
)
467 char errbuf
[_POSIX2_LINE_MAX
];
469 if (fd
->fs_type
!= PS_FST_TYPE_SOCKET
) continue;
471 procstat_get_socket_info( pstat
, fd
, &sock
, errbuf
);
473 if (sock
.so_pcb
== inode
)
475 procstat_freefiles( pstat
, fds
);
476 procstat_freeprocs( pstat
, proc
);
477 procstat_close( pstat
);
482 procstat_freefiles( pstat
, fds
);
483 procstat_freeprocs( pstat
, proc
);
486 procstat_close( pstat
);
488 #elif defined(HAVE_PROC_PIDINFO)
489 struct proc_fdinfo
*fds
;
490 struct socket_fdinfo sock
;
491 unsigned int i
, j
, n
;
493 for (i
= 0; i
< num_entries
; i
++)
495 int fd_len
= proc_pidinfo( map
[i
].unix_pid
, PROC_PIDLISTFDS
, 0, NULL
, 0 );
496 if (fd_len
<= 0) continue;
498 fds
= heap_alloc( fd_len
);
501 proc_pidinfo( map
[i
].unix_pid
, PROC_PIDLISTFDS
, 0, fds
, fd_len
);
502 n
= fd_len
/ sizeof(struct proc_fdinfo
);
503 for (j
= 0; j
< n
; j
++)
505 if (fds
[j
].proc_fdtype
!= PROX_FDTYPE_SOCKET
) continue;
507 proc_pidfdinfo( map
[i
].unix_pid
, fds
[j
].proc_fd
, PROC_PIDFDSOCKETINFO
, &sock
, sizeof(sock
) );
508 if (sock
.psi
.soi_pcb
== inode
)
519 FIXME( "not implemented\n" );
524 static NTSTATUS
tcp_conns_enumerate_all( DWORD filter
, struct nsi_tcp_conn_key
*key_data
, DWORD key_size
,
525 void *rw
, DWORD rw_size
,
526 struct nsi_tcp_conn_dynamic
*dynamic_data
, DWORD dynamic_size
,
527 struct nsi_tcp_conn_static
*static_data
, DWORD static_size
, DWORD_PTR
*count
)
530 NTSTATUS status
= STATUS_SUCCESS
;
531 BOOL want_data
= key_size
|| rw_size
|| dynamic_size
|| static_size
;
532 struct nsi_tcp_conn_key key
;
533 struct nsi_tcp_conn_dynamic dyn
;
534 struct nsi_tcp_conn_static stat
;
535 struct ipv6_addr_scope
*addr_scopes
= NULL
;
536 unsigned int addr_scopes_size
= 0, pid_map_size
= 0;
537 struct pid_map
*pid_map
= NULL
;
545 if (!(fp
= fopen( "/proc/net/tcp", "r" ))) return ERROR_NOT_SUPPORTED
;
547 memset( &key
, 0, sizeof(key
) );
548 memset( &dyn
, 0, sizeof(dyn
) );
549 memset( &stat
, 0, sizeof(stat
) );
550 pid_map
= get_pid_map( &pid_map_size
);
552 /* skip header line */
553 ptr
= fgets( buf
, sizeof(buf
), fp
);
554 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
556 if (sscanf( ptr
, "%*x: %x:%hx %x:%hx %x %*s %*s %*s %*s %*s %d",
557 &key
.local
.Ipv4
.sin_addr
.WS_s_addr
, &key
.local
.Ipv4
.sin_port
,
558 &key
.remote
.Ipv4
.sin_addr
.WS_s_addr
, &key
.remote
.Ipv4
.sin_port
,
559 &dyn
.state
, &inode
) != 6)
561 dyn
.state
= tcp_state_to_mib_state( dyn
.state
);
562 if (filter
&& filter
!= dyn
.state
) continue;
564 key
.local
.Ipv4
.sin_family
= key
.remote
.Ipv4
.sin_family
= WS_AF_INET
;
565 key
.local
.Ipv4
.sin_port
= htons( key
.local
.Ipv4
.sin_port
);
566 key
.remote
.Ipv4
.sin_port
= htons( key
.remote
.Ipv4
.sin_port
);
568 stat
.pid
= find_owning_pid( pid_map
, pid_map_size
, inode
);
569 stat
.create_time
= 0; /* FIXME */
570 stat
.mod_info
= 0; /* FIXME */
574 if (key_data
) *key_data
++ = key
;
575 if (dynamic_data
) *dynamic_data
++ = dyn
;
576 if (static_data
) *static_data
++ = stat
;
582 if ((fp
= fopen( "/proc/net/tcp6", "r" )))
584 memset( &key
, 0, sizeof(key
) );
585 memset( &dyn
, 0, sizeof(dyn
) );
586 memset( &stat
, 0, sizeof(stat
) );
588 addr_scopes
= get_ipv6_addr_scope_table( &addr_scopes_size
);
590 /* skip header line */
591 ptr
= fgets( buf
, sizeof(buf
), fp
);
592 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
594 DWORD
*local_addr
= (DWORD
*)&key
.local
.Ipv6
.sin6_addr
;
595 DWORD
*remote_addr
= (DWORD
*)&key
.remote
.Ipv6
.sin6_addr
;
597 if (sscanf( ptr
, "%*u: %8x%8x%8x%8x:%hx %8x%8x%8x%8x:%hx %x %*s %*s %*s %*s %*s %*s %*s %d",
598 local_addr
, local_addr
+ 1, local_addr
+ 2, local_addr
+ 3, &key
.local
.Ipv6
.sin6_port
,
599 remote_addr
, remote_addr
+ 1, remote_addr
+ 2, remote_addr
+ 3, &key
.remote
.Ipv6
.sin6_port
,
600 &dyn
.state
, &inode
) != 12)
602 dyn
.state
= tcp_state_to_mib_state( dyn
.state
);
603 if (filter
&& filter
!= dyn
.state
) continue;
604 key
.local
.Ipv6
.sin6_family
= key
.remote
.Ipv6
.sin6_family
= WS_AF_INET6
;
605 key
.local
.Ipv6
.sin6_port
= htons( key
.local
.Ipv6
.sin6_port
);
606 key
.remote
.Ipv6
.sin6_port
= htons( key
.remote
.Ipv6
.sin6_port
);
607 key
.local
.Ipv6
.sin6_scope_id
= find_ipv6_addr_scope( &key
.local
.Ipv6
.sin6_addr
, addr_scopes
,
609 key
.remote
.Ipv6
.sin6_scope_id
= find_ipv6_addr_scope( &key
.remote
.Ipv6
.sin6_addr
, addr_scopes
,
612 stat
.pid
= find_owning_pid( pid_map
, pid_map_size
, inode
);
613 stat
.create_time
= 0; /* FIXME */
614 stat
.mod_info
= 0; /* FIXME */
618 if (key_data
) *key_data
++ = key
;
619 if (dynamic_data
) *dynamic_data
++ = dyn
;
620 if (static_data
) *static_data
++ = stat
;
627 #elif defined(HAVE_SYS_SYSCTL_H) && defined(TCPCTL_PCBLIST) && defined(HAVE_STRUCT_XINPGEN)
629 int mib
[] = { CTL_NET
, PF_INET
, IPPROTO_TCP
, TCPCTL_PCBLIST
};
632 struct xinpgen
*xig
, *orig_xig
;
634 if (sysctl( mib
, ARRAY_SIZE(mib
), NULL
, &len
, NULL
, 0 ) < 0)
636 ERR( "Failure to read net.inet.tcp.pcblist via sysctl\n" );
637 status
= STATUS_NOT_SUPPORTED
;
641 buf
= heap_alloc( len
);
644 status
= STATUS_NO_MEMORY
;
648 if (sysctl( mib
, ARRAY_SIZE(mib
), buf
, &len
, NULL
, 0 ) < 0)
650 ERR( "Failure to read net.inet.tcp.pcblist via sysctl\n" );
651 status
= STATUS_NOT_SUPPORTED
;
655 /* Might be nothing here; first entry is just a header it seems */
656 if (len
<= sizeof(struct xinpgen
)) goto err
;
658 addr_scopes
= get_ipv6_addr_scope_table( &addr_scopes_size
);
659 pid_map
= get_pid_map( &pid_map_size
);
661 orig_xig
= (struct xinpgen
*)buf
;
664 for (xig
= (struct xinpgen
*)((char *)xig
+ xig
->xig_len
);
665 xig
->xig_len
> sizeof(struct xinpgen
);
666 xig
= (struct xinpgen
*)((char *)xig
+ xig
->xig_len
))
668 #if __FreeBSD_version >= 1200026
669 struct xtcpcb
*tcp
= (struct xtcpcb
*)xig
;
670 struct xinpcb
*in
= &tcp
->xt_inp
;
671 struct xsocket
*sock
= &in
->xi_socket
;
673 struct tcpcb
*tcp
= &((struct xtcpcb
*)xig
)->xt_tp
;
674 struct inpcb
*in
= &((struct xtcpcb
*)xig
)->xt_inp
;
675 struct xsocket
*sock
= &((struct xtcpcb
*)xig
)->xt_socket
;
677 static const struct in6_addr zero
;
679 /* Ignore sockets for other protocols */
680 if (sock
->xso_protocol
!= IPPROTO_TCP
) continue;
682 /* Ignore PCBs that were freed while generating the data */
683 if (in
->inp_gencnt
> orig_xig
->xig_gen
) continue;
685 /* we're only interested in IPv4 and IPV6 addresses */
686 if (!(in
->inp_vflag
& (INP_IPV4
| INP_IPV6
))) continue;
688 /* If all 0's, skip it */
689 if (in
->inp_vflag
& INP_IPV4
&& !in
->inp_laddr
.s_addr
&& !in
->inp_lport
&&
690 !in
->inp_faddr
.s_addr
&& !in
->inp_fport
) continue;
691 if (in
->inp_vflag
& INP_IPV6
&& !memcmp( &in
->in6p_laddr
, &zero
, sizeof(zero
) ) && !in
->inp_lport
&&
692 !memcmp( &in
->in6p_faddr
, &zero
, sizeof(zero
) ) && !in
->inp_fport
) continue;
694 dyn
.state
= tcp_state_to_mib_state( tcp
->t_state
);
695 if (filter
&& filter
!= dyn
.state
) continue;
697 if (in
->inp_vflag
& INP_IPV4
)
699 key
.local
.Ipv4
.sin_family
= key
.remote
.Ipv4
.sin_family
= WS_AF_INET
;
700 key
.local
.Ipv4
.sin_addr
.WS_s_addr
= in
->inp_laddr
.s_addr
;
701 key
.local
.Ipv4
.sin_port
= in
->inp_lport
;
702 key
.remote
.Ipv4
.sin_addr
.WS_s_addr
= in
->inp_faddr
.s_addr
;
703 key
.remote
.Ipv4
.sin_port
= in
->inp_fport
;
707 key
.local
.Ipv6
.sin6_family
= key
.remote
.Ipv6
.sin6_family
= WS_AF_INET6
;
708 memcpy( &key
.local
.Ipv6
.sin6_addr
, &in
->in6p_laddr
, sizeof(in
->in6p_laddr
) );
709 key
.local
.Ipv6
.sin6_port
= in
->inp_lport
;
710 key
.local
.Ipv6
.sin6_scope_id
= find_ipv6_addr_scope( &key
.local
.Ipv6
.sin6_addr
, addr_scopes
,
712 memcpy( &key
.remote
.Ipv6
.sin6_addr
, &in
->in6p_faddr
, sizeof(in
->in6p_faddr
) );
713 key
.remote
.Ipv6
.sin6_port
= in
->inp_fport
;
714 key
.remote
.Ipv6
.sin6_scope_id
= find_ipv6_addr_scope( &key
.remote
.Ipv6
.sin6_addr
, addr_scopes
,
718 stat
.pid
= find_owning_pid( pid_map
, pid_map_size
, (UINT_PTR
)sock
->so_pcb
);
719 stat
.create_time
= 0; /* FIXME */
720 stat
.mod_info
= 0; /* FIXME */
724 if (key_data
) *key_data
++ = key
;
725 if (dynamic_data
) *dynamic_data
++ = dyn
;
726 if (static_data
) *static_data
++ = stat
;
734 FIXME( "not implemented\n" );
735 status
= STATUS_NOT_IMPLEMENTED
;
738 if (!want_data
|| num
<= *count
) *count
= num
;
739 else status
= STATUS_MORE_ENTRIES
;
741 heap_free( pid_map
);
742 heap_free( addr_scopes
);
746 static NTSTATUS
tcp_all_enumerate_all( void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
747 void *dynamic_data
, DWORD dynamic_size
,
748 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
750 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data
, key_size
, rw_data
, rw_size
,
751 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
753 return tcp_conns_enumerate_all( 0, key_data
, key_size
, rw_data
, rw_size
,
754 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
757 static NTSTATUS
tcp_estab_enumerate_all( void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
758 void *dynamic_data
, DWORD dynamic_size
,
759 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
761 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data
, key_size
, rw_data
, rw_size
,
762 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
764 return tcp_conns_enumerate_all( MIB_TCP_STATE_ESTAB
, key_data
, key_size
, rw_data
, rw_size
,
765 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
768 static NTSTATUS
tcp_listen_enumerate_all( void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
769 void *dynamic_data
, DWORD dynamic_size
,
770 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
772 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data
, key_size
, rw_data
, rw_size
,
773 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
775 return tcp_conns_enumerate_all( MIB_TCP_STATE_LISTEN
, key_data
, key_size
, rw_data
, rw_size
,
776 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
779 static struct module_table tcp_tables
[] =
785 sizeof(struct nsi_tcp_stats_dynamic
), sizeof(struct nsi_tcp_stats_static
)
788 tcp_stats_get_all_parameters
,
793 sizeof(struct nsi_tcp_conn_key
), 0,
794 sizeof(struct nsi_tcp_conn_dynamic
), sizeof(struct nsi_tcp_conn_static
)
796 tcp_all_enumerate_all
,
801 sizeof(struct nsi_tcp_conn_key
), 0,
802 sizeof(struct nsi_tcp_conn_dynamic
), sizeof(struct nsi_tcp_conn_static
)
804 tcp_estab_enumerate_all
,
807 NSI_TCP_LISTEN_TABLE
,
809 sizeof(struct nsi_tcp_conn_key
), 0,
810 sizeof(struct nsi_tcp_conn_dynamic
), sizeof(struct nsi_tcp_conn_static
)
812 tcp_listen_enumerate_all
,
819 const struct module tcp_module
=
821 &NPI_MS_TCP_MODULEID
,