kernel32/tests/pipe: Enable compilation with long types.
[wine.git] / dlls / nsiproxy.sys / ip.c
blob3194dd1552499f1db9679d676c0aa0d8c3964230
1 /*
2 * nsiproxy.sys ipv4 and ipv6 modules
4 * Copyright 2003, 2006, 2011 Juan Lang
5 * Copyright 2021 Huw Davies
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
30 #ifdef HAVE_NET_ROUTE_H
31 #include <net/route.h>
32 #endif
34 #ifdef HAVE_SYS_SYSCTL_H
35 #include <sys/sysctl.h>
36 #endif
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
42 #ifdef HAVE_NETINET_IP_H
43 #include <netinet/ip.h>
44 #endif
46 #ifdef HAVE_NETINET_IN_SYSTM_H
47 #include <netinet/in_systm.h>
48 #endif
50 #ifdef HAVE_NETINET_IP_ICMP_H
51 #include <netinet/ip_icmp.h>
52 #endif
54 #ifdef HAVE_NETINET_IP_VAR_H
55 #include <netinet/ip_var.h>
56 #endif
58 #ifdef HAVE_NETINET_ICMP_VAR_H
59 #include <netinet/icmp_var.h>
60 #endif
62 #ifdef HAVE_NETINET_IF_ETHER_H
63 #include <netinet/if_ether.h>
64 #endif
66 #ifdef HAVE_NET_IF_ARP_H
67 #include <net/if_arp.h>
68 #endif
70 #ifdef HAVE_NET_IF_DL_H
71 #include <net/if_dl.h>
72 #endif
74 #ifdef HAVE_IFADDRS_H
75 #include <ifaddrs.h>
76 #endif
78 #ifdef HAVE_ARPA_INET_H
79 #include <arpa/inet.h>
80 #endif
82 #include "ntstatus.h"
83 #define WIN32_NO_STATUS
84 #include "windef.h"
85 #include "winbase.h"
86 #include "winternl.h"
87 #include "winioctl.h"
88 #define USE_WS_PREFIX
89 #include "winsock2.h"
90 #include "ws2ipdef.h"
91 #include "nldef.h"
92 #include "ifdef.h"
93 #include "ipmib.h"
94 #include "netiodef.h"
95 #include "wine/nsi.h"
96 #include "wine/debug.h"
98 #include "unix_private.h"
100 WINE_DEFAULT_DEBUG_CHANNEL(nsi);
102 static inline DWORD nsi_popcount( DWORD m )
104 #ifdef HAVE___BUILTIN_POPCOUNT
105 return __builtin_popcount( m );
106 #else
107 m -= m >> 1 & 0x55555555;
108 m = (m & 0x33333333) + (m >> 2 & 0x33333333);
109 return ((m + (m >> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
110 #endif
113 static DWORD mask_v4_to_prefix( struct in_addr *addr )
115 return nsi_popcount( addr->s_addr );
118 static DWORD mask_v6_to_prefix( struct in6_addr *addr )
120 DWORD ret;
122 ret = nsi_popcount( *(DWORD *)addr->s6_addr );
123 ret += nsi_popcount( *(DWORD *)(addr->s6_addr + 4) );
124 ret += nsi_popcount( *(DWORD *)(addr->s6_addr + 8) );
125 ret += nsi_popcount( *(DWORD *)(addr->s6_addr + 12) );
126 return ret;
129 static ULONG64 get_boot_time( void )
131 SYSTEM_TIMEOFDAY_INFORMATION ti;
133 NtQuerySystemInformation( SystemTimeOfDayInformation, &ti, sizeof(ti), NULL );
134 return ti.BootTime.QuadPart;
137 #if __linux__
138 static NTSTATUS read_sysctl_int( const char *file, int *val )
140 FILE *fp;
141 char buf[128], *endptr = buf;
143 fp = fopen( file, "r" );
144 if (!fp) return STATUS_NOT_SUPPORTED;
146 if (fgets( buf, sizeof(buf), fp ))
147 *val = strtol( buf, &endptr, 10 );
149 fclose( fp );
150 return (endptr == buf) ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS;
152 #endif
154 static NTSTATUS ip_cmpt_get_all_parameters( DWORD fam, const DWORD *key, DWORD key_size,
155 struct nsi_ip_cmpt_rw *rw_data, DWORD rw_size,
156 struct nsi_ip_cmpt_dynamic *dynamic_data, DWORD dynamic_size,
157 void *static_data, DWORD static_size )
159 const NPI_MODULEID *ip_mod = (fam == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID;
160 struct nsi_ip_cmpt_rw rw;
161 struct nsi_ip_cmpt_dynamic dyn;
162 DWORD count;
164 memset( &rw, 0, sizeof(rw) );
165 memset( &dyn, 0, sizeof(dyn) );
167 if (*key != 1) return STATUS_NOT_SUPPORTED;
169 #if __linux__
171 const char *fwd = (fam == AF_INET) ? "/proc/sys/net/ipv4/conf/default/forwarding" :
172 "/proc/sys/net/ipv6/conf/default/forwarding";
173 const char *ttl = (fam == AF_INET) ? "/proc/sys/net/ipv4/ip_default_ttl" :
174 "/proc/sys/net/ipv6/conf/default/hop_limit";
175 int value;
177 if (!read_sysctl_int( fwd, &value )) rw.not_forwarding = !value;
178 if (!read_sysctl_int( ttl, &value )) rw.default_ttl = value;
180 #elif defined(HAVE_SYS_SYSCTL_H)
182 int fwd_4[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_FORWARDING };
183 int fwd_6[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_FORWARDING };
184 int ttl_4[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
185 int ttl_6[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
186 int value;
187 size_t needed;
189 needed = sizeof(value);
190 if (!sysctl( (fam == AF_INET) ? fwd_4 : fwd_6, ARRAY_SIZE(fwd_4), &value, &needed, NULL, 0 ))
191 rw.not_forwarding = value;
193 needed = sizeof(value);
194 if (!sysctl( (fam == AF_INET) ? ttl_4 : ttl_6, ARRAY_SIZE(ttl_4), &value, &needed, NULL, 0 ))
195 rw.default_ttl = value;
197 #else
198 FIXME( "forwarding and default ttl not implemented\n" );
199 #endif
201 count = 0;
202 if (!nsi_enumerate_all( 1, 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0, NULL, 0,
203 NULL, 0, NULL, 0, &count ))
204 dyn.num_ifs = count;
206 count = 0;
207 if (!nsi_enumerate_all( 1, 0, ip_mod, NSI_IP_FORWARD_TABLE, NULL, 0, NULL, 0,
208 NULL, 0, NULL, 0, &count ))
209 dyn.num_routes = count;
211 count = 0;
212 if (!nsi_enumerate_all( 1, 0, ip_mod, NSI_IP_UNICAST_TABLE, NULL, 0, NULL, 0,
213 NULL, 0, NULL, 0, &count ))
214 dyn.num_addrs = count;
216 if (rw_data) *rw_data = rw;
217 if (dynamic_data) *dynamic_data = dyn;
219 return STATUS_SUCCESS;
222 static NTSTATUS ipv4_cmpt_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size,
223 void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size )
225 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
226 static_data, static_size );
227 return ip_cmpt_get_all_parameters( AF_INET, key, key_size, rw_data, rw_size,
228 dynamic_data, dynamic_size, static_data, static_size );
231 static NTSTATUS ipv6_cmpt_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size,
232 void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size )
234 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
235 static_data, static_size );
236 return ip_cmpt_get_all_parameters( AF_INET6, key, key_size, rw_data, rw_size,
237 dynamic_data, dynamic_size, static_data, static_size );
240 static NTSTATUS ipv4_icmpstats_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size,
241 void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size )
243 struct nsi_ip_icmpstats_dynamic dyn;
245 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
246 static_data, static_size );
248 memset( &dyn, 0, sizeof(dyn) );
250 #ifdef __linux__
252 NTSTATUS status = STATUS_NOT_SUPPORTED;
253 static const char hdr[] = "Icmp:";
254 char buf[512], *ptr;
255 FILE *fp;
257 if (!(fp = fopen( "/proc/net/snmp", "r" ))) return STATUS_NOT_SUPPORTED;
259 while ((ptr = fgets( buf, sizeof(buf), fp )))
261 if (ascii_strncasecmp( buf, hdr, sizeof(hdr) - 1 )) continue;
262 /* last line was a header, get another */
263 if (!(ptr = fgets( buf, sizeof(buf), fp ))) break;
264 if (!ascii_strncasecmp( buf, hdr, sizeof(hdr) - 1 ))
266 ptr += sizeof(hdr);
267 sscanf( ptr, "%u %u %*u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
268 &dyn.in_msgs,
269 &dyn.in_errors,
270 &dyn.in_type_counts[ICMP4_DST_UNREACH],
271 &dyn.in_type_counts[ICMP4_TIME_EXCEEDED],
272 &dyn.in_type_counts[ICMP4_PARAM_PROB],
273 &dyn.in_type_counts[ICMP4_SOURCE_QUENCH],
274 &dyn.in_type_counts[ICMP4_REDIRECT],
275 &dyn.in_type_counts[ICMP4_ECHO_REQUEST],
276 &dyn.in_type_counts[ICMP4_ECHO_REPLY],
277 &dyn.in_type_counts[ICMP4_TIMESTAMP_REQUEST],
278 &dyn.in_type_counts[ICMP4_TIMESTAMP_REPLY],
279 &dyn.in_type_counts[ICMP4_MASK_REQUEST],
280 &dyn.in_type_counts[ICMP4_MASK_REPLY],
281 &dyn.out_msgs,
282 &dyn.out_errors,
283 &dyn.out_type_counts[ICMP4_DST_UNREACH],
284 &dyn.out_type_counts[ICMP4_TIME_EXCEEDED],
285 &dyn.out_type_counts[ICMP4_PARAM_PROB],
286 &dyn.out_type_counts[ICMP4_SOURCE_QUENCH],
287 &dyn.out_type_counts[ICMP4_REDIRECT],
288 &dyn.out_type_counts[ICMP4_ECHO_REQUEST],
289 &dyn.out_type_counts[ICMP4_ECHO_REPLY],
290 &dyn.out_type_counts[ICMP4_TIMESTAMP_REQUEST],
291 &dyn.out_type_counts[ICMP4_TIMESTAMP_REPLY],
292 &dyn.out_type_counts[ICMP4_MASK_REQUEST],
293 &dyn.out_type_counts[ICMP4_MASK_REPLY] );
294 status = STATUS_SUCCESS;
295 if (dynamic_data) *(struct nsi_ip_icmpstats_dynamic *)dynamic_data = dyn;
296 break;
299 fclose( fp );
300 return status;
302 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
304 int mib[] = { CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS };
305 struct icmpstat icmp_stat;
306 size_t needed = sizeof(icmp_stat);
307 int i;
309 if (sysctl( mib, ARRAY_SIZE(mib), &icmp_stat, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
311 dyn.in_msgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
312 for (i = 0; i <= ICMP_MAXTYPE; i++)
313 dyn.in_msgs += icmp_stat.icps_inhist[i];
315 dyn.in_errors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
317 dyn.in_type_counts[ICMP4_DST_UNREACH] = icmp_stat.icps_inhist[ICMP_UNREACH];
318 dyn.in_type_counts[ICMP4_TIME_EXCEEDED] = icmp_stat.icps_inhist[ICMP_TIMXCEED];
319 dyn.in_type_counts[ICMP4_PARAM_PROB] = icmp_stat.icps_inhist[ICMP_PARAMPROB];
320 dyn.in_type_counts[ICMP4_SOURCE_QUENCH] = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
321 dyn.in_type_counts[ICMP4_REDIRECT] = icmp_stat.icps_inhist[ICMP_REDIRECT];
322 dyn.in_type_counts[ICMP4_ECHO_REQUEST] = icmp_stat.icps_inhist[ICMP_ECHO];
323 dyn.in_type_counts[ICMP4_ECHO_REPLY] = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
324 dyn.in_type_counts[ICMP4_TIMESTAMP_REQUEST] = icmp_stat.icps_inhist[ICMP_TSTAMP];
325 dyn.in_type_counts[ICMP4_TIMESTAMP_REPLY] = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
326 dyn.in_type_counts[ICMP4_MASK_REQUEST] = icmp_stat.icps_inhist[ICMP_MASKREQ];
327 dyn.in_type_counts[ICMP4_MASK_REPLY] = icmp_stat.icps_inhist[ICMP_MASKREPLY];
329 dyn.out_msgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
330 for (i = 0; i <= ICMP_MAXTYPE; i++)
331 dyn.out_msgs += icmp_stat.icps_outhist[i];
333 dyn.out_errors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
335 dyn.out_type_counts[ICMP4_DST_UNREACH] = icmp_stat.icps_outhist[ICMP_UNREACH];
336 dyn.out_type_counts[ICMP4_TIME_EXCEEDED] = icmp_stat.icps_outhist[ICMP_TIMXCEED];
337 dyn.out_type_counts[ICMP4_PARAM_PROB] = icmp_stat.icps_outhist[ICMP_PARAMPROB];
338 dyn.out_type_counts[ICMP4_SOURCE_QUENCH] = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
339 dyn.out_type_counts[ICMP4_REDIRECT] = icmp_stat.icps_outhist[ICMP_REDIRECT];
340 dyn.out_type_counts[ICMP4_ECHO_REQUEST] = icmp_stat.icps_outhist[ICMP_ECHO];
341 dyn.out_type_counts[ICMP4_ECHO_REPLY] = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
342 dyn.out_type_counts[ICMP4_TIMESTAMP_REQUEST] = icmp_stat.icps_outhist[ICMP_TSTAMP];
343 dyn.out_type_counts[ICMP4_TIMESTAMP_REPLY] = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
344 dyn.out_type_counts[ICMP4_MASK_REQUEST] = icmp_stat.icps_outhist[ICMP_MASKREQ];
345 dyn.out_type_counts[ICMP4_MASK_REPLY] = icmp_stat.icps_outhist[ICMP_MASKREPLY];
346 if (dynamic_data) *(struct nsi_ip_icmpstats_dynamic *)dynamic_data = dyn;
347 return STATUS_SUCCESS;
349 #else
350 FIXME( "not implemented\n" );
351 return STATUS_NOT_IMPLEMENTED;
352 #endif
355 static NTSTATUS ipv6_icmpstats_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size,
356 void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size )
358 struct nsi_ip_icmpstats_dynamic dyn;
360 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
361 static_data, static_size );
363 memset( &dyn, 0, sizeof(dyn) );
365 #ifdef __linux__
367 struct data
369 const char *name;
370 DWORD pos;
372 static const struct data in_list[] =
374 { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH },
375 { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG },
376 { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED },
377 { "Icmp6InParmProblems", ICMP6_PARAM_PROB },
378 { "Icmp6InEchos", ICMP6_ECHO_REQUEST },
379 { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY },
380 { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
381 { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
382 { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
383 { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT },
384 { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT },
385 { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT },
386 { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
387 { "Icmp6InRedirects", ND_REDIRECT },
388 { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
390 static const struct data out_list[] =
392 { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH },
393 { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG },
394 { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED },
395 { "Icmp6OutParmProblems", ICMP6_PARAM_PROB },
396 { "Icmp6OutEchos", ICMP6_ECHO_REQUEST },
397 { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY },
398 { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
399 { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
400 { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
401 { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT },
402 { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT },
403 { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT },
404 { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
405 { "Icmp6OutRedirects", ND_REDIRECT },
406 { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
408 char buf[512], *ptr, *value;
409 DWORD res, i;
410 FILE *fp;
412 if (!(fp = fopen( "/proc/net/snmp6", "r" ))) return STATUS_NOT_SUPPORTED;
414 while ((ptr = fgets( buf, sizeof(buf), fp )))
416 if (!(value = strchr( buf, ' ' ))) continue;
418 /* terminate the valuename */
419 ptr = value - 1;
420 *(ptr + 1) = '\0';
422 /* and strip leading spaces from value */
423 value += 1;
424 while (*value == ' ') value++;
425 if ((ptr = strchr( value, '\n' ))) *ptr='\0';
427 if (!ascii_strcasecmp( buf, "Icmp6InMsgs" ))
429 if (sscanf( value, "%d", &res )) dyn.in_msgs = res;
430 continue;
433 if (!ascii_strcasecmp( buf, "Icmp6InErrors" ))
435 if (sscanf( value, "%d", &res )) dyn.in_errors = res;
436 continue;
439 for (i = 0; i < ARRAY_SIZE(in_list); i++)
441 if (!ascii_strcasecmp( buf, in_list[i].name ))
443 if (sscanf( value, "%d", &res ))
444 dyn.in_type_counts[in_list[i].pos] = res;
445 break;
449 if (!ascii_strcasecmp( buf, "Icmp6OutMsgs" ))
451 if (sscanf( value, "%d", &res )) dyn.out_msgs = res;
452 continue;
455 if (!ascii_strcasecmp( buf, "Icmp6OutErrors" ))
457 if (sscanf( value, "%d", &res )) dyn.out_errors = res;
458 continue;
461 for (i = 0; i < ARRAY_SIZE(out_list); i++)
463 if (!ascii_strcasecmp( buf, out_list[i].name ))
465 if (sscanf( value, "%d", &res ))
466 dyn.out_type_counts[out_list[i].pos] = res;
467 break;
471 fclose( fp );
472 if (dynamic_data) *(struct nsi_ip_icmpstats_dynamic *)dynamic_data = dyn;
473 return STATUS_SUCCESS;
475 #else
476 FIXME( "not implemented\n" );
477 return STATUS_NOT_IMPLEMENTED;
478 #endif
481 static NTSTATUS ipv4_ipstats_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size,
482 void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size )
484 struct nsi_ip_ipstats_dynamic dyn;
485 struct nsi_ip_ipstats_static stat;
487 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
488 static_data, static_size );
490 memset( &dyn, 0, sizeof(dyn) );
491 memset( &stat, 0, sizeof(stat) );
493 #ifdef __linux__
495 NTSTATUS status = STATUS_NOT_SUPPORTED;
496 static const char hdr[] = "Ip:";
497 char buf[512], *ptr;
498 FILE *fp;
500 if (!(fp = fopen( "/proc/net/snmp", "r" ))) return STATUS_NOT_SUPPORTED;
502 while ((ptr = fgets( buf, sizeof(buf), fp )))
504 if (ascii_strncasecmp( buf, hdr, sizeof(hdr) - 1 )) continue;
505 /* last line was a header, get another */
506 if (!(ptr = fgets( buf, sizeof(buf), fp ))) break;
507 if (!ascii_strncasecmp( buf, hdr, sizeof(hdr) - 1 ))
509 DWORD in_recv, in_hdr_errs, fwd_dgrams, in_delivers, out_reqs;
510 ptr += sizeof(hdr);
511 sscanf( ptr, "%*u %*u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
512 &in_recv,
513 &in_hdr_errs,
514 &dyn.in_addr_errs,
515 &fwd_dgrams,
516 &dyn.in_unk_protos,
517 &dyn.in_discards,
518 &in_delivers,
519 &out_reqs,
520 &dyn.out_discards,
521 &dyn.out_no_routes,
522 &stat.reasm_timeout,
523 &dyn.reasm_reqds,
524 &dyn.reasm_oks,
525 &dyn.reasm_fails,
526 &dyn.frag_oks,
527 &dyn.frag_fails,
528 &dyn.frag_creates );
529 /* no routingDiscards */
530 dyn.in_recv = in_recv;
531 dyn.in_hdr_errs = in_hdr_errs;
532 dyn.fwd_dgrams = fwd_dgrams;
533 dyn.in_delivers = in_delivers;
534 dyn.out_reqs = out_reqs;
535 if (dynamic_data) *(struct nsi_ip_ipstats_dynamic *)dynamic_data = dyn;
536 if (static_data) *(struct nsi_ip_ipstats_static *)static_data = stat;
537 status = STATUS_SUCCESS;
538 break;
541 fclose( fp );
542 return status;
544 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
546 int mib[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS };
547 #if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
548 struct ipstat ip_stat;
549 #elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
550 struct ip_stats ip_stat;
551 #endif
552 size_t needed;
554 needed = sizeof(ip_stat);
555 if (sysctl( mib, ARRAY_SIZE(mib), &ip_stat, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
557 dyn.in_recv = ip_stat.ips_total;
558 dyn.in_hdr_errs = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen +
559 ip_stat.ips_badvers + ip_stat.ips_badoptions;
560 /* ips_badaddr also includes outgoing packets with a bad address, but we can't account for that right now */
561 dyn.in_addr_errs = ip_stat.ips_cantforward + ip_stat.ips_badaddr + ip_stat.ips_notmember;
562 dyn.fwd_dgrams = ip_stat.ips_forward;
563 dyn.in_unk_protos = ip_stat.ips_noproto;
564 dyn.in_discards = ip_stat.ips_fragdropped;
565 dyn.in_delivers = ip_stat.ips_delivered;
566 dyn.out_reqs = ip_stat.ips_localout;
567 dyn.out_discards = ip_stat.ips_odropped;
568 dyn.out_no_routes = ip_stat.ips_noroute;
569 stat.reasm_timeout = ip_stat.ips_fragtimeout;
570 dyn.reasm_reqds = ip_stat.ips_fragments;
571 dyn.reasm_oks = ip_stat.ips_reassembled;
572 dyn.reasm_fails = ip_stat.ips_fragments - ip_stat.ips_reassembled;
573 dyn.frag_oks = ip_stat.ips_fragmented;
574 dyn.frag_fails = ip_stat.ips_cantfrag;
575 dyn.frag_creates = ip_stat.ips_ofragments;
577 if (dynamic_data) *(struct nsi_ip_ipstats_dynamic *)dynamic_data = dyn;
578 if (static_data) *(struct nsi_ip_ipstats_static *)static_data = stat;
579 return STATUS_SUCCESS;
581 #else
582 FIXME( "not implemented\n" );
583 return STATUS_NOT_IMPLEMENTED;
584 #endif
587 static NTSTATUS ipv6_ipstats_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size,
588 void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size )
590 struct nsi_ip_ipstats_dynamic dyn;
591 struct nsi_ip_ipstats_static stat;
593 memset( &dyn, 0, sizeof(dyn) );
594 memset( &stat, 0, sizeof(stat) );
596 #ifdef __linux__
598 struct
600 const char *name;
601 void *elem;
602 int size;
603 } ipstatlist[] =
605 #define X(x) &x, sizeof(x)
606 { "Ip6InReceives", X( dyn.in_recv ) },
607 { "Ip6InHdrErrors", X( dyn.in_hdr_errs ) },
608 { "Ip6InAddrErrors", X( dyn.in_addr_errs ) },
609 { "Ip6OutForwDatagrams", X( dyn.fwd_dgrams ) },
610 { "Ip6InUnknownProtos", X( dyn.in_unk_protos ) },
611 { "Ip6InDiscards", X( dyn.in_discards ) },
612 { "Ip6InDelivers", X( dyn.in_delivers ) },
613 { "Ip6OutRequests", X( dyn.out_reqs ) },
614 { "Ip6OutDiscards", X( dyn.out_discards ) },
615 { "Ip6OutNoRoutes", X( dyn.out_no_routes ) },
616 { "Ip6ReasmTimeout", X( stat.reasm_timeout ) },
617 { "Ip6ReasmReqds", X( dyn.reasm_reqds ) },
618 { "Ip6ReasmOKs", X( dyn.reasm_oks ) },
619 { "Ip6ReasmFails", X( dyn.reasm_fails ) },
620 { "Ip6FragOKs", X( dyn.frag_oks ) },
621 { "Ip6FragFails", X( dyn.frag_fails ) },
622 { "Ip6FragCreates", X( dyn.frag_creates ) },
623 /* no routingDiscards */
624 #undef X
626 NTSTATUS status = STATUS_NOT_SUPPORTED;
627 char buf[512], *ptr, *value;
628 DWORD i;
629 FILE *fp;
631 if (!(fp = fopen( "/proc/net/snmp6", "r" ))) return STATUS_NOT_SUPPORTED;
633 while ((ptr = fgets( buf, sizeof(buf), fp )))
635 if (!(value = strchr( buf, ' ' ))) continue;
636 /* terminate the valuename */
637 *value++ = '\0';
638 /* and strip leading spaces from value */
639 while (*value == ' ') value++;
640 if ((ptr = strchr( value, '\n' ))) *ptr = '\0';
642 for (i = 0; i < ARRAY_SIZE(ipstatlist); i++)
643 if (!ascii_strcasecmp( buf, ipstatlist[i].name ))
645 if (ipstatlist[i].size == sizeof(long))
646 *(long *)ipstatlist[i].elem = strtoul( value, NULL, 10 );
647 else
648 *(long long *)ipstatlist[i].elem = strtoull( value, NULL, 10 );
649 status = STATUS_SUCCESS;
652 fclose( fp );
653 if (dynamic_data) *(struct nsi_ip_ipstats_dynamic *)dynamic_data = dyn;
654 if (static_data) *(struct nsi_ip_ipstats_static *)static_data = stat;
655 return status;
657 #else
658 FIXME( "not implemented\n" );
659 return STATUS_NOT_IMPLEMENTED;
660 #endif
663 static void unicast_fill_entry( struct ifaddrs *entry, void *key, struct nsi_ip_unicast_rw *rw,
664 struct nsi_ip_unicast_dynamic *dyn, struct nsi_ip_unicast_static *stat )
666 struct nsi_ipv6_unicast_key placeholder, *key6 = key;
667 struct nsi_ipv4_unicast_key *key4 = key;
668 DWORD scope_id = 0;
670 if (!key)
672 key6 = &placeholder;
673 key4 = (struct nsi_ipv4_unicast_key *)&placeholder;
676 convert_unix_name_to_luid( entry->ifa_name, &key6->luid );
678 if (entry->ifa_addr->sa_family == AF_INET)
680 memcpy( &key4->addr, &((struct sockaddr_in *)entry->ifa_addr)->sin_addr, sizeof(key4->addr) );
681 key4->pad = 0;
683 else if (entry->ifa_addr->sa_family == AF_INET6)
685 memcpy( &key6->addr, &((struct sockaddr_in6 *)entry->ifa_addr)->sin6_addr, sizeof(key6->addr) );
686 scope_id = ((struct sockaddr_in6 *)entry->ifa_addr)->sin6_scope_id;
689 if (rw)
691 rw->preferred_lifetime = 60000;
692 rw->valid_lifetime = 60000;
694 if (key6->luid.Info.IfType != IF_TYPE_SOFTWARE_LOOPBACK)
696 rw->prefix_origin = IpPrefixOriginDhcp;
697 rw->suffix_origin = IpSuffixOriginDhcp;
699 else
701 rw->prefix_origin = IpPrefixOriginManual;
702 rw->suffix_origin = IpSuffixOriginManual;
704 if (entry->ifa_netmask && entry->ifa_netmask->sa_family == AF_INET)
705 rw->on_link_prefix = mask_v4_to_prefix( &((struct sockaddr_in *)entry->ifa_netmask)->sin_addr );
706 else if (entry->ifa_netmask && entry->ifa_netmask->sa_family == AF_INET6)
707 rw->on_link_prefix = mask_v6_to_prefix( &((struct sockaddr_in6 *)entry->ifa_netmask)->sin6_addr );
708 else rw->on_link_prefix = 0;
709 rw->unk[0] = 0;
710 rw->unk[1] = 0;
713 if (dyn)
715 dyn->scope_id = scope_id;
716 dyn->dad_state = IpDadStatePreferred;
719 if (stat) stat->creation_time = get_boot_time();
722 static NTSTATUS ip_unicast_enumerate_all( int family, void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
723 void *dynamic_data, DWORD dynamic_size,
724 void *static_data, DWORD static_size, DWORD_PTR *count )
726 DWORD num = 0;
727 NTSTATUS status = STATUS_SUCCESS;
728 BOOL want_data = key_size || rw_size || dynamic_size || static_size;
729 struct ifaddrs *addrs, *entry;
731 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
732 dynamic_data, dynamic_size, static_data, static_size, count );
734 if (getifaddrs( &addrs )) return STATUS_NO_MORE_ENTRIES;
736 for (entry = addrs; entry; entry = entry->ifa_next)
738 if (!entry->ifa_addr || entry->ifa_addr->sa_family != family) continue;
740 if (num < *count)
742 unicast_fill_entry( entry, key_data, rw_data, dynamic_data, static_data );
743 key_data = (BYTE *)key_data + key_size;
744 rw_data = (BYTE *)rw_data + rw_size;
745 dynamic_data = (BYTE *)dynamic_data + dynamic_size;
746 static_data = (BYTE *)static_data + static_size;
748 num++;
751 freeifaddrs( addrs );
753 if (!want_data || num <= *count) *count = num;
754 else status = STATUS_BUFFER_OVERFLOW;
756 return status;
759 static NTSTATUS ipv4_unicast_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
760 void *dynamic_data, DWORD dynamic_size,
761 void *static_data, DWORD static_size, DWORD_PTR *count )
763 return ip_unicast_enumerate_all( AF_INET, key_data, key_size, rw_data, rw_size,
764 dynamic_data, dynamic_size, static_data, static_size, count );
767 static NTSTATUS ipv6_unicast_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
768 void *dynamic_data, DWORD dynamic_size,
769 void *static_data, DWORD static_size, DWORD_PTR *count )
771 return ip_unicast_enumerate_all( AF_INET6, key_data, key_size, rw_data, rw_size,
772 dynamic_data, dynamic_size, static_data, static_size, count );
775 static NTSTATUS ip_unicast_get_all_parameters( const void *key, DWORD key_size, void *rw_data, DWORD rw_size,
776 void *dynamic_data, DWORD dynamic_size,
777 void *static_data, DWORD static_size )
779 int family = (key_size == sizeof(struct nsi_ipv4_unicast_key)) ? AF_INET : AF_INET6;
780 NTSTATUS status = STATUS_NOT_FOUND;
781 const struct nsi_ipv6_unicast_key *key6 = key;
782 const struct nsi_ipv4_unicast_key *key4 = key;
783 struct ifaddrs *addrs, *entry;
784 const char *unix_name;
786 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
787 static_data, static_size );
789 if (!convert_luid_to_unix_name( &key6->luid, &unix_name )) return STATUS_NOT_FOUND;
791 if (getifaddrs( &addrs )) return STATUS_NO_MORE_ENTRIES;
793 for (entry = addrs; entry; entry = entry->ifa_next)
795 if (!entry->ifa_addr || entry->ifa_addr->sa_family != family) continue;
796 if (strcmp( entry->ifa_name, unix_name )) continue;
798 if (family == AF_INET &&
799 memcmp( &key4->addr, &((struct sockaddr_in *)entry->ifa_addr)->sin_addr, sizeof(key4->addr) )) continue;
800 if (family == AF_INET6 &&
801 memcmp( &key6->addr, &((struct sockaddr_in6 *)entry->ifa_addr)->sin6_addr, sizeof(key6->addr) )) continue;
803 unicast_fill_entry( entry, NULL, rw_data, dynamic_data, static_data );
804 status = STATUS_SUCCESS;
805 break;
808 freeifaddrs( addrs );
809 return status;
812 struct ipv4_neighbour_data
814 NET_LUID luid;
815 DWORD if_index;
816 struct in_addr addr;
817 BYTE phys_addr[IF_MAX_PHYS_ADDRESS_LENGTH];
818 DWORD state;
819 USHORT phys_addr_len;
820 BOOL is_router;
821 BOOL is_unreachable;
824 static void ipv4_neighbour_fill_entry( struct ipv4_neighbour_data *entry, struct nsi_ipv4_neighbour_key *key, struct nsi_ip_neighbour_rw *rw,
825 struct nsi_ip_neighbour_dynamic *dyn, void *stat )
827 USHORT phys_addr_len = entry->phys_addr_len > sizeof(rw->phys_addr) ? 0 : entry->phys_addr_len;
829 if (key)
831 key->luid = entry->luid;
832 key->luid2 = entry->luid;
833 key->addr.WS_s_addr = entry->addr.s_addr;
834 key->pad = 0;
837 if (rw)
839 memcpy( rw->phys_addr, entry->phys_addr, phys_addr_len );
840 memset( rw->phys_addr + entry->phys_addr_len, 0, sizeof(rw->phys_addr) - phys_addr_len );
843 if (dyn)
845 memset( dyn, 0, sizeof(*dyn) );
846 dyn->state = entry->state;
847 dyn->flags.is_router = entry->is_router;
848 dyn->flags.is_unreachable = entry->is_unreachable;
849 dyn->phys_addr_len = phys_addr_len;
853 static NTSTATUS ipv4_neighbour_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
854 void *dynamic_data, DWORD dynamic_size,
855 void *static_data, DWORD static_size, DWORD_PTR *count )
857 DWORD num = 0;
858 NTSTATUS status = STATUS_SUCCESS;
859 BOOL want_data = key_size || rw_size || dynamic_size || static_size;
860 struct ipv4_neighbour_data entry;
862 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
863 dynamic_data, dynamic_size, static_data, static_size, count );
865 #ifdef __linux__
867 char buf[512], *ptr;
868 DWORD atf_flags;
869 FILE *fp;
871 if (!(fp = fopen( "/proc/net/arp", "r" ))) return STATUS_NOT_SUPPORTED;
873 /* skip header line */
874 ptr = fgets( buf, sizeof(buf), fp );
875 while ((ptr = fgets( buf, sizeof(buf), fp )))
877 entry.addr.s_addr = inet_addr( ptr );
878 while (*ptr && !isspace( *ptr )) ptr++;
879 strtoul( ptr + 1, &ptr, 16 ); /* hw type (skip) */
880 atf_flags = strtoul( ptr + 1, &ptr, 16 );
882 if (atf_flags & ATF_PERM) entry.state = NlnsPermanent;
883 else if (atf_flags & ATF_COM) entry.state = NlnsReachable;
884 else entry.state = NlnsStale;
886 entry.is_router = 0;
887 entry.is_unreachable = !(atf_flags & (ATF_PERM | ATF_COM));
889 while (*ptr && isspace( *ptr )) ptr++;
890 entry.phys_addr_len = 0;
891 while (*ptr && !isspace( *ptr ))
893 if (entry.phys_addr_len >= sizeof(entry.phys_addr))
895 entry.phys_addr_len = 0;
896 while (*ptr && !isspace( *ptr )) ptr++;
897 break;
899 entry.phys_addr[entry.phys_addr_len++] = strtoul( ptr, &ptr, 16 );
900 if (*ptr) ptr++;
902 while (*ptr && isspace( *ptr )) ptr++;
903 while (*ptr && !isspace( *ptr )) ptr++; /* mask (skip) */
904 while (*ptr && isspace( *ptr )) ptr++;
906 if (!convert_unix_name_to_luid( ptr, &entry.luid )) continue;
907 if (!convert_luid_to_index( &entry.luid, &entry.if_index )) continue;
909 if (num < *count)
911 ipv4_neighbour_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
913 if (key_data) key_data = (BYTE *)key_data + key_size;
914 if (rw_data) rw_data = (BYTE *)rw_data + rw_size;
915 if (dynamic_data) dynamic_data = (BYTE *)dynamic_data + dynamic_size;
916 if (static_data) static_data = (BYTE *)static_data + static_size;
918 num++;
920 fclose( fp );
922 #elif defined(HAVE_SYS_SYSCTL_H)
924 int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO }, sinarp_len;
925 size_t needed;
926 char *buf = NULL, *lim, *next;
927 struct rt_msghdr *rtm;
928 struct sockaddr_inarp *sinarp;
929 struct sockaddr_dl *sdl;
931 if (sysctl( mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
933 buf = malloc( needed );
934 if (!buf) return STATUS_NO_MEMORY;
936 if (sysctl( mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0 ) == -1)
938 free( buf );
939 return STATUS_NOT_SUPPORTED;
942 lim = buf + needed;
943 next = buf;
944 while (next < lim)
946 rtm = (struct rt_msghdr *)next;
947 sinarp = (struct sockaddr_inarp *)(rtm + 1);
948 if (sinarp->sin_len) sinarp_len = (sinarp->sin_len + sizeof(int)-1) & ~(sizeof(int)-1);
949 else sinarp_len = sizeof(int);
950 sdl = (struct sockaddr_dl *)((char *)sinarp + sinarp_len);
952 if (sdl->sdl_alen) /* arp entry */
954 entry.addr = sinarp->sin_addr;
955 entry.if_index = sdl->sdl_index;
956 if (!convert_index_to_luid( entry.if_index, &entry.luid )) break;
957 entry.phys_addr_len = min( 8, sdl->sdl_alen );
958 if (entry.phys_addr_len > sizeof(entry.phys_addr)) entry.phys_addr_len = 0;
959 memcpy( entry.phys_addr, &sdl->sdl_data[sdl->sdl_nlen], entry.phys_addr_len );
960 if (rtm->rtm_rmx.rmx_expire == 0) entry.state = NlnsPermanent;
961 else entry.state = NlnsReachable;
962 #ifdef SIN_ROUTER
963 entry.is_router = sinarp->sin_other & SIN_ROUTER;
964 #else
965 entry.is_router = 0;
966 #endif
967 entry.is_unreachable = 0; /* FIXME */
969 if (num < *count)
971 ipv4_neighbour_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
973 if (key_data) key_data = (BYTE *)key_data + key_size;
974 if (rw_data) rw_data = (BYTE *)rw_data + rw_size;
975 if (dynamic_data) dynamic_data = (BYTE *)dynamic_data + dynamic_size;
976 if (static_data) static_data = (BYTE *)static_data + static_size;
978 num++;
980 next += rtm->rtm_msglen;
982 free( buf );
984 #else
985 FIXME( "not implemented\n" );
986 return STATUS_NOT_IMPLEMENTED;
987 #endif
989 if (!want_data || num <= *count) *count = num;
990 else status = STATUS_BUFFER_OVERFLOW;
992 return status;
995 static NTSTATUS ipv6_neighbour_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
996 void *dynamic_data, DWORD dynamic_size,
997 void *static_data, DWORD static_size, DWORD_PTR *count )
999 FIXME( "not implemented\n" );
1000 return STATUS_NOT_IMPLEMENTED;
1003 struct ipv4_route_data
1005 NET_LUID luid;
1006 DWORD if_index;
1007 struct in_addr prefix;
1008 DWORD prefix_len;
1009 struct in_addr next_hop;
1010 DWORD metric;
1011 DWORD protocol;
1012 BYTE loopback;
1015 static void ipv4_forward_fill_entry( struct ipv4_route_data *entry, struct nsi_ipv4_forward_key *key,
1016 struct nsi_ip_forward_rw *rw, struct nsi_ipv4_forward_dynamic *dyn,
1017 struct nsi_ip_forward_static *stat )
1019 if (key)
1021 key->unk = 0;
1022 key->prefix.WS_s_addr = entry->prefix.s_addr;
1023 key->prefix_len = entry->prefix_len;
1024 memset( key->unk2, 0, sizeof(key->unk2) );
1025 memset( key->unk3, 0, sizeof(key->unk3) );
1026 key->luid = entry->luid;
1027 key->luid2 = entry->luid;
1028 key->next_hop.WS_s_addr = entry->next_hop.s_addr;
1029 key->pad = 0;
1032 if (rw)
1034 rw->site_prefix_len = 0;
1035 rw->valid_lifetime = ~0u;
1036 rw->preferred_lifetime = ~0u;
1037 rw->metric = entry->metric;
1038 rw->protocol = entry->protocol;
1039 rw->loopback = entry->loopback;
1040 rw->autoconf = 1;
1041 rw->publish = 0;
1042 rw->immortal = 1;
1043 memset( rw->unk, 0, sizeof(rw->unk) );
1044 rw->unk2 = 0;
1047 if (dyn)
1049 memset( dyn, 0, sizeof(*dyn) );
1052 if (stat)
1054 stat->origin = NlroManual;
1055 stat->if_index = entry->if_index;
1059 static NTSTATUS ipv4_forward_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
1060 void *dynamic_data, DWORD dynamic_size,
1061 void *static_data, DWORD static_size, DWORD_PTR *count )
1063 DWORD num = 0;
1064 NTSTATUS status = STATUS_SUCCESS;
1065 BOOL want_data = key_size || rw_size || dynamic_size || static_size;
1066 struct ipv4_route_data entry;
1068 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
1069 dynamic_data, dynamic_size, static_data, static_size, count );
1071 #ifdef __linux__
1073 char buf[512], *ptr;
1074 struct in_addr mask;
1075 DWORD rtf_flags;
1076 FILE *fp;
1078 if (!(fp = fopen( "/proc/net/route", "r" ))) return STATUS_NOT_SUPPORTED;
1080 /* skip header line */
1081 fgets( buf, sizeof(buf), fp );
1082 while ((ptr = fgets( buf, sizeof(buf), fp )))
1084 while (!isspace( *ptr )) ptr++;
1085 *ptr++ = '\0';
1087 if (!convert_unix_name_to_luid( buf, &entry.luid )) continue;
1088 if (!convert_luid_to_index( &entry.luid, &entry.if_index )) continue;
1090 entry.prefix.s_addr = strtoul( ptr, &ptr, 16 );
1091 entry.next_hop.s_addr = strtoul( ptr + 1, &ptr, 16 );
1092 rtf_flags = strtoul( ptr + 1, &ptr, 16 );
1093 strtoul( ptr + 1, &ptr, 16 ); /* refcount, skip */
1094 strtoul( ptr + 1, &ptr, 16 ); /* use, skip */
1095 entry.metric = strtoul( ptr + 1, &ptr, 16 );
1096 mask.s_addr = strtoul( ptr + 1, &ptr, 16 );
1097 entry.prefix_len = mask_v4_to_prefix( &mask );
1098 entry.protocol = (rtf_flags & RTF_GATEWAY) ? MIB_IPPROTO_NETMGMT : MIB_IPPROTO_LOCAL;
1099 entry.loopback = entry.protocol == MIB_IPPROTO_LOCAL && entry.prefix_len == 32;
1101 if (num < *count)
1103 ipv4_forward_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
1104 key_data = (BYTE *)key_data + key_size;
1105 rw_data = (BYTE *)rw_data + rw_size;
1106 dynamic_data = (BYTE *)dynamic_data + dynamic_size;
1107 static_data = (BYTE *)static_data + static_size;
1109 num++;
1111 fclose( fp );
1113 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1115 int mib[6] = { CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0 };
1116 size_t needed;
1117 char *buf = NULL, *lim, *next, *addr_ptr;
1118 struct rt_msghdr *rtm;
1120 if (sysctl( mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0 ) < 0) return STATUS_NOT_SUPPORTED;
1122 buf = malloc( needed );
1123 if (!buf) return STATUS_NO_MEMORY;
1125 if (sysctl( mib, 6, buf, &needed, NULL, 0 ) < 0)
1127 free( buf );
1128 return STATUS_NOT_SUPPORTED;
1131 lim = buf + needed;
1132 for (next = buf; next < lim; next += rtm->rtm_msglen)
1134 int i;
1135 sa_family_t dst_family = AF_UNSPEC;
1137 rtm = (struct rt_msghdr *)next;
1139 if (rtm->rtm_type != RTM_GET)
1141 WARN( "Got unexpected message type 0x%x!\n", rtm->rtm_type );
1142 continue;
1145 /* Ignore gateway routes which are multicast */
1146 if ((rtm->rtm_flags & RTF_GATEWAY) && (rtm->rtm_flags & RTF_MULTICAST)) continue;
1148 entry.if_index = rtm->rtm_index;
1149 if (!convert_index_to_luid( entry.if_index, &entry.luid )) continue;
1150 entry.protocol = (rtm->rtm_flags & RTF_GATEWAY) ? MIB_IPPROTO_NETMGMT : MIB_IPPROTO_LOCAL;
1151 entry.metric = rtm->rtm_rmx.rmx_hopcount;
1153 addr_ptr = (char *)(rtm + 1);
1155 for (i = 1; i; i <<= 1)
1157 struct sockaddr *sa;
1158 struct in_addr addr;
1160 if (!(i & rtm->rtm_addrs)) continue;
1162 sa = (struct sockaddr *)addr_ptr;
1163 if (addr_ptr + sa->sa_len > next + rtm->rtm_msglen)
1165 ERR( "struct sockaddr extends beyond the route message, %p > %p\n",
1166 addr_ptr + sa->sa_len, next + rtm->rtm_msglen );
1169 if (sa->sa_len) addr_ptr += (sa->sa_len + sizeof(int)-1) & ~(sizeof(int)-1);
1170 else addr_ptr += sizeof(int);
1171 /* Apple's netstat prints the netmask together with the destination
1172 * and only looks at the destination's address family. The netmask's
1173 * sa_family sometimes contains the non-existent value 0xff. */
1174 switch (i == RTA_NETMASK ? dst_family : sa->sa_family)
1176 case AF_INET:
1178 /* Netmasks (and possibly other addresses) have only enough size
1179 * to represent the non-zero bits, e.g. a netmask of 255.0.0.0 has
1180 * 5 bytes (1 sa_len, 1 sa_family, 2 sa_port and 1 for the first
1181 * byte of sin_addr). */
1182 struct sockaddr_in sin = {0};
1183 memcpy( &sin, sa, sa->sa_len );
1184 addr = sin.sin_addr;
1185 break;
1187 #ifdef AF_LINK
1188 case AF_LINK:
1189 if (i == RTA_GATEWAY && entry.protocol == MIB_IPPROTO_NETMGMT)
1191 /* For direct route we may simply use dest addr as next hop */
1192 C_ASSERT(RTA_DST < RTA_GATEWAY);
1193 addr = entry.prefix;
1194 break;
1196 /* fallthrough */
1197 #endif
1198 default:
1199 WARN( "Received unsupported sockaddr family 0x%x\n", sa->sa_family );
1200 addr.s_addr = 0;
1202 switch (i)
1204 case RTA_DST:
1205 entry.prefix = addr;
1206 dst_family = sa->sa_family;
1207 break;
1208 case RTA_GATEWAY: entry.next_hop = addr; break;
1209 case RTA_NETMASK: entry.prefix_len = mask_v4_to_prefix( &addr ); break;
1210 default:
1211 WARN( "Unexpected address type 0x%x\n", i );
1215 if (num < *count)
1217 ipv4_forward_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
1218 key_data = (BYTE *)key_data + key_size;
1219 rw_data = (BYTE *)rw_data + rw_size;
1220 dynamic_data = (BYTE *)dynamic_data + dynamic_size;
1221 static_data = (BYTE *)static_data + static_size;
1223 num++;
1225 free( buf );
1227 #else
1228 FIXME( "not implemented\n" );
1229 return STATUS_NOT_IMPLEMENTED;
1230 #endif
1232 if (!want_data || num <= *count) *count = num;
1233 else status = STATUS_BUFFER_OVERFLOW;
1235 return status;
1238 static NTSTATUS ipv6_forward_enumerate_all( void *key_data, DWORD key_size, void *rw_data, DWORD rw_size,
1239 void *dynamic_data, DWORD dynamic_size,
1240 void *static_data, DWORD static_size, DWORD_PTR *count )
1242 FIXME( "not implemented\n" );
1243 *count = 0;
1244 return STATUS_SUCCESS;
1247 static struct module_table ipv4_tables[] =
1250 NSI_IP_COMPARTMENT_TABLE,
1252 sizeof(DWORD), sizeof(struct nsi_ip_cmpt_rw),
1253 sizeof(struct nsi_ip_cmpt_dynamic), 0
1255 NULL,
1256 ipv4_cmpt_get_all_parameters,
1259 NSI_IP_ICMPSTATS_TABLE,
1261 0, 0,
1262 sizeof(struct nsi_ip_icmpstats_dynamic), 0
1264 NULL,
1265 ipv4_icmpstats_get_all_parameters,
1268 NSI_IP_IPSTATS_TABLE,
1270 0, 0,
1271 sizeof(struct nsi_ip_ipstats_dynamic), sizeof(struct nsi_ip_ipstats_static)
1273 NULL,
1274 ipv4_ipstats_get_all_parameters,
1277 NSI_IP_UNICAST_TABLE,
1279 sizeof(struct nsi_ipv4_unicast_key), sizeof(struct nsi_ip_unicast_rw),
1280 sizeof(struct nsi_ip_unicast_dynamic), sizeof(struct nsi_ip_unicast_static)
1282 ipv4_unicast_enumerate_all,
1283 ip_unicast_get_all_parameters,
1286 NSI_IP_NEIGHBOUR_TABLE,
1288 sizeof(struct nsi_ipv4_neighbour_key), sizeof(struct nsi_ip_neighbour_rw),
1289 sizeof(struct nsi_ip_neighbour_dynamic), 0
1291 ipv4_neighbour_enumerate_all,
1294 NSI_IP_FORWARD_TABLE,
1296 sizeof(struct nsi_ipv4_forward_key), sizeof(struct nsi_ip_forward_rw),
1297 sizeof(struct nsi_ipv4_forward_dynamic), sizeof(struct nsi_ip_forward_static)
1299 ipv4_forward_enumerate_all,
1306 const struct module ipv4_module =
1308 &NPI_MS_IPV4_MODULEID,
1309 ipv4_tables
1312 static struct module_table ipv6_tables[] =
1315 NSI_IP_COMPARTMENT_TABLE,
1317 sizeof(DWORD), sizeof(struct nsi_ip_cmpt_rw),
1318 sizeof(struct nsi_ip_cmpt_dynamic), 0
1320 NULL,
1321 ipv6_cmpt_get_all_parameters,
1324 NSI_IP_ICMPSTATS_TABLE,
1326 0, 0,
1327 sizeof(struct nsi_ip_icmpstats_dynamic), 0
1329 NULL,
1330 ipv6_icmpstats_get_all_parameters,
1333 NSI_IP_IPSTATS_TABLE,
1335 0, 0,
1336 sizeof(struct nsi_ip_ipstats_dynamic), sizeof(struct nsi_ip_ipstats_static)
1338 NULL,
1339 ipv6_ipstats_get_all_parameters,
1342 NSI_IP_UNICAST_TABLE,
1344 sizeof(struct nsi_ipv6_unicast_key), sizeof(struct nsi_ip_unicast_rw),
1345 sizeof(struct nsi_ip_unicast_dynamic), sizeof(struct nsi_ip_unicast_static)
1347 ipv6_unicast_enumerate_all,
1348 ip_unicast_get_all_parameters,
1351 NSI_IP_NEIGHBOUR_TABLE,
1353 sizeof(struct nsi_ipv6_neighbour_key), sizeof(struct nsi_ip_neighbour_rw),
1354 sizeof(struct nsi_ip_neighbour_dynamic), 0
1356 ipv6_neighbour_enumerate_all,
1359 NSI_IP_FORWARD_TABLE,
1361 sizeof(struct nsi_ipv6_forward_key), sizeof(struct nsi_ip_forward_rw),
1362 sizeof(struct nsi_ipv6_forward_dynamic), sizeof(struct nsi_ip_forward_static)
1364 ipv6_forward_enumerate_all,
1371 const struct module ipv6_module =
1373 &NPI_MS_IPV6_MODULEID,
1374 ipv6_tables