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
27 #include <sys/types.h>
28 #include <sys/socket.h>
30 #ifdef HAVE_NET_ROUTE_H
31 #include <net/route.h>
34 #ifdef HAVE_SYS_SYSCTL_H
35 #include <sys/sysctl.h>
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
42 #ifdef HAVE_NETINET_IP_H
43 #include <netinet/ip.h>
46 #ifdef HAVE_NETINET_IN_SYSTM_H
47 #include <netinet/in_systm.h>
50 #ifdef HAVE_NETINET_IP_ICMP_H
51 #include <netinet/ip_icmp.h>
54 #ifdef HAVE_NETINET_IP_VAR_H
55 #include <netinet/ip_var.h>
58 #ifdef HAVE_NETINET6_IP6_VAR_H
59 #include <netinet6/ip6_var.h>
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.
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
;
89 u_quad_t ip6s_badscope
;
90 u_quad_t ip6s_notmember
;
91 u_quad_t ip6s_nxthist
[256];
93 u_quad_t ip6s_m2m
[32];
96 u_quad_t ip6s_exthdrtoolong
;
98 u_quad_t ip6s_toomanyhdr
;
102 #ifdef HAVE_NETINET_ICMP_VAR_H
103 #include <netinet/icmp_var.h>
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
124 #ifdef HAVE_NETINET_IF_ETHER_H
125 #include <netinet/if_ether.h>
128 #ifdef HAVE_NET_IF_ARP_H
129 #include <net/if_arp.h>
132 #ifdef HAVE_NET_IF_DL_H
133 #include <net/if_dl.h>
136 #ifdef HAVE_IFADDRS_H
140 #ifdef HAVE_ARPA_INET_H
141 #include <arpa/inet.h>
144 #include "ntstatus.h"
145 #define WIN32_NO_STATUS
148 #include "winternl.h"
149 #include "winioctl.h"
150 #define USE_WS_PREFIX
151 #include "winsock2.h"
152 #include "ws2ipdef.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
);
169 m
-= m
>> 1 & 0x55555555;
170 m
= (m
& 0x33333333) + (m
>> 2 & 0x33333333);
171 return ((m
+ (m
>> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
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
)
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) );
191 static ULONG64
get_boot_time( void )
193 SYSTEM_TIMEOFDAY_INFORMATION ti
;
195 NtQuerySystemInformation( SystemTimeOfDayInformation
, &ti
, sizeof(ti
), NULL
);
196 return ti
.BootTime
.QuadPart
;
200 static NTSTATUS
read_sysctl_int( const char *file
, int *val
)
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 );
212 return (endptr
== buf
) ? STATUS_NOT_SUPPORTED
: STATUS_SUCCESS
;
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
;
226 memset( &rw
, 0, sizeof(rw
) );
227 memset( &dyn
, 0, sizeof(dyn
) );
229 if (*key
!= 1) return STATUS_NOT_SUPPORTED
;
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";
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
};
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
;
260 FIXME( "forwarding and default ttl not implemented\n" );
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
))
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
;
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
) );
314 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
315 static const char hdr
[] = "Icmp:";
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 ))
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",
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
],
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
;
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
);
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
;
412 FIXME( "not implemented\n" );
413 return STATUS_NOT_IMPLEMENTED
;
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
) );
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
;
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 */
484 /* and strip leading spaces from value */
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
;
495 if (!ascii_strcasecmp( buf
, "Icmp6InErrors" ))
497 if (sscanf( value
, "%d", &res
)) dyn
.in_errors
= res
;
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
;
511 if (!ascii_strcasecmp( buf
, "Icmp6OutMsgs" ))
513 if (sscanf( value
, "%d", &res
)) dyn
.out_msgs
= res
;
517 if (!ascii_strcasecmp( buf
, "Icmp6OutErrors" ))
519 if (sscanf( value
, "%d", &res
)) dyn
.out_errors
= res
;
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
;
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
);
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
;
595 FIXME( "not implemented\n" );
596 return STATUS_NOT_IMPLEMENTED
;
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
) );
614 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
615 static const char hdr
[] = "Ip:";
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
;
630 sscanf( ptr
, "%*u %*u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
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
;
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
;
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
;
701 FIXME( "not implemented\n" );
702 return STATUS_NOT_IMPLEMENTED
;
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
) );
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 */
745 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
746 char buf
[512], *ptr
, *value
;
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 */
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 );
767 *(long long *)ipstatlist
[i
].elem
= strtoull( value
, NULL
, 10 );
768 status
= STATUS_SUCCESS
;
772 if (dynamic_data
) *(struct nsi_ip_ipstats_dynamic
*)dynamic_data
= dyn
;
773 if (static_data
) *(struct nsi_ip_ipstats_static
*)static_data
= stat
;
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
;
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
;
808 FIXME( "not implemented\n" );
809 return STATUS_NOT_IMPLEMENTED
;
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
;
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
) );
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
;
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
;
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;
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
)
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;
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
;
901 freeifaddrs( addrs
);
903 if (!want_data
|| num
<= *count
) *count
= num
;
904 else status
= STATUS_BUFFER_OVERFLOW
;
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
;
958 freeifaddrs( addrs
);
962 struct ipv4_neighbour_data
967 BYTE phys_addr
[IF_MAX_PHYS_ADDRESS_LENGTH
];
969 USHORT phys_addr_len
;
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
;
981 key
->luid
= entry
->luid
;
982 key
->luid2
= entry
->luid
;
983 key
->addr
.WS_s_addr
= entry
->addr
.s_addr
;
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
);
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
)
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
;
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
;
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
);
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
)))
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
) )))
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
)
1064 free( iface_static
);
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;
1074 char buf
[512], *ptr
, *s
;
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
++;
1106 entry
.phys_addr
[entry
.phys_addr_len
++] = strtoul( ptr
, &ptr
, 16 );
1109 while (*ptr
&& isspace( *ptr
)) ptr
++;
1110 while (*ptr
&& !isspace( *ptr
)) ptr
++; /* mask (skip) */
1111 while (*ptr
&& isspace( *ptr
)) ptr
++;
1114 while (*s
&& !isspace(*s
)) s
++;
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
);
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
;
1134 #elif defined(HAVE_SYS_SYSCTL_H)
1136 int mib
[] = { CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
}, sinarp_len
;
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)
1151 return STATUS_NOT_SUPPORTED
;
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
;
1175 entry
.is_router
= sinarp
->sin_other
& SIN_ROUTER
;
1177 entry
.is_router
= 0;
1179 entry
.is_unreachable
= 0; /* FIXME */
1181 update_static_address_found( entry
.addr
.s_addr
, entry
.if_index
, iface_static
, iface_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
;
1194 next
+= rtm
->rtm_msglen
;
1199 FIXME( "not implemented\n" );
1201 free( iface_static
);
1202 return STATUS_NOT_IMPLEMENTED
;
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;
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
;
1234 free( iface_static
);
1236 if (!want_data
|| num
<= *count
) *count
= num
;
1237 else status
= STATUS_BUFFER_OVERFLOW
;
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
1254 struct in_addr prefix
;
1256 struct in_addr next_hop
;
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
)
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
;
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
;
1290 memset( rw
->unk
, 0, sizeof(rw
->unk
) );
1296 memset( dyn
, 0, sizeof(*dyn
) );
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
)
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
);
1320 char buf
[512], *ptr
;
1321 struct in_addr mask
;
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
++;
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;
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
;
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 };
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)
1375 return STATUS_NOT_SUPPORTED
;
1379 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
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
);
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
)
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
;
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
;
1446 WARN( "Received unsupported sockaddr family 0x%x\n", sa
->sa_family
);
1452 entry
.prefix
= addr
;
1453 dst_family
= sa
->sa_family
;
1455 case RTA_GATEWAY
: entry
.next_hop
= addr
; break;
1456 case RTA_NETMASK
: entry
.prefix_len
= mask_v4_to_prefix( &addr
); break;
1458 WARN( "Unexpected address type 0x%x\n", i
);
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
;
1475 FIXME( "not implemented\n" );
1476 return STATUS_NOT_IMPLEMENTED
;
1479 if (!want_data
|| num
<= *count
) *count
= num
;
1480 else status
= STATUS_BUFFER_OVERFLOW
;
1485 struct ipv6_route_data
1489 struct in6_addr prefix
;
1491 struct in6_addr next_hop
;
1497 static void ipv6_forward_fill_entry( struct ipv6_route_data
*entry
, struct nsi_ipv6_forward_key
*key
,
1498 struct nsi_ip_forward_rw
*rw
, struct nsi_ipv6_forward_dynamic
*dyn
,
1499 struct nsi_ip_forward_static
*stat
)
1504 memcpy( key
->prefix
.u
.Byte
, entry
->prefix
.s6_addr
, sizeof(entry
->prefix
.s6_addr
) );
1505 key
->prefix_len
= entry
->prefix_len
;
1506 memset( key
->unk2
, 0, sizeof(key
->unk2
) );
1507 memset( key
->unk3
, 0, sizeof(key
->unk3
) );
1508 key
->luid
= entry
->luid
;
1509 key
->luid2
= entry
->luid
;
1510 memcpy( key
->next_hop
.u
.Byte
, entry
->next_hop
.s6_addr
, sizeof(entry
->next_hop
.s6_addr
) );
1516 rw
->site_prefix_len
= 0;
1517 rw
->valid_lifetime
= ~0u;
1518 rw
->preferred_lifetime
= ~0u;
1519 rw
->metric
= entry
->metric
;
1520 rw
->protocol
= entry
->protocol
;
1521 rw
->loopback
= entry
->loopback
;
1525 memset( rw
->unk
, 0, sizeof(rw
->unk
) );
1531 memset( dyn
, 0, sizeof(*dyn
) );
1536 stat
->origin
= NlroManual
;
1537 stat
->if_index
= entry
->if_index
;
1541 struct in6_addr
str_to_in6_addr(char *nptr
, char **endptr
)
1543 struct in6_addr ret
;
1545 for (int i
= 0; i
< sizeof(ret
); i
++)
1547 if (!isxdigit( *nptr
) || !isxdigit( *(nptr
+ 1) ))
1549 /* invalid hex string */
1550 if (endptr
) *endptr
= nptr
;
1554 sscanf( nptr
, "%2hhx", &ret
.s6_addr
[i
] );
1558 if (endptr
) *endptr
= nptr
;
1563 static NTSTATUS
ipv6_forward_enumerate_all( void *key_data
, UINT key_size
, void *rw_data
, UINT rw_size
,
1564 void *dynamic_data
, UINT dynamic_size
,
1565 void *static_data
, UINT static_size
, UINT_PTR
*count
)
1568 NTSTATUS status
= STATUS_SUCCESS
;
1569 BOOL want_data
= key_size
|| rw_size
|| dynamic_size
|| static_size
;
1570 struct ipv6_route_data entry
;
1572 TRACE( "%p %d %p %d %p %d %p %d %p\n" , key_data
, key_size
, rw_data
, rw_size
,
1573 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
1577 char buf
[512], *ptr
, *end
;
1581 if (!(fp
= fopen( "/proc/net/ipv6_route", "r" ))) return STATUS_NOT_SUPPORTED
;
1583 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
1585 entry
.prefix
= str_to_in6_addr( ptr
, &ptr
);
1586 entry
.prefix_len
= strtoul( ptr
+ 1, &ptr
, 16 );
1587 str_to_in6_addr( ptr
+ 1, &ptr
); /* source network, skip */
1588 strtoul( ptr
+ 1, &ptr
, 16 ); /* source prefix length, skip */
1589 entry
.next_hop
= str_to_in6_addr( ptr
+ 1, &ptr
);
1590 entry
.metric
= strtoul( ptr
+ 1, &ptr
, 16 );
1591 strtoul( ptr
+ 1, &ptr
, 16 ); /* refcount, skip */
1592 strtoul( ptr
+ 1, &ptr
, 16 ); /* use, skip */
1593 rtf_flags
= strtoul( ptr
+ 1, &ptr
, 16);
1594 entry
.protocol
= (rtf_flags
& RTF_GATEWAY
) ? MIB_IPPROTO_NETMGMT
: MIB_IPPROTO_LOCAL
;
1595 entry
.loopback
= entry
.protocol
== MIB_IPPROTO_LOCAL
&& entry
.prefix_len
== 32;
1597 while (isspace( *ptr
)) ptr
++;
1599 while (*end
&& !isspace(*end
)) ++end
;
1601 if (!convert_unix_name_to_luid( ptr
, &entry
.luid
)) continue;
1602 if (!convert_luid_to_index( &entry
.luid
, &entry
.if_index
)) continue;
1606 ipv6_forward_fill_entry( &entry
, key_data
, rw_data
, dynamic_data
, static_data
);
1607 key_data
= (BYTE
*)key_data
+ key_size
;
1608 rw_data
= (BYTE
*)rw_data
+ rw_size
;
1609 dynamic_data
= (BYTE
*)dynamic_data
+ dynamic_size
;
1610 static_data
= (BYTE
*)static_data
+ static_size
;
1617 FIXME( "not implemented\n" );
1619 return STATUS_SUCCESS
;
1622 if (!want_data
|| num
<= *count
) *count
= num
;
1623 else status
= STATUS_BUFFER_OVERFLOW
;
1628 static struct module_table ipv4_tables
[] =
1631 NSI_IP_COMPARTMENT_TABLE
,
1633 sizeof(UINT
), sizeof(struct nsi_ip_cmpt_rw
),
1634 sizeof(struct nsi_ip_cmpt_dynamic
), 0
1637 ipv4_cmpt_get_all_parameters
,
1640 NSI_IP_ICMPSTATS_TABLE
,
1643 sizeof(struct nsi_ip_icmpstats_dynamic
), 0
1646 ipv4_icmpstats_get_all_parameters
,
1649 NSI_IP_IPSTATS_TABLE
,
1652 sizeof(struct nsi_ip_ipstats_dynamic
), sizeof(struct nsi_ip_ipstats_static
)
1655 ipv4_ipstats_get_all_parameters
,
1658 NSI_IP_UNICAST_TABLE
,
1660 sizeof(struct nsi_ipv4_unicast_key
), sizeof(struct nsi_ip_unicast_rw
),
1661 sizeof(struct nsi_ip_unicast_dynamic
), sizeof(struct nsi_ip_unicast_static
)
1663 ipv4_unicast_enumerate_all
,
1664 ip_unicast_get_all_parameters
,
1667 NSI_IP_NEIGHBOUR_TABLE
,
1669 sizeof(struct nsi_ipv4_neighbour_key
), sizeof(struct nsi_ip_neighbour_rw
),
1670 sizeof(struct nsi_ip_neighbour_dynamic
), 0
1672 ipv4_neighbour_enumerate_all
,
1675 NSI_IP_FORWARD_TABLE
,
1677 sizeof(struct nsi_ipv4_forward_key
), sizeof(struct nsi_ip_forward_rw
),
1678 sizeof(struct nsi_ipv4_forward_dynamic
), sizeof(struct nsi_ip_forward_static
)
1680 ipv4_forward_enumerate_all
,
1687 const struct module ipv4_module
=
1689 &NPI_MS_IPV4_MODULEID
,
1693 static struct module_table ipv6_tables
[] =
1696 NSI_IP_COMPARTMENT_TABLE
,
1698 sizeof(UINT
), sizeof(struct nsi_ip_cmpt_rw
),
1699 sizeof(struct nsi_ip_cmpt_dynamic
), 0
1702 ipv6_cmpt_get_all_parameters
,
1705 NSI_IP_ICMPSTATS_TABLE
,
1708 sizeof(struct nsi_ip_icmpstats_dynamic
), 0
1711 ipv6_icmpstats_get_all_parameters
,
1714 NSI_IP_IPSTATS_TABLE
,
1717 sizeof(struct nsi_ip_ipstats_dynamic
), sizeof(struct nsi_ip_ipstats_static
)
1720 ipv6_ipstats_get_all_parameters
,
1723 NSI_IP_UNICAST_TABLE
,
1725 sizeof(struct nsi_ipv6_unicast_key
), sizeof(struct nsi_ip_unicast_rw
),
1726 sizeof(struct nsi_ip_unicast_dynamic
), sizeof(struct nsi_ip_unicast_static
)
1728 ipv6_unicast_enumerate_all
,
1729 ip_unicast_get_all_parameters
,
1732 NSI_IP_NEIGHBOUR_TABLE
,
1734 sizeof(struct nsi_ipv6_neighbour_key
), sizeof(struct nsi_ip_neighbour_rw
),
1735 sizeof(struct nsi_ip_neighbour_dynamic
), 0
1737 ipv6_neighbour_enumerate_all
,
1740 NSI_IP_FORWARD_TABLE
,
1742 sizeof(struct nsi_ipv6_forward_key
), sizeof(struct nsi_ip_forward_rw
),
1743 sizeof(struct nsi_ipv6_forward_dynamic
), sizeof(struct nsi_ip_forward_static
)
1745 ipv6_forward_enumerate_all
,
1752 const struct module ipv6_module
=
1754 &NPI_MS_IPV6_MODULEID
,