mshtml: Implement MediaQueryList's addListener method.
[wine.git] / dlls / nsiproxy.sys / ip.c
blobdbe3a0b46b75f0303ea302145cd0f8d9efd7d4e7
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_NETINET6_IP6_VAR_H
59 #include <netinet6/ip6_var.h>
60 #endif
62 #ifdef __APPLE__
63 /* For reasons unknown, Mac OS doesn't export <netinet6/ip6_var.h> to user-
64 * space. We'll have to define the needed struct ourselves.
66 struct ip6stat {
67 u_quad_t ip6s_total;
68 u_quad_t ip6s_tooshort;
69 u_quad_t ip6s_toosmall;
70 u_quad_t ip6s_fragments;
71 u_quad_t ip6s_fragdropped;
72 u_quad_t ip6s_fragtimeout;
73 u_quad_t ip6s_fragoverflow;
74 u_quad_t ip6s_forward;
75 u_quad_t ip6s_cantforward;
76 u_quad_t ip6s_redirectsent;
77 u_quad_t ip6s_delivered;
78 u_quad_t ip6s_localout;
79 u_quad_t ip6s_odropped;
80 u_quad_t ip6s_reassembled;
81 u_quad_t ip6s_atmfrag_rcvd;
82 u_quad_t ip6s_fragmented;
83 u_quad_t ip6s_ofragments;
84 u_quad_t ip6s_cantfrag;
85 u_quad_t ip6s_badoptions;
86 u_quad_t ip6s_noroute;
87 u_quad_t ip6s_badvers;
88 u_quad_t ip6s_rawout;
89 u_quad_t ip6s_badscope;
90 u_quad_t ip6s_notmember;
91 u_quad_t ip6s_nxthist[256];
92 u_quad_t ip6s_m1;
93 u_quad_t ip6s_m2m[32];
94 u_quad_t ip6s_mext1;
95 u_quad_t ip6s_mext2m;
96 u_quad_t ip6s_exthdrtoolong;
97 u_quad_t ip6s_nogif;
98 u_quad_t ip6s_toomanyhdr;
100 #endif
102 #ifdef HAVE_NETINET_ICMP_VAR_H
103 #include <netinet/icmp_var.h>
104 #endif
106 #ifdef HAVE_NETINET_ICMP6_H
107 #include <netinet/icmp6.h>
108 #undef ICMP6_DST_UNREACH
109 #undef ICMP6_PACKET_TOO_BIG
110 #undef ICMP6_TIME_EXCEEDED
111 #undef ICMP6_PARAM_PROB
112 #undef ICMP6_ECHO_REQUEST
113 #undef ICMP6_ECHO_REPLY
114 #undef ICMP6_MEMBERSHIP_QUERY
115 #undef ICMP6_MEMBERSHIP_REPORT
116 #undef ICMP6_MEMBERSHIP_REDUCTION
117 #undef ND_ROUTER_SOLICIT
118 #undef ND_ROUTER_ADVERT
119 #undef ND_NEIGHBOR_SOLICIT
120 #undef ND_NEIGHBOR_ADVERT
121 #undef ND_REDIRECT
122 #endif
124 #ifdef HAVE_NETINET_IF_ETHER_H
125 #include <netinet/if_ether.h>
126 #endif
128 #ifdef HAVE_NET_IF_ARP_H
129 #include <net/if_arp.h>
130 #endif
132 #ifdef HAVE_NET_IF_DL_H
133 #include <net/if_dl.h>
134 #endif
136 #ifdef HAVE_IFADDRS_H
137 #include <ifaddrs.h>
138 #endif
140 #ifdef HAVE_ARPA_INET_H
141 #include <arpa/inet.h>
142 #endif
144 #include "ntstatus.h"
145 #define WIN32_NO_STATUS
146 #include "windef.h"
147 #include "winbase.h"
148 #include "winternl.h"
149 #include "winioctl.h"
150 #define USE_WS_PREFIX
151 #include "winsock2.h"
152 #include "ws2ipdef.h"
153 #include "nldef.h"
154 #include "ifdef.h"
155 #include "ipmib.h"
156 #include "netiodef.h"
157 #include "wine/nsi.h"
158 #include "wine/debug.h"
160 #include "unix_private.h"
162 WINE_DEFAULT_DEBUG_CHANNEL(nsi);
164 static inline UINT nsi_popcount( UINT m )
166 #ifdef HAVE___BUILTIN_POPCOUNT
167 return __builtin_popcount( m );
168 #else
169 m -= m >> 1 & 0x55555555;
170 m = (m & 0x33333333) + (m >> 2 & 0x33333333);
171 return ((m + (m >> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
172 #endif
175 static UINT mask_v4_to_prefix( struct in_addr *addr )
177 return nsi_popcount( addr->s_addr );
180 static UINT mask_v6_to_prefix( struct in6_addr *addr )
182 UINT ret;
184 ret = nsi_popcount( *(UINT *)addr->s6_addr );
185 ret += nsi_popcount( *(UINT *)(addr->s6_addr + 4) );
186 ret += nsi_popcount( *(UINT *)(addr->s6_addr + 8) );
187 ret += nsi_popcount( *(UINT *)(addr->s6_addr + 12) );
188 return ret;
191 static ULONG64 get_boot_time( void )
193 SYSTEM_TIMEOFDAY_INFORMATION ti;
195 NtQuerySystemInformation( SystemTimeOfDayInformation, &ti, sizeof(ti), NULL );
196 return ti.BootTime.QuadPart;
199 #if __linux__
200 static NTSTATUS read_sysctl_int( const char *file, int *val )
202 FILE *fp;
203 char buf[128], *endptr = buf;
205 fp = fopen( file, "r" );
206 if (!fp) return STATUS_NOT_SUPPORTED;
208 if (fgets( buf, sizeof(buf), fp ))
209 *val = strtol( buf, &endptr, 10 );
211 fclose( fp );
212 return (endptr == buf) ? STATUS_NOT_SUPPORTED : STATUS_SUCCESS;
214 #endif
216 static NTSTATUS ip_cmpt_get_all_parameters( UINT fam, const UINT *key, UINT key_size,
217 struct nsi_ip_cmpt_rw *rw_data, UINT rw_size,
218 struct nsi_ip_cmpt_dynamic *dynamic_data, UINT dynamic_size,
219 void *static_data, UINT static_size )
221 const NPI_MODULEID *ip_mod = (fam == AF_INET) ? &NPI_MS_IPV4_MODULEID : &NPI_MS_IPV6_MODULEID;
222 struct nsi_ip_cmpt_rw rw;
223 struct nsi_ip_cmpt_dynamic dyn;
224 UINT count;
226 memset( &rw, 0, sizeof(rw) );
227 memset( &dyn, 0, sizeof(dyn) );
229 if (*key != 1) return STATUS_NOT_SUPPORTED;
231 #if __linux__
233 const char *fwd = (fam == AF_INET) ? "/proc/sys/net/ipv4/conf/default/forwarding" :
234 "/proc/sys/net/ipv6/conf/default/forwarding";
235 const char *ttl = (fam == AF_INET) ? "/proc/sys/net/ipv4/ip_default_ttl" :
236 "/proc/sys/net/ipv6/conf/default/hop_limit";
237 int value;
239 if (!read_sysctl_int( fwd, &value )) rw.not_forwarding = !value;
240 if (!read_sysctl_int( ttl, &value )) rw.default_ttl = value;
242 #elif defined(HAVE_SYS_SYSCTL_H)
244 int fwd_4[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_FORWARDING };
245 int fwd_6[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_FORWARDING };
246 int ttl_4[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
247 int ttl_6[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
248 int value;
249 size_t needed;
251 needed = sizeof(value);
252 if (!sysctl( (fam == AF_INET) ? fwd_4 : fwd_6, ARRAY_SIZE(fwd_4), &value, &needed, NULL, 0 ))
253 rw.not_forwarding = value;
255 needed = sizeof(value);
256 if (!sysctl( (fam == AF_INET) ? ttl_4 : ttl_6, ARRAY_SIZE(ttl_4), &value, &needed, NULL, 0 ))
257 rw.default_ttl = value;
259 #else
260 FIXME( "forwarding and default ttl not implemented\n" );
261 #endif
263 count = 0;
264 if (!nsi_enumerate_all( 1, 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0, NULL, 0,
265 NULL, 0, NULL, 0, &count ))
266 dyn.num_ifs = count;
268 count = 0;
269 if (!nsi_enumerate_all( 1, 0, ip_mod, NSI_IP_FORWARD_TABLE, NULL, 0, NULL, 0,
270 NULL, 0, NULL, 0, &count ))
271 dyn.num_routes = count;
273 count = 0;
274 if (!nsi_enumerate_all( 1, 0, ip_mod, NSI_IP_UNICAST_TABLE, NULL, 0, NULL, 0,
275 NULL, 0, NULL, 0, &count ))
276 dyn.num_addrs = count;
278 if (rw_data) *rw_data = rw;
279 if (dynamic_data) *dynamic_data = dyn;
281 return STATUS_SUCCESS;
284 static NTSTATUS ipv4_cmpt_get_all_parameters( const void *key, UINT key_size, void *rw_data, UINT rw_size,
285 void *dynamic_data, UINT dynamic_size, void *static_data, UINT static_size )
287 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
288 static_data, static_size );
289 return ip_cmpt_get_all_parameters( AF_INET, key, key_size, rw_data, rw_size,
290 dynamic_data, dynamic_size, static_data, static_size );
293 static NTSTATUS ipv6_cmpt_get_all_parameters( const void *key, UINT key_size, void *rw_data, UINT rw_size,
294 void *dynamic_data, UINT dynamic_size, void *static_data, UINT static_size )
296 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
297 static_data, static_size );
298 return ip_cmpt_get_all_parameters( AF_INET6, key, key_size, rw_data, rw_size,
299 dynamic_data, dynamic_size, static_data, static_size );
302 static NTSTATUS ipv4_icmpstats_get_all_parameters( const void *key, UINT key_size, void *rw_data, UINT rw_size,
303 void *dynamic_data, UINT dynamic_size, void *static_data, UINT static_size )
305 struct nsi_ip_icmpstats_dynamic dyn;
307 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
308 static_data, static_size );
310 memset( &dyn, 0, sizeof(dyn) );
312 #ifdef __linux__
314 NTSTATUS status = STATUS_NOT_SUPPORTED;
315 static const char hdr[] = "Icmp:";
316 char buf[512], *ptr;
317 FILE *fp;
319 if (!(fp = fopen( "/proc/net/snmp", "r" ))) return STATUS_NOT_SUPPORTED;
321 while ((ptr = fgets( buf, sizeof(buf), fp )))
323 if (ascii_strncasecmp( buf, hdr, sizeof(hdr) - 1 )) continue;
324 /* last line was a header, get another */
325 if (!(ptr = fgets( buf, sizeof(buf), fp ))) break;
326 if (!ascii_strncasecmp( buf, hdr, sizeof(hdr) - 1 ))
328 ptr += sizeof(hdr);
329 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",
330 &dyn.in_msgs,
331 &dyn.in_errors,
332 &dyn.in_type_counts[ICMP4_DST_UNREACH],
333 &dyn.in_type_counts[ICMP4_TIME_EXCEEDED],
334 &dyn.in_type_counts[ICMP4_PARAM_PROB],
335 &dyn.in_type_counts[ICMP4_SOURCE_QUENCH],
336 &dyn.in_type_counts[ICMP4_REDIRECT],
337 &dyn.in_type_counts[ICMP4_ECHO_REQUEST],
338 &dyn.in_type_counts[ICMP4_ECHO_REPLY],
339 &dyn.in_type_counts[ICMP4_TIMESTAMP_REQUEST],
340 &dyn.in_type_counts[ICMP4_TIMESTAMP_REPLY],
341 &dyn.in_type_counts[ICMP4_MASK_REQUEST],
342 &dyn.in_type_counts[ICMP4_MASK_REPLY],
343 &dyn.out_msgs,
344 &dyn.out_errors,
345 &dyn.out_type_counts[ICMP4_DST_UNREACH],
346 &dyn.out_type_counts[ICMP4_TIME_EXCEEDED],
347 &dyn.out_type_counts[ICMP4_PARAM_PROB],
348 &dyn.out_type_counts[ICMP4_SOURCE_QUENCH],
349 &dyn.out_type_counts[ICMP4_REDIRECT],
350 &dyn.out_type_counts[ICMP4_ECHO_REQUEST],
351 &dyn.out_type_counts[ICMP4_ECHO_REPLY],
352 &dyn.out_type_counts[ICMP4_TIMESTAMP_REQUEST],
353 &dyn.out_type_counts[ICMP4_TIMESTAMP_REPLY],
354 &dyn.out_type_counts[ICMP4_MASK_REQUEST],
355 &dyn.out_type_counts[ICMP4_MASK_REPLY] );
356 status = STATUS_SUCCESS;
357 if (dynamic_data) *(struct nsi_ip_icmpstats_dynamic *)dynamic_data = dyn;
358 break;
361 fclose( fp );
362 return status;
364 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS) && defined(HAVE_STRUCT_ICMPSTAT_ICPS_ERROR)
366 int mib[] = { CTL_NET, PF_INET, IPPROTO_ICMP, ICMPCTL_STATS };
367 struct icmpstat icmp_stat;
368 size_t needed = sizeof(icmp_stat);
369 int i;
371 if (sysctl( mib, ARRAY_SIZE(mib), &icmp_stat, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
373 dyn.in_msgs = icmp_stat.icps_badcode + icmp_stat.icps_checksum + icmp_stat.icps_tooshort + icmp_stat.icps_badlen;
374 for (i = 0; i <= ICMP_MAXTYPE; i++)
375 dyn.in_msgs += icmp_stat.icps_inhist[i];
377 dyn.in_errors = icmp_stat.icps_badcode + icmp_stat.icps_tooshort + icmp_stat.icps_checksum + icmp_stat.icps_badlen;
379 dyn.in_type_counts[ICMP4_DST_UNREACH] = icmp_stat.icps_inhist[ICMP_UNREACH];
380 dyn.in_type_counts[ICMP4_TIME_EXCEEDED] = icmp_stat.icps_inhist[ICMP_TIMXCEED];
381 dyn.in_type_counts[ICMP4_PARAM_PROB] = icmp_stat.icps_inhist[ICMP_PARAMPROB];
382 dyn.in_type_counts[ICMP4_SOURCE_QUENCH] = icmp_stat.icps_inhist[ICMP_SOURCEQUENCH];
383 dyn.in_type_counts[ICMP4_REDIRECT] = icmp_stat.icps_inhist[ICMP_REDIRECT];
384 dyn.in_type_counts[ICMP4_ECHO_REQUEST] = icmp_stat.icps_inhist[ICMP_ECHO];
385 dyn.in_type_counts[ICMP4_ECHO_REPLY] = icmp_stat.icps_inhist[ICMP_ECHOREPLY];
386 dyn.in_type_counts[ICMP4_TIMESTAMP_REQUEST] = icmp_stat.icps_inhist[ICMP_TSTAMP];
387 dyn.in_type_counts[ICMP4_TIMESTAMP_REPLY] = icmp_stat.icps_inhist[ICMP_TSTAMPREPLY];
388 dyn.in_type_counts[ICMP4_MASK_REQUEST] = icmp_stat.icps_inhist[ICMP_MASKREQ];
389 dyn.in_type_counts[ICMP4_MASK_REPLY] = icmp_stat.icps_inhist[ICMP_MASKREPLY];
391 dyn.out_msgs = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
392 for (i = 0; i <= ICMP_MAXTYPE; i++)
393 dyn.out_msgs += icmp_stat.icps_outhist[i];
395 dyn.out_errors = icmp_stat.icps_oldshort + icmp_stat.icps_oldicmp;
397 dyn.out_type_counts[ICMP4_DST_UNREACH] = icmp_stat.icps_outhist[ICMP_UNREACH];
398 dyn.out_type_counts[ICMP4_TIME_EXCEEDED] = icmp_stat.icps_outhist[ICMP_TIMXCEED];
399 dyn.out_type_counts[ICMP4_PARAM_PROB] = icmp_stat.icps_outhist[ICMP_PARAMPROB];
400 dyn.out_type_counts[ICMP4_SOURCE_QUENCH] = icmp_stat.icps_outhist[ICMP_SOURCEQUENCH];
401 dyn.out_type_counts[ICMP4_REDIRECT] = icmp_stat.icps_outhist[ICMP_REDIRECT];
402 dyn.out_type_counts[ICMP4_ECHO_REQUEST] = icmp_stat.icps_outhist[ICMP_ECHO];
403 dyn.out_type_counts[ICMP4_ECHO_REPLY] = icmp_stat.icps_outhist[ICMP_ECHOREPLY];
404 dyn.out_type_counts[ICMP4_TIMESTAMP_REQUEST] = icmp_stat.icps_outhist[ICMP_TSTAMP];
405 dyn.out_type_counts[ICMP4_TIMESTAMP_REPLY] = icmp_stat.icps_outhist[ICMP_TSTAMPREPLY];
406 dyn.out_type_counts[ICMP4_MASK_REQUEST] = icmp_stat.icps_outhist[ICMP_MASKREQ];
407 dyn.out_type_counts[ICMP4_MASK_REPLY] = icmp_stat.icps_outhist[ICMP_MASKREPLY];
408 if (dynamic_data) *(struct nsi_ip_icmpstats_dynamic *)dynamic_data = dyn;
409 return STATUS_SUCCESS;
411 #else
412 FIXME( "not implemented\n" );
413 return STATUS_NOT_IMPLEMENTED;
414 #endif
417 static NTSTATUS ipv6_icmpstats_get_all_parameters( const void *key, UINT key_size, void *rw_data, UINT rw_size,
418 void *dynamic_data, UINT dynamic_size, void *static_data, UINT static_size )
420 struct nsi_ip_icmpstats_dynamic dyn;
422 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
423 static_data, static_size );
425 memset( &dyn, 0, sizeof(dyn) );
427 #ifdef __linux__
429 struct data
431 const char *name;
432 UINT pos;
434 static const struct data in_list[] =
436 { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH },
437 { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG },
438 { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED },
439 { "Icmp6InParmProblems", ICMP6_PARAM_PROB },
440 { "Icmp6InEchos", ICMP6_ECHO_REQUEST },
441 { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY },
442 { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
443 { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
444 { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
445 { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT },
446 { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT },
447 { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT },
448 { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
449 { "Icmp6InRedirects", ND_REDIRECT },
450 { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
452 static const struct data out_list[] =
454 { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH },
455 { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG },
456 { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED },
457 { "Icmp6OutParmProblems", ICMP6_PARAM_PROB },
458 { "Icmp6OutEchos", ICMP6_ECHO_REQUEST },
459 { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY },
460 { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY },
461 { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT },
462 { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION },
463 { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT },
464 { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT },
465 { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT },
466 { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT },
467 { "Icmp6OutRedirects", ND_REDIRECT },
468 { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT },
470 char buf[512], *ptr, *value;
471 UINT res, i;
472 FILE *fp;
474 if (!(fp = fopen( "/proc/net/snmp6", "r" ))) return STATUS_NOT_SUPPORTED;
476 while ((ptr = fgets( buf, sizeof(buf), fp )))
478 if (!(value = strchr( buf, ' ' ))) continue;
480 /* terminate the valuename */
481 ptr = value - 1;
482 *(ptr + 1) = '\0';
484 /* and strip leading spaces from value */
485 value += 1;
486 while (*value == ' ') value++;
487 if ((ptr = strchr( value, '\n' ))) *ptr='\0';
489 if (!ascii_strcasecmp( buf, "Icmp6InMsgs" ))
491 if (sscanf( value, "%d", &res )) dyn.in_msgs = res;
492 continue;
495 if (!ascii_strcasecmp( buf, "Icmp6InErrors" ))
497 if (sscanf( value, "%d", &res )) dyn.in_errors = res;
498 continue;
501 for (i = 0; i < ARRAY_SIZE(in_list); i++)
503 if (!ascii_strcasecmp( buf, in_list[i].name ))
505 if (sscanf( value, "%d", &res ))
506 dyn.in_type_counts[in_list[i].pos] = res;
507 break;
511 if (!ascii_strcasecmp( buf, "Icmp6OutMsgs" ))
513 if (sscanf( value, "%d", &res )) dyn.out_msgs = res;
514 continue;
517 if (!ascii_strcasecmp( buf, "Icmp6OutErrors" ))
519 if (sscanf( value, "%d", &res )) dyn.out_errors = res;
520 continue;
523 for (i = 0; i < ARRAY_SIZE(out_list); i++)
525 if (!ascii_strcasecmp( buf, out_list[i].name ))
527 if (sscanf( value, "%d", &res ))
528 dyn.out_type_counts[out_list[i].pos] = res;
529 break;
533 fclose( fp );
534 if (dynamic_data) *(struct nsi_ip_icmpstats_dynamic *)dynamic_data = dyn;
535 return STATUS_SUCCESS;
537 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPV6CTL_STATS) && defined(HAVE_STRUCT_ICMP6STAT_ICP6S_ERROR)
539 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_STATS };
540 struct icmp6stat icmp_stat;
541 size_t needed = sizeof(icmp_stat);
542 int i;
544 if (sysctl( mib, ARRAY_SIZE(mib), &icmp_stat, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
546 dyn.in_msgs = icmp_stat.icp6s_badcode + icmp_stat.icp6s_checksum + icmp_stat.icp6s_tooshort +
547 icmp_stat.icp6s_badlen + icmp_stat.icp6s_nd_toomanyopt;
548 for (i = 0; i <= ICMP6_MAXTYPE; i++)
549 dyn.in_msgs += icmp_stat.icp6s_inhist[i];
551 dyn.in_errors = icmp_stat.icp6s_badcode + icmp_stat.icp6s_checksum + icmp_stat.icp6s_tooshort +
552 icmp_stat.icp6s_badlen + icmp_stat.icp6s_nd_toomanyopt;
554 dyn.in_type_counts[ICMP6_DST_UNREACH] = icmp_stat.icp6s_inhist[ICMP6_DST_UNREACH];
555 dyn.in_type_counts[ICMP6_PACKET_TOO_BIG] = icmp_stat.icp6s_inhist[ICMP6_PACKET_TOO_BIG];
556 dyn.in_type_counts[ICMP6_TIME_EXCEEDED] = icmp_stat.icp6s_inhist[ICMP6_TIME_EXCEEDED];
557 dyn.in_type_counts[ICMP6_PARAM_PROB] = icmp_stat.icp6s_inhist[ICMP6_PARAM_PROB];
558 dyn.in_type_counts[ICMP6_ECHO_REQUEST] = icmp_stat.icp6s_inhist[ICMP6_ECHO_REQUEST];
559 dyn.in_type_counts[ICMP6_ECHO_REPLY] = icmp_stat.icp6s_inhist[ICMP6_ECHO_REPLY];
560 dyn.in_type_counts[ICMP6_MEMBERSHIP_QUERY] = icmp_stat.icp6s_inhist[ICMP6_MEMBERSHIP_QUERY];
561 dyn.in_type_counts[ICMP6_MEMBERSHIP_REPORT] = icmp_stat.icp6s_inhist[ICMP6_MEMBERSHIP_REPORT];
562 dyn.in_type_counts[ICMP6_MEMBERSHIP_REDUCTION] = icmp_stat.icp6s_inhist[ICMP6_MEMBERSHIP_REDUCTION];
563 dyn.in_type_counts[ND_ROUTER_SOLICIT] = icmp_stat.icp6s_inhist[ND_ROUTER_SOLICIT];
564 dyn.in_type_counts[ND_ROUTER_ADVERT] = icmp_stat.icp6s_inhist[ND_ROUTER_ADVERT];
565 dyn.in_type_counts[ND_NEIGHBOR_SOLICIT] = icmp_stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT];
566 dyn.in_type_counts[ND_NEIGHBOR_ADVERT] = icmp_stat.icp6s_inhist[ND_NEIGHBOR_ADVERT];
567 dyn.in_type_counts[ND_REDIRECT] = icmp_stat.icp6s_inhist[ND_REDIRECT];
568 dyn.in_type_counts[ICMP6_V2_MEMBERSHIP_REPORT] = icmp_stat.icp6s_inhist[MLDV2_LISTENER_REPORT];
570 dyn.out_msgs = icmp_stat.icp6s_canterror + icmp_stat.icp6s_toofreq;
571 for (i = 0; i <= ICMP6_MAXTYPE; i++)
572 dyn.out_msgs += icmp_stat.icp6s_outhist[i];
574 dyn.out_errors = icmp_stat.icp6s_canterror + icmp_stat.icp6s_toofreq;
576 dyn.out_type_counts[ICMP6_DST_UNREACH] = icmp_stat.icp6s_outhist[ICMP6_DST_UNREACH];
577 dyn.out_type_counts[ICMP6_PACKET_TOO_BIG] = icmp_stat.icp6s_outhist[ICMP6_PACKET_TOO_BIG];
578 dyn.out_type_counts[ICMP6_TIME_EXCEEDED] = icmp_stat.icp6s_outhist[ICMP6_TIME_EXCEEDED];
579 dyn.out_type_counts[ICMP6_PARAM_PROB] = icmp_stat.icp6s_outhist[ICMP6_PARAM_PROB];
580 dyn.out_type_counts[ICMP6_ECHO_REQUEST] = icmp_stat.icp6s_outhist[ICMP6_ECHO_REQUEST];
581 dyn.out_type_counts[ICMP6_ECHO_REPLY] = icmp_stat.icp6s_outhist[ICMP6_ECHO_REPLY];
582 dyn.out_type_counts[ICMP6_MEMBERSHIP_QUERY] = icmp_stat.icp6s_outhist[ICMP6_MEMBERSHIP_QUERY];
583 dyn.out_type_counts[ICMP6_MEMBERSHIP_REPORT] = icmp_stat.icp6s_outhist[ICMP6_MEMBERSHIP_REPORT];
584 dyn.out_type_counts[ICMP6_MEMBERSHIP_REDUCTION] = icmp_stat.icp6s_outhist[ICMP6_MEMBERSHIP_REDUCTION];
585 dyn.out_type_counts[ND_ROUTER_SOLICIT] = icmp_stat.icp6s_outhist[ND_ROUTER_SOLICIT];
586 dyn.out_type_counts[ND_ROUTER_ADVERT] = icmp_stat.icp6s_outhist[ND_ROUTER_ADVERT];
587 dyn.out_type_counts[ND_NEIGHBOR_SOLICIT] = icmp_stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT];
588 dyn.out_type_counts[ND_NEIGHBOR_ADVERT] = icmp_stat.icp6s_outhist[ND_NEIGHBOR_ADVERT];
589 dyn.out_type_counts[ND_REDIRECT] = icmp_stat.icp6s_outhist[ND_REDIRECT];
590 dyn.out_type_counts[ICMP6_V2_MEMBERSHIP_REPORT] = icmp_stat.icp6s_outhist[MLDV2_LISTENER_REPORT];
591 if (dynamic_data) *(struct nsi_ip_icmpstats_dynamic *)dynamic_data = dyn;
592 return STATUS_SUCCESS;
594 #else
595 FIXME( "not implemented\n" );
596 return STATUS_NOT_IMPLEMENTED;
597 #endif
600 static NTSTATUS ipv4_ipstats_get_all_parameters( const void *key, UINT key_size, void *rw_data, UINT rw_size,
601 void *dynamic_data, UINT dynamic_size, void *static_data, UINT static_size )
603 struct nsi_ip_ipstats_dynamic dyn;
604 struct nsi_ip_ipstats_static stat;
606 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
607 static_data, static_size );
609 memset( &dyn, 0, sizeof(dyn) );
610 memset( &stat, 0, sizeof(stat) );
612 #ifdef __linux__
614 NTSTATUS status = STATUS_NOT_SUPPORTED;
615 static const char hdr[] = "Ip:";
616 char buf[512], *ptr;
617 FILE *fp;
619 if (!(fp = fopen( "/proc/net/snmp", "r" ))) return STATUS_NOT_SUPPORTED;
621 while ((ptr = fgets( buf, sizeof(buf), fp )))
623 if (ascii_strncasecmp( buf, hdr, sizeof(hdr) - 1 )) continue;
624 /* last line was a header, get another */
625 if (!(ptr = fgets( buf, sizeof(buf), fp ))) break;
626 if (!ascii_strncasecmp( buf, hdr, sizeof(hdr) - 1 ))
628 UINT in_recv, in_hdr_errs, fwd_dgrams, in_delivers, out_reqs;
629 ptr += sizeof(hdr);
630 sscanf( ptr, "%*u %*u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
631 &in_recv,
632 &in_hdr_errs,
633 &dyn.in_addr_errs,
634 &fwd_dgrams,
635 &dyn.in_unk_protos,
636 &dyn.in_discards,
637 &in_delivers,
638 &out_reqs,
639 &dyn.out_discards,
640 &dyn.out_no_routes,
641 &stat.reasm_timeout,
642 &dyn.reasm_reqds,
643 &dyn.reasm_oks,
644 &dyn.reasm_fails,
645 &dyn.frag_oks,
646 &dyn.frag_fails,
647 &dyn.frag_creates );
648 /* no routingDiscards */
649 dyn.in_recv = in_recv;
650 dyn.in_hdr_errs = in_hdr_errs;
651 dyn.fwd_dgrams = fwd_dgrams;
652 dyn.in_delivers = in_delivers;
653 dyn.out_reqs = out_reqs;
654 if (dynamic_data) *(struct nsi_ip_ipstats_dynamic *)dynamic_data = dyn;
655 if (static_data) *(struct nsi_ip_ipstats_static *)static_data = stat;
656 status = STATUS_SUCCESS;
657 break;
660 fclose( fp );
661 return status;
663 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
665 int mib[] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS };
666 #if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
667 struct ipstat ip_stat;
668 #elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
669 struct ip_stats ip_stat;
670 #endif
671 size_t needed;
673 needed = sizeof(ip_stat);
674 if (sysctl( mib, ARRAY_SIZE(mib), &ip_stat, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
676 dyn.in_recv = ip_stat.ips_total;
677 dyn.in_hdr_errs = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen +
678 ip_stat.ips_badvers + ip_stat.ips_badoptions;
679 /* ips_badaddr also includes outgoing packets with a bad address, but we can't account for that right now */
680 dyn.in_addr_errs = ip_stat.ips_cantforward + ip_stat.ips_badaddr + ip_stat.ips_notmember;
681 dyn.fwd_dgrams = ip_stat.ips_forward;
682 dyn.in_unk_protos = ip_stat.ips_noproto;
683 dyn.in_discards = ip_stat.ips_fragdropped;
684 dyn.in_delivers = ip_stat.ips_delivered;
685 dyn.out_reqs = ip_stat.ips_localout;
686 dyn.out_discards = ip_stat.ips_odropped;
687 dyn.out_no_routes = ip_stat.ips_noroute;
688 stat.reasm_timeout = ip_stat.ips_fragtimeout;
689 dyn.reasm_reqds = ip_stat.ips_fragments;
690 dyn.reasm_oks = ip_stat.ips_reassembled;
691 dyn.reasm_fails = ip_stat.ips_fragments - ip_stat.ips_reassembled;
692 dyn.frag_oks = ip_stat.ips_fragmented;
693 dyn.frag_fails = ip_stat.ips_cantfrag;
694 dyn.frag_creates = ip_stat.ips_ofragments;
696 if (dynamic_data) *(struct nsi_ip_ipstats_dynamic *)dynamic_data = dyn;
697 if (static_data) *(struct nsi_ip_ipstats_static *)static_data = stat;
698 return STATUS_SUCCESS;
700 #else
701 FIXME( "not implemented\n" );
702 return STATUS_NOT_IMPLEMENTED;
703 #endif
706 static NTSTATUS ipv6_ipstats_get_all_parameters( const void *key, UINT key_size, void *rw_data, UINT rw_size,
707 void *dynamic_data, UINT dynamic_size, void *static_data, UINT static_size )
709 struct nsi_ip_ipstats_dynamic dyn;
710 struct nsi_ip_ipstats_static stat;
712 memset( &dyn, 0, sizeof(dyn) );
713 memset( &stat, 0, sizeof(stat) );
715 #ifdef __linux__
717 struct
719 const char *name;
720 void *elem;
721 int size;
722 } ipstatlist[] =
724 #define X(x) &x, sizeof(x)
725 { "Ip6InReceives", X( dyn.in_recv ) },
726 { "Ip6InHdrErrors", X( dyn.in_hdr_errs ) },
727 { "Ip6InAddrErrors", X( dyn.in_addr_errs ) },
728 { "Ip6OutForwDatagrams", X( dyn.fwd_dgrams ) },
729 { "Ip6InUnknownProtos", X( dyn.in_unk_protos ) },
730 { "Ip6InDiscards", X( dyn.in_discards ) },
731 { "Ip6InDelivers", X( dyn.in_delivers ) },
732 { "Ip6OutRequests", X( dyn.out_reqs ) },
733 { "Ip6OutDiscards", X( dyn.out_discards ) },
734 { "Ip6OutNoRoutes", X( dyn.out_no_routes ) },
735 { "Ip6ReasmTimeout", X( stat.reasm_timeout ) },
736 { "Ip6ReasmReqds", X( dyn.reasm_reqds ) },
737 { "Ip6ReasmOKs", X( dyn.reasm_oks ) },
738 { "Ip6ReasmFails", X( dyn.reasm_fails ) },
739 { "Ip6FragOKs", X( dyn.frag_oks ) },
740 { "Ip6FragFails", X( dyn.frag_fails ) },
741 { "Ip6FragCreates", X( dyn.frag_creates ) },
742 /* no routingDiscards */
743 #undef X
745 NTSTATUS status = STATUS_NOT_SUPPORTED;
746 char buf[512], *ptr, *value;
747 UINT i;
748 FILE *fp;
750 if (!(fp = fopen( "/proc/net/snmp6", "r" ))) return STATUS_NOT_SUPPORTED;
752 while ((ptr = fgets( buf, sizeof(buf), fp )))
754 if (!(value = strchr( buf, ' ' ))) continue;
755 /* terminate the valuename */
756 *value++ = '\0';
757 /* and strip leading spaces from value */
758 while (*value == ' ') value++;
759 if ((ptr = strchr( value, '\n' ))) *ptr = '\0';
761 for (i = 0; i < ARRAY_SIZE(ipstatlist); i++)
762 if (!ascii_strcasecmp( buf, ipstatlist[i].name ))
764 if (ipstatlist[i].size == sizeof(long))
765 *(long *)ipstatlist[i].elem = strtoul( value, NULL, 10 );
766 else
767 *(long long *)ipstatlist[i].elem = strtoull( value, NULL, 10 );
768 status = STATUS_SUCCESS;
771 fclose( fp );
772 if (dynamic_data) *(struct nsi_ip_ipstats_dynamic *)dynamic_data = dyn;
773 if (static_data) *(struct nsi_ip_ipstats_static *)static_data = stat;
774 return status;
776 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPV6CTL_STATS) && (defined(HAVE_STRUCT_IP6STAT_IP6S_TOTAL) || defined(__APPLE__))
778 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_STATS };
779 struct ip6stat ip_stat;
780 size_t needed;
782 needed = sizeof(ip_stat);
783 if (sysctl( mib, ARRAY_SIZE(mib), &ip_stat, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
785 dyn.in_recv = ip_stat.ip6s_total;
786 dyn.in_hdr_errs = ip_stat.ip6s_tooshort + ip_stat.ip6s_toosmall + ip_stat.ip6s_badvers +
787 ip_stat.ip6s_badoptions + ip_stat.ip6s_exthdrtoolong + ip_stat.ip6s_toomanyhdr;
788 dyn.in_addr_errs = ip_stat.ip6s_cantforward + ip_stat.ip6s_badscope + ip_stat.ip6s_notmember;
789 dyn.fwd_dgrams = ip_stat.ip6s_forward;
790 dyn.in_discards = ip_stat.ip6s_fragdropped;
791 dyn.in_delivers = ip_stat.ip6s_delivered;
792 dyn.out_reqs = ip_stat.ip6s_localout;
793 dyn.out_discards = ip_stat.ip6s_odropped;
794 dyn.out_no_routes = ip_stat.ip6s_noroute;
795 stat.reasm_timeout = ip_stat.ip6s_fragtimeout;
796 dyn.reasm_reqds = ip_stat.ip6s_fragments;
797 dyn.reasm_oks = ip_stat.ip6s_reassembled;
798 dyn.reasm_fails = ip_stat.ip6s_fragments - ip_stat.ip6s_reassembled;
799 dyn.frag_oks = ip_stat.ip6s_fragmented;
800 dyn.frag_fails = ip_stat.ip6s_cantfrag;
801 dyn.frag_creates = ip_stat.ip6s_ofragments;
803 if (dynamic_data) *(struct nsi_ip_ipstats_dynamic *)dynamic_data = dyn;
804 if (static_data) *(struct nsi_ip_ipstats_static *)static_data = stat;
805 return STATUS_SUCCESS;
807 #else
808 FIXME( "not implemented\n" );
809 return STATUS_NOT_IMPLEMENTED;
810 #endif
813 static void unicast_fill_entry( struct ifaddrs *entry, void *key, struct nsi_ip_unicast_rw *rw,
814 struct nsi_ip_unicast_dynamic *dyn, struct nsi_ip_unicast_static *stat )
816 struct nsi_ipv6_unicast_key placeholder, *key6 = key;
817 struct nsi_ipv4_unicast_key *key4 = key;
818 UINT scope_id = 0;
820 if (!key)
822 key6 = &placeholder;
823 key4 = (struct nsi_ipv4_unicast_key *)&placeholder;
826 convert_unix_name_to_luid( entry->ifa_name, &key6->luid );
828 if (entry->ifa_addr->sa_family == AF_INET)
830 memcpy( &key4->addr, &((struct sockaddr_in *)entry->ifa_addr)->sin_addr, sizeof(key4->addr) );
831 key4->pad = 0;
833 else if (entry->ifa_addr->sa_family == AF_INET6)
835 memcpy( &key6->addr, &((struct sockaddr_in6 *)entry->ifa_addr)->sin6_addr, sizeof(key6->addr) );
836 scope_id = ((struct sockaddr_in6 *)entry->ifa_addr)->sin6_scope_id;
839 if (rw)
841 rw->preferred_lifetime = 60000;
842 rw->valid_lifetime = 60000;
844 if (key6->luid.Info.IfType != IF_TYPE_SOFTWARE_LOOPBACK)
846 rw->prefix_origin = IpPrefixOriginDhcp;
847 rw->suffix_origin = IpSuffixOriginDhcp;
849 else
851 rw->prefix_origin = IpPrefixOriginManual;
852 rw->suffix_origin = IpSuffixOriginManual;
854 if (entry->ifa_netmask && entry->ifa_netmask->sa_family == AF_INET)
855 rw->on_link_prefix = mask_v4_to_prefix( &((struct sockaddr_in *)entry->ifa_netmask)->sin_addr );
856 else if (entry->ifa_netmask && entry->ifa_netmask->sa_family == AF_INET6)
857 rw->on_link_prefix = mask_v6_to_prefix( &((struct sockaddr_in6 *)entry->ifa_netmask)->sin6_addr );
858 else rw->on_link_prefix = 0;
859 rw->unk[0] = 0;
860 rw->unk[1] = 0;
863 if (dyn)
865 dyn->scope_id = scope_id;
866 dyn->dad_state = IpDadStatePreferred;
869 if (stat) stat->creation_time = get_boot_time();
872 static NTSTATUS ip_unicast_enumerate_all( int family, void *key_data, UINT key_size, void *rw_data, UINT rw_size,
873 void *dynamic_data, UINT dynamic_size,
874 void *static_data, UINT static_size, UINT_PTR *count )
876 UINT num = 0;
877 NTSTATUS status = STATUS_SUCCESS;
878 BOOL want_data = key_size || rw_size || dynamic_size || static_size;
879 struct ifaddrs *addrs, *entry;
881 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
882 dynamic_data, dynamic_size, static_data, static_size, count );
884 if (getifaddrs( &addrs )) return STATUS_NO_MORE_ENTRIES;
886 for (entry = addrs; entry; entry = entry->ifa_next)
888 if (!entry->ifa_addr || entry->ifa_addr->sa_family != family) continue;
890 if (num < *count)
892 unicast_fill_entry( entry, key_data, rw_data, dynamic_data, static_data );
893 key_data = (BYTE *)key_data + key_size;
894 rw_data = (BYTE *)rw_data + rw_size;
895 dynamic_data = (BYTE *)dynamic_data + dynamic_size;
896 static_data = (BYTE *)static_data + static_size;
898 num++;
901 freeifaddrs( addrs );
903 if (!want_data || num <= *count) *count = num;
904 else status = STATUS_BUFFER_OVERFLOW;
906 return status;
909 static NTSTATUS ipv4_unicast_enumerate_all( void *key_data, UINT key_size, void *rw_data, UINT rw_size,
910 void *dynamic_data, UINT dynamic_size,
911 void *static_data, UINT static_size, UINT_PTR *count )
913 return ip_unicast_enumerate_all( AF_INET, key_data, key_size, rw_data, rw_size,
914 dynamic_data, dynamic_size, static_data, static_size, count );
917 static NTSTATUS ipv6_unicast_enumerate_all( void *key_data, UINT key_size, void *rw_data, UINT rw_size,
918 void *dynamic_data, UINT dynamic_size,
919 void *static_data, UINT static_size, UINT_PTR *count )
921 return ip_unicast_enumerate_all( AF_INET6, key_data, key_size, rw_data, rw_size,
922 dynamic_data, dynamic_size, static_data, static_size, count );
925 static NTSTATUS ip_unicast_get_all_parameters( const void *key, UINT key_size, void *rw_data, UINT rw_size,
926 void *dynamic_data, UINT dynamic_size,
927 void *static_data, UINT static_size )
929 int family = (key_size == sizeof(struct nsi_ipv4_unicast_key)) ? AF_INET : AF_INET6;
930 NTSTATUS status = STATUS_NOT_FOUND;
931 const struct nsi_ipv6_unicast_key *key6 = key;
932 const struct nsi_ipv4_unicast_key *key4 = key;
933 struct ifaddrs *addrs, *entry;
934 const char *unix_name;
936 TRACE( "%p %d %p %d %p %d %p %d\n", key, key_size, rw_data, rw_size, dynamic_data, dynamic_size,
937 static_data, static_size );
939 if (!convert_luid_to_unix_name( &key6->luid, &unix_name )) return STATUS_NOT_FOUND;
941 if (getifaddrs( &addrs )) return STATUS_NO_MORE_ENTRIES;
943 for (entry = addrs; entry; entry = entry->ifa_next)
945 if (!entry->ifa_addr || entry->ifa_addr->sa_family != family) continue;
946 if (strcmp( entry->ifa_name, unix_name )) continue;
948 if (family == AF_INET &&
949 memcmp( &key4->addr, &((struct sockaddr_in *)entry->ifa_addr)->sin_addr, sizeof(key4->addr) )) continue;
950 if (family == AF_INET6 &&
951 memcmp( &key6->addr, &((struct sockaddr_in6 *)entry->ifa_addr)->sin6_addr, sizeof(key6->addr) )) continue;
953 unicast_fill_entry( entry, NULL, rw_data, dynamic_data, static_data );
954 status = STATUS_SUCCESS;
955 break;
958 freeifaddrs( addrs );
959 return status;
962 struct ipv4_neighbour_data
964 NET_LUID luid;
965 UINT if_index;
966 struct in_addr addr;
967 BYTE phys_addr[IF_MAX_PHYS_ADDRESS_LENGTH];
968 UINT state;
969 USHORT phys_addr_len;
970 BOOL is_router;
971 BOOL is_unreachable;
974 static void ipv4_neighbour_fill_entry( struct ipv4_neighbour_data *entry, struct nsi_ipv4_neighbour_key *key, struct nsi_ip_neighbour_rw *rw,
975 struct nsi_ip_neighbour_dynamic *dyn, void *stat )
977 USHORT phys_addr_len = entry->phys_addr_len > sizeof(rw->phys_addr) ? 0 : entry->phys_addr_len;
979 if (key)
981 key->luid = entry->luid;
982 key->luid2 = entry->luid;
983 key->addr.WS_s_addr = entry->addr.s_addr;
984 key->pad = 0;
987 if (rw)
989 memcpy( rw->phys_addr, entry->phys_addr, phys_addr_len );
990 memset( rw->phys_addr + entry->phys_addr_len, 0, sizeof(rw->phys_addr) - phys_addr_len );
993 if (dyn)
995 memset( dyn, 0, sizeof(*dyn) );
996 dyn->state = entry->state;
997 dyn->flags.is_router = entry->is_router;
998 dyn->flags.is_unreachable = entry->is_unreachable;
999 dyn->phys_addr_len = phys_addr_len;
1003 /* ARP entries for these multicast addresses are always present on Windows for each interface. */
1004 static DWORD ipv4_multicast_addresses[] =
1006 IPV4_ADDR(224, 0, 0, 22),
1007 IPV4_ADDR(239, 255, 255, 250),
1010 static void update_static_address_found( DWORD address, UINT if_index, struct nsi_ndis_ifinfo_static *iface,
1011 unsigned int iface_count )
1013 unsigned int i, j;
1015 for (i = 0; i < ARRAY_SIZE(ipv4_multicast_addresses); ++i)
1016 if (ipv4_multicast_addresses[i] == address) break;
1018 if (i == ARRAY_SIZE(ipv4_multicast_addresses)) return;
1020 for (j = 0; j < iface_count; ++j)
1022 if (iface[j].if_index == if_index)
1024 iface[j].unk |= 1 << i;
1025 return;
1030 static NTSTATUS ipv4_neighbour_enumerate_all( void *key_data, UINT key_size, void *rw_data, UINT rw_size,
1031 void *dynamic_data, UINT dynamic_size,
1032 void *static_data, UINT static_size, UINT_PTR *count )
1034 UINT num = 0, iface_count;
1035 NTSTATUS status = STATUS_SUCCESS;
1036 BOOL want_data = key_size || rw_size || dynamic_size || static_size;
1037 struct nsi_ndis_ifinfo_static *iface_static;
1038 struct ipv4_neighbour_data entry;
1039 NET_LUID *luid_tbl;
1040 unsigned int i, j;
1042 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
1043 dynamic_data, dynamic_size, static_data, static_size, count );
1045 iface_count = 0;
1046 if ((status = nsi_enumerate_all( 1, 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, NULL, 0, NULL, 0,
1047 NULL, 0, NULL, 0, &iface_count )))
1048 return status;
1050 if (!(luid_tbl = malloc( iface_count * sizeof(*luid_tbl) )))
1051 return STATUS_NO_MEMORY;
1053 if (!(iface_static = malloc( iface_count * sizeof(*iface_static) )))
1055 free( luid_tbl );
1056 return STATUS_NO_MEMORY;
1059 if ((status = nsi_enumerate_all( 1, 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, luid_tbl, sizeof(*luid_tbl),
1060 NULL, 0, NULL, 0, iface_static, sizeof(*iface_static), &iface_count ))
1061 && status != STATUS_BUFFER_OVERFLOW)
1063 free( luid_tbl );
1064 free( iface_static );
1065 return status;
1068 /* Use unk field to indicate whether we found mandatory multicast addresses in the host ARP table. */
1069 for (i = 0; i < iface_count; ++i)
1070 iface_static[i].unk = 0;
1072 #ifdef __linux__
1074 char buf[512], *ptr, *s;
1075 UINT atf_flags;
1076 FILE *fp;
1078 if (!(fp = fopen( "/proc/net/arp", "r" ))) return STATUS_NOT_SUPPORTED;
1080 /* skip header line */
1081 ptr = fgets( buf, sizeof(buf), fp );
1082 while ((ptr = fgets( buf, sizeof(buf), fp )))
1084 entry.addr.s_addr = inet_addr( ptr );
1085 while (*ptr && !isspace( *ptr )) ptr++;
1086 strtoul( ptr + 1, &ptr, 16 ); /* hw type (skip) */
1087 atf_flags = strtoul( ptr + 1, &ptr, 16 );
1089 if (atf_flags & ATF_PERM) entry.state = NlnsPermanent;
1090 else if (atf_flags & ATF_COM) entry.state = NlnsReachable;
1091 else entry.state = NlnsStale;
1093 entry.is_router = 0;
1094 entry.is_unreachable = !(atf_flags & (ATF_PERM | ATF_COM));
1096 while (*ptr && isspace( *ptr )) ptr++;
1097 entry.phys_addr_len = 0;
1098 while (*ptr && !isspace( *ptr ))
1100 if (entry.phys_addr_len >= sizeof(entry.phys_addr))
1102 entry.phys_addr_len = 0;
1103 while (*ptr && !isspace( *ptr )) ptr++;
1104 break;
1106 entry.phys_addr[entry.phys_addr_len++] = strtoul( ptr, &ptr, 16 );
1107 if (*ptr) ptr++;
1109 while (*ptr && isspace( *ptr )) ptr++;
1110 while (*ptr && !isspace( *ptr )) ptr++; /* mask (skip) */
1111 while (*ptr && isspace( *ptr )) ptr++;
1113 s = ptr;
1114 while (*s && !isspace(*s)) s++;
1115 *s = 0;
1116 if (!convert_unix_name_to_luid( ptr, &entry.luid )) continue;
1117 if (!convert_luid_to_index( &entry.luid, &entry.if_index )) continue;
1119 update_static_address_found( entry.addr.s_addr, entry.if_index, iface_static, iface_count );
1121 if (num < *count)
1123 ipv4_neighbour_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
1125 if (key_data) key_data = (BYTE *)key_data + key_size;
1126 if (rw_data) rw_data = (BYTE *)rw_data + rw_size;
1127 if (dynamic_data) dynamic_data = (BYTE *)dynamic_data + dynamic_size;
1128 if (static_data) static_data = (BYTE *)static_data + static_size;
1130 num++;
1132 fclose( fp );
1134 #elif defined(HAVE_SYS_SYSCTL_H)
1136 int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO }, sinarp_len;
1137 size_t needed;
1138 char *buf = NULL, *lim, *next;
1139 struct rt_msghdr *rtm;
1140 struct sockaddr_inarp *sinarp;
1141 struct sockaddr_dl *sdl;
1143 if (sysctl( mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0 ) == -1) return STATUS_NOT_SUPPORTED;
1145 buf = malloc( needed );
1146 if (!buf) return STATUS_NO_MEMORY;
1148 if (sysctl( mib, ARRAY_SIZE(mib), buf, &needed, NULL, 0 ) == -1)
1150 free( buf );
1151 return STATUS_NOT_SUPPORTED;
1154 lim = buf + needed;
1155 next = buf;
1156 while (next < lim)
1158 rtm = (struct rt_msghdr *)next;
1159 sinarp = (struct sockaddr_inarp *)(rtm + 1);
1160 if (sinarp->sin_len) sinarp_len = (sinarp->sin_len + sizeof(int)-1) & ~(sizeof(int)-1);
1161 else sinarp_len = sizeof(int);
1162 sdl = (struct sockaddr_dl *)((char *)sinarp + sinarp_len);
1164 if (sdl->sdl_alen) /* arp entry */
1166 entry.addr = sinarp->sin_addr;
1167 entry.if_index = sdl->sdl_index;
1168 if (!convert_index_to_luid( entry.if_index, &entry.luid )) break;
1169 entry.phys_addr_len = min( 8, sdl->sdl_alen );
1170 if (entry.phys_addr_len > sizeof(entry.phys_addr)) entry.phys_addr_len = 0;
1171 memcpy( entry.phys_addr, &sdl->sdl_data[sdl->sdl_nlen], entry.phys_addr_len );
1172 if (rtm->rtm_rmx.rmx_expire == 0) entry.state = NlnsPermanent;
1173 else entry.state = NlnsReachable;
1174 #ifdef SIN_ROUTER
1175 entry.is_router = sinarp->sin_other & SIN_ROUTER;
1176 #else
1177 entry.is_router = 0;
1178 #endif
1179 entry.is_unreachable = 0; /* FIXME */
1181 update_static_address_found( entry.addr.s_addr, entry.if_index, iface_static, iface_count );
1183 if (num < *count)
1185 ipv4_neighbour_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
1187 if (key_data) key_data = (BYTE *)key_data + key_size;
1188 if (rw_data) rw_data = (BYTE *)rw_data + rw_size;
1189 if (dynamic_data) dynamic_data = (BYTE *)dynamic_data + dynamic_size;
1190 if (static_data) static_data = (BYTE *)static_data + static_size;
1192 num++;
1194 next += rtm->rtm_msglen;
1196 free( buf );
1198 #else
1199 FIXME( "not implemented\n" );
1200 free( luid_tbl );
1201 free( iface_static );
1202 return STATUS_NOT_IMPLEMENTED;
1203 #endif
1205 if (!want_data || num <= *count)
1207 /* Certain ipv4 multicast addresses are always present on Windows for each interface.
1208 * Add those if they weren't added already. */
1209 memset( &entry, 0, sizeof(entry) );
1210 entry.state = NlnsPermanent;
1211 for (i = 0; i < iface_count; ++i)
1213 entry.if_index = iface_static[i].if_index;
1214 entry.luid = luid_tbl[i];
1215 for (j = 0; j < ARRAY_SIZE(ipv4_multicast_addresses); ++j)
1217 if (iface_static[i].unk & (1 << j)) continue;
1218 if (num <= *count)
1220 entry.addr.s_addr = ipv4_multicast_addresses[j];
1221 ipv4_neighbour_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
1223 if (key_data) key_data = (BYTE *)key_data + key_size;
1224 if (rw_data) rw_data = (BYTE *)rw_data + rw_size;
1225 if (dynamic_data) dynamic_data = (BYTE *)dynamic_data + dynamic_size;
1226 if (static_data) static_data = (BYTE *)static_data + static_size;
1228 ++num;
1233 free( luid_tbl );
1234 free( iface_static );
1236 if (!want_data || num <= *count) *count = num;
1237 else status = STATUS_BUFFER_OVERFLOW;
1239 return status;
1242 static NTSTATUS ipv6_neighbour_enumerate_all( void *key_data, UINT key_size, void *rw_data, UINT rw_size,
1243 void *dynamic_data, UINT dynamic_size,
1244 void *static_data, UINT static_size, UINT_PTR *count )
1246 FIXME( "not implemented\n" );
1247 return STATUS_NOT_IMPLEMENTED;
1250 struct ipv4_route_data
1252 NET_LUID luid;
1253 UINT if_index;
1254 struct in_addr prefix;
1255 UINT prefix_len;
1256 struct in_addr next_hop;
1257 UINT metric;
1258 UINT protocol;
1259 BYTE loopback;
1262 static void ipv4_forward_fill_entry( struct ipv4_route_data *entry, struct nsi_ipv4_forward_key *key,
1263 struct nsi_ip_forward_rw *rw, struct nsi_ipv4_forward_dynamic *dyn,
1264 struct nsi_ip_forward_static *stat )
1266 if (key)
1268 key->unk = 0;
1269 key->prefix.WS_s_addr = entry->prefix.s_addr;
1270 key->prefix_len = entry->prefix_len;
1271 memset( key->unk2, 0, sizeof(key->unk2) );
1272 memset( key->unk3, 0, sizeof(key->unk3) );
1273 key->luid = entry->luid;
1274 key->luid2 = entry->luid;
1275 key->next_hop.WS_s_addr = entry->next_hop.s_addr;
1276 key->pad = 0;
1279 if (rw)
1281 rw->site_prefix_len = 0;
1282 rw->valid_lifetime = ~0u;
1283 rw->preferred_lifetime = ~0u;
1284 rw->metric = entry->metric;
1285 rw->protocol = entry->protocol;
1286 rw->loopback = entry->loopback;
1287 rw->autoconf = 1;
1288 rw->publish = 0;
1289 rw->immortal = 1;
1290 memset( rw->unk, 0, sizeof(rw->unk) );
1291 rw->unk2 = 0;
1294 if (dyn)
1296 memset( dyn, 0, sizeof(*dyn) );
1299 if (stat)
1301 stat->origin = NlroManual;
1302 stat->if_index = entry->if_index;
1306 static NTSTATUS ipv4_forward_enumerate_all( void *key_data, UINT key_size, void *rw_data, UINT rw_size,
1307 void *dynamic_data, UINT dynamic_size,
1308 void *static_data, UINT static_size, UINT_PTR *count )
1310 UINT num = 0;
1311 NTSTATUS status = STATUS_SUCCESS;
1312 BOOL want_data = key_size || rw_size || dynamic_size || static_size;
1313 struct ipv4_route_data entry;
1315 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data, key_size, rw_data, rw_size,
1316 dynamic_data, dynamic_size, static_data, static_size, count );
1318 #ifdef __linux__
1320 char buf[512], *ptr;
1321 struct in_addr mask;
1322 UINT rtf_flags;
1323 FILE *fp;
1325 if (!(fp = fopen( "/proc/net/route", "r" ))) return STATUS_NOT_SUPPORTED;
1327 /* skip header line */
1328 fgets( buf, sizeof(buf), fp );
1329 while ((ptr = fgets( buf, sizeof(buf), fp )))
1331 while (!isspace( *ptr )) ptr++;
1332 *ptr++ = '\0';
1334 if (!convert_unix_name_to_luid( buf, &entry.luid )) continue;
1335 if (!convert_luid_to_index( &entry.luid, &entry.if_index )) continue;
1337 entry.prefix.s_addr = strtoul( ptr, &ptr, 16 );
1338 entry.next_hop.s_addr = strtoul( ptr + 1, &ptr, 16 );
1339 rtf_flags = strtoul( ptr + 1, &ptr, 16 );
1340 strtoul( ptr + 1, &ptr, 16 ); /* refcount, skip */
1341 strtoul( ptr + 1, &ptr, 16 ); /* use, skip */
1342 entry.metric = strtoul( ptr + 1, &ptr, 16 );
1343 mask.s_addr = strtoul( ptr + 1, &ptr, 16 );
1344 entry.prefix_len = mask_v4_to_prefix( &mask );
1345 entry.protocol = (rtf_flags & RTF_GATEWAY) ? MIB_IPPROTO_NETMGMT : MIB_IPPROTO_LOCAL;
1346 entry.loopback = entry.protocol == MIB_IPPROTO_LOCAL && entry.prefix_len == 32;
1348 if (num < *count)
1350 ipv4_forward_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
1351 key_data = (BYTE *)key_data + key_size;
1352 rw_data = (BYTE *)rw_data + rw_size;
1353 dynamic_data = (BYTE *)dynamic_data + dynamic_size;
1354 static_data = (BYTE *)static_data + static_size;
1356 num++;
1358 fclose( fp );
1360 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1362 int mib[6] = { CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0 };
1363 size_t needed;
1364 char *buf = NULL, *lim, *next, *addr_ptr;
1365 struct rt_msghdr *rtm;
1367 if (sysctl( mib, ARRAY_SIZE(mib), NULL, &needed, NULL, 0 ) < 0) return STATUS_NOT_SUPPORTED;
1369 buf = malloc( needed );
1370 if (!buf) return STATUS_NO_MEMORY;
1372 if (sysctl( mib, 6, buf, &needed, NULL, 0 ) < 0)
1374 free( buf );
1375 return STATUS_NOT_SUPPORTED;
1378 lim = buf + needed;
1379 for (next = buf; next < lim; next += rtm->rtm_msglen)
1381 int i;
1382 sa_family_t dst_family = AF_UNSPEC;
1384 rtm = (struct rt_msghdr *)next;
1386 if (rtm->rtm_type != RTM_GET)
1388 WARN( "Got unexpected message type 0x%x!\n", rtm->rtm_type );
1389 continue;
1392 /* Ignore gateway routes which are multicast */
1393 if ((rtm->rtm_flags & RTF_GATEWAY) && (rtm->rtm_flags & RTF_MULTICAST)) continue;
1395 entry.if_index = rtm->rtm_index;
1396 if (!convert_index_to_luid( entry.if_index, &entry.luid )) continue;
1397 entry.protocol = (rtm->rtm_flags & RTF_GATEWAY) ? MIB_IPPROTO_NETMGMT : MIB_IPPROTO_LOCAL;
1398 entry.metric = rtm->rtm_rmx.rmx_hopcount;
1400 addr_ptr = (char *)(rtm + 1);
1402 for (i = 1; i; i <<= 1)
1404 struct sockaddr *sa;
1405 struct in_addr addr;
1407 if (!(i & rtm->rtm_addrs)) continue;
1409 sa = (struct sockaddr *)addr_ptr;
1410 if (addr_ptr + sa->sa_len > next + rtm->rtm_msglen)
1412 ERR( "struct sockaddr extends beyond the route message, %p > %p\n",
1413 addr_ptr + sa->sa_len, next + rtm->rtm_msglen );
1416 if (sa->sa_len) addr_ptr += (sa->sa_len + sizeof(int)-1) & ~(sizeof(int)-1);
1417 else addr_ptr += sizeof(int);
1418 /* Apple's netstat prints the netmask together with the destination
1419 * and only looks at the destination's address family. The netmask's
1420 * sa_family sometimes contains the non-existent value 0xff. */
1421 switch (i == RTA_NETMASK ? dst_family : sa->sa_family)
1423 case AF_INET:
1425 /* Netmasks (and possibly other addresses) have only enough size
1426 * to represent the non-zero bits, e.g. a netmask of 255.0.0.0 has
1427 * 5 bytes (1 sa_len, 1 sa_family, 2 sa_port and 1 for the first
1428 * byte of sin_addr). */
1429 struct sockaddr_in sin = {0};
1430 memcpy( &sin, sa, sa->sa_len );
1431 addr = sin.sin_addr;
1432 break;
1434 #ifdef AF_LINK
1435 case AF_LINK:
1436 if (i == RTA_GATEWAY && entry.protocol == MIB_IPPROTO_NETMGMT)
1438 /* For direct route we may simply use dest addr as next hop */
1439 C_ASSERT(RTA_DST < RTA_GATEWAY);
1440 addr = entry.prefix;
1441 break;
1443 /* fallthrough */
1444 #endif
1445 default:
1446 WARN( "Received unsupported sockaddr family 0x%x\n", sa->sa_family );
1447 addr.s_addr = 0;
1449 switch (i)
1451 case RTA_DST:
1452 entry.prefix = addr;
1453 dst_family = sa->sa_family;
1454 break;
1455 case RTA_GATEWAY: entry.next_hop = addr; break;
1456 case RTA_NETMASK: entry.prefix_len = mask_v4_to_prefix( &addr ); break;
1457 default:
1458 WARN( "Unexpected address type 0x%x\n", i );
1462 if (num < *count)
1464 ipv4_forward_fill_entry( &entry, key_data, rw_data, dynamic_data, static_data );
1465 key_data = (BYTE *)key_data + key_size;
1466 rw_data = (BYTE *)rw_data + rw_size;
1467 dynamic_data = (BYTE *)dynamic_data + dynamic_size;
1468 static_data = (BYTE *)static_data + static_size;
1470 num++;
1472 free( buf );
1474 #else
1475 FIXME( "not implemented\n" );
1476 return STATUS_NOT_IMPLEMENTED;
1477 #endif
1479 if (!want_data || num <= *count) *count = num;
1480 else status = STATUS_BUFFER_OVERFLOW;
1482 return status;
1485 static NTSTATUS ipv6_forward_enumerate_all( void *key_data, UINT key_size, void *rw_data, UINT rw_size,
1486 void *dynamic_data, UINT dynamic_size,
1487 void *static_data, UINT static_size, UINT_PTR *count )
1489 FIXME( "not implemented\n" );
1490 *count = 0;
1491 return STATUS_SUCCESS;
1494 static struct module_table ipv4_tables[] =
1497 NSI_IP_COMPARTMENT_TABLE,
1499 sizeof(UINT), sizeof(struct nsi_ip_cmpt_rw),
1500 sizeof(struct nsi_ip_cmpt_dynamic), 0
1502 NULL,
1503 ipv4_cmpt_get_all_parameters,
1506 NSI_IP_ICMPSTATS_TABLE,
1508 0, 0,
1509 sizeof(struct nsi_ip_icmpstats_dynamic), 0
1511 NULL,
1512 ipv4_icmpstats_get_all_parameters,
1515 NSI_IP_IPSTATS_TABLE,
1517 0, 0,
1518 sizeof(struct nsi_ip_ipstats_dynamic), sizeof(struct nsi_ip_ipstats_static)
1520 NULL,
1521 ipv4_ipstats_get_all_parameters,
1524 NSI_IP_UNICAST_TABLE,
1526 sizeof(struct nsi_ipv4_unicast_key), sizeof(struct nsi_ip_unicast_rw),
1527 sizeof(struct nsi_ip_unicast_dynamic), sizeof(struct nsi_ip_unicast_static)
1529 ipv4_unicast_enumerate_all,
1530 ip_unicast_get_all_parameters,
1533 NSI_IP_NEIGHBOUR_TABLE,
1535 sizeof(struct nsi_ipv4_neighbour_key), sizeof(struct nsi_ip_neighbour_rw),
1536 sizeof(struct nsi_ip_neighbour_dynamic), 0
1538 ipv4_neighbour_enumerate_all,
1541 NSI_IP_FORWARD_TABLE,
1543 sizeof(struct nsi_ipv4_forward_key), sizeof(struct nsi_ip_forward_rw),
1544 sizeof(struct nsi_ipv4_forward_dynamic), sizeof(struct nsi_ip_forward_static)
1546 ipv4_forward_enumerate_all,
1553 const struct module ipv4_module =
1555 &NPI_MS_IPV4_MODULEID,
1556 ipv4_tables
1559 static struct module_table ipv6_tables[] =
1562 NSI_IP_COMPARTMENT_TABLE,
1564 sizeof(UINT), sizeof(struct nsi_ip_cmpt_rw),
1565 sizeof(struct nsi_ip_cmpt_dynamic), 0
1567 NULL,
1568 ipv6_cmpt_get_all_parameters,
1571 NSI_IP_ICMPSTATS_TABLE,
1573 0, 0,
1574 sizeof(struct nsi_ip_icmpstats_dynamic), 0
1576 NULL,
1577 ipv6_icmpstats_get_all_parameters,
1580 NSI_IP_IPSTATS_TABLE,
1582 0, 0,
1583 sizeof(struct nsi_ip_ipstats_dynamic), sizeof(struct nsi_ip_ipstats_static)
1585 NULL,
1586 ipv6_ipstats_get_all_parameters,
1589 NSI_IP_UNICAST_TABLE,
1591 sizeof(struct nsi_ipv6_unicast_key), sizeof(struct nsi_ip_unicast_rw),
1592 sizeof(struct nsi_ip_unicast_dynamic), sizeof(struct nsi_ip_unicast_static)
1594 ipv6_unicast_enumerate_all,
1595 ip_unicast_get_all_parameters,
1598 NSI_IP_NEIGHBOUR_TABLE,
1600 sizeof(struct nsi_ipv6_neighbour_key), sizeof(struct nsi_ip_neighbour_rw),
1601 sizeof(struct nsi_ip_neighbour_dynamic), 0
1603 ipv6_neighbour_enumerate_all,
1606 NSI_IP_FORWARD_TABLE,
1608 sizeof(struct nsi_ipv6_forward_key), sizeof(struct nsi_ip_forward_rw),
1609 sizeof(struct nsi_ipv6_forward_dynamic), sizeof(struct nsi_ip_forward_static)
1611 ipv6_forward_enumerate_all,
1618 const struct module ipv6_module =
1620 &NPI_MS_IPV6_MODULEID,
1621 ipv6_tables