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_NETINET_ICMP_VAR_H
59 #include <netinet/icmp_var.h>
62 #ifdef HAVE_NETINET_IF_ETHER_H
63 #include <netinet/if_ether.h>
66 #ifdef HAVE_NET_IF_ARP_H
67 #include <net/if_arp.h>
70 #ifdef HAVE_NET_IF_DL_H
71 #include <net/if_dl.h>
78 #ifdef HAVE_ARPA_INET_H
79 #include <arpa/inet.h>
83 #define WIN32_NO_STATUS
96 #include "wine/debug.h"
98 #include "unix_private.h"
100 WINE_DEFAULT_DEBUG_CHANNEL(nsi
);
102 static inline DWORD
nsi_popcount( DWORD m
)
104 #ifdef HAVE___BUILTIN_POPCOUNT
105 return __builtin_popcount( m
);
107 m
-= m
>> 1 & 0x55555555;
108 m
= (m
& 0x33333333) + (m
>> 2 & 0x33333333);
109 return ((m
+ (m
>> 4)) & 0x0f0f0f0f) * 0x01010101 >> 24;
113 static DWORD
mask_v4_to_prefix( struct in_addr
*addr
)
115 return nsi_popcount( addr
->s_addr
);
118 static DWORD
mask_v6_to_prefix( struct in6_addr
*addr
)
122 ret
= nsi_popcount( *(DWORD
*)addr
->s6_addr
);
123 ret
+= nsi_popcount( *(DWORD
*)(addr
->s6_addr
+ 4) );
124 ret
+= nsi_popcount( *(DWORD
*)(addr
->s6_addr
+ 8) );
125 ret
+= nsi_popcount( *(DWORD
*)(addr
->s6_addr
+ 12) );
129 static ULONG64
get_boot_time( void )
131 SYSTEM_TIMEOFDAY_INFORMATION ti
;
133 NtQuerySystemInformation( SystemTimeOfDayInformation
, &ti
, sizeof(ti
), NULL
);
134 return ti
.BootTime
.QuadPart
;
138 static NTSTATUS
read_sysctl_int( const char *file
, int *val
)
141 char buf
[128], *endptr
= buf
;
143 fp
= fopen( file
, "r" );
144 if (!fp
) return STATUS_NOT_SUPPORTED
;
146 if (fgets( buf
, sizeof(buf
), fp
))
147 *val
= strtol( buf
, &endptr
, 10 );
150 return (endptr
== buf
) ? STATUS_NOT_SUPPORTED
: STATUS_SUCCESS
;
154 static NTSTATUS
ip_cmpt_get_all_parameters( DWORD fam
, const DWORD
*key
, DWORD key_size
,
155 struct nsi_ip_cmpt_rw
*rw_data
, DWORD rw_size
,
156 struct nsi_ip_cmpt_dynamic
*dynamic_data
, DWORD dynamic_size
,
157 void *static_data
, DWORD static_size
)
159 const NPI_MODULEID
*ip_mod
= (fam
== AF_INET
) ? &NPI_MS_IPV4_MODULEID
: &NPI_MS_IPV6_MODULEID
;
160 struct nsi_ip_cmpt_rw rw
;
161 struct nsi_ip_cmpt_dynamic dyn
;
164 memset( &rw
, 0, sizeof(rw
) );
165 memset( &dyn
, 0, sizeof(dyn
) );
167 if (*key
!= 1) return STATUS_NOT_SUPPORTED
;
171 const char *fwd
= (fam
== AF_INET
) ? "/proc/sys/net/ipv4/conf/default/forwarding" :
172 "/proc/sys/net/ipv6/conf/default/forwarding";
173 const char *ttl
= (fam
== AF_INET
) ? "/proc/sys/net/ipv4/ip_default_ttl" :
174 "/proc/sys/net/ipv6/conf/default/hop_limit";
177 if (!read_sysctl_int( fwd
, &value
)) rw
.not_forwarding
= !value
;
178 if (!read_sysctl_int( ttl
, &value
)) rw
.default_ttl
= value
;
180 #elif defined(HAVE_SYS_SYSCTL_H)
182 int fwd_4
[] = { CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_FORWARDING
};
183 int fwd_6
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, IPV6CTL_FORWARDING
};
184 int ttl_4
[] = { CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_DEFTTL
};
185 int ttl_6
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, IPV6CTL_DEFHLIM
};
189 needed
= sizeof(value
);
190 if (!sysctl( (fam
== AF_INET
) ? fwd_4
: fwd_6
, ARRAY_SIZE(fwd_4
), &value
, &needed
, NULL
, 0 ))
191 rw
.not_forwarding
= value
;
193 needed
= sizeof(value
);
194 if (!sysctl( (fam
== AF_INET
) ? ttl_4
: ttl_6
, ARRAY_SIZE(ttl_4
), &value
, &needed
, NULL
, 0 ))
195 rw
.default_ttl
= value
;
198 FIXME( "forwarding and default ttl not implemented\n" );
202 if (!nsi_enumerate_all( 1, 0, &NPI_MS_NDIS_MODULEID
, NSI_NDIS_IFINFO_TABLE
, NULL
, 0, NULL
, 0,
203 NULL
, 0, NULL
, 0, &count
))
207 if (!nsi_enumerate_all( 1, 0, ip_mod
, NSI_IP_FORWARD_TABLE
, NULL
, 0, NULL
, 0,
208 NULL
, 0, NULL
, 0, &count
))
209 dyn
.num_routes
= count
;
212 if (!nsi_enumerate_all( 1, 0, ip_mod
, NSI_IP_UNICAST_TABLE
, NULL
, 0, NULL
, 0,
213 NULL
, 0, NULL
, 0, &count
))
214 dyn
.num_addrs
= count
;
216 if (rw_data
) *rw_data
= rw
;
217 if (dynamic_data
) *dynamic_data
= dyn
;
219 return STATUS_SUCCESS
;
222 static NTSTATUS
ipv4_cmpt_get_all_parameters( const void *key
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
223 void *dynamic_data
, DWORD dynamic_size
, void *static_data
, DWORD static_size
)
225 TRACE( "%p %d %p %d %p %d %p %d\n", key
, key_size
, rw_data
, rw_size
, dynamic_data
, dynamic_size
,
226 static_data
, static_size
);
227 return ip_cmpt_get_all_parameters( AF_INET
, key
, key_size
, rw_data
, rw_size
,
228 dynamic_data
, dynamic_size
, static_data
, static_size
);
231 static NTSTATUS
ipv6_cmpt_get_all_parameters( const void *key
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
232 void *dynamic_data
, DWORD dynamic_size
, void *static_data
, DWORD static_size
)
234 TRACE( "%p %d %p %d %p %d %p %d\n", key
, key_size
, rw_data
, rw_size
, dynamic_data
, dynamic_size
,
235 static_data
, static_size
);
236 return ip_cmpt_get_all_parameters( AF_INET6
, key
, key_size
, rw_data
, rw_size
,
237 dynamic_data
, dynamic_size
, static_data
, static_size
);
240 static NTSTATUS
ipv4_icmpstats_get_all_parameters( const void *key
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
241 void *dynamic_data
, DWORD dynamic_size
, void *static_data
, DWORD static_size
)
243 struct nsi_ip_icmpstats_dynamic dyn
;
245 TRACE( "%p %d %p %d %p %d %p %d\n", key
, key_size
, rw_data
, rw_size
, dynamic_data
, dynamic_size
,
246 static_data
, static_size
);
248 memset( &dyn
, 0, sizeof(dyn
) );
252 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
253 static const char hdr
[] = "Icmp:";
257 if (!(fp
= fopen( "/proc/net/snmp", "r" ))) return STATUS_NOT_SUPPORTED
;
259 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
261 if (ascii_strncasecmp( buf
, hdr
, sizeof(hdr
) - 1 )) continue;
262 /* last line was a header, get another */
263 if (!(ptr
= fgets( buf
, sizeof(buf
), fp
))) break;
264 if (!ascii_strncasecmp( buf
, hdr
, sizeof(hdr
) - 1 ))
267 sscanf( ptr
, "%u %u %*u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
270 &dyn
.in_type_counts
[ICMP4_DST_UNREACH
],
271 &dyn
.in_type_counts
[ICMP4_TIME_EXCEEDED
],
272 &dyn
.in_type_counts
[ICMP4_PARAM_PROB
],
273 &dyn
.in_type_counts
[ICMP4_SOURCE_QUENCH
],
274 &dyn
.in_type_counts
[ICMP4_REDIRECT
],
275 &dyn
.in_type_counts
[ICMP4_ECHO_REQUEST
],
276 &dyn
.in_type_counts
[ICMP4_ECHO_REPLY
],
277 &dyn
.in_type_counts
[ICMP4_TIMESTAMP_REQUEST
],
278 &dyn
.in_type_counts
[ICMP4_TIMESTAMP_REPLY
],
279 &dyn
.in_type_counts
[ICMP4_MASK_REQUEST
],
280 &dyn
.in_type_counts
[ICMP4_MASK_REPLY
],
283 &dyn
.out_type_counts
[ICMP4_DST_UNREACH
],
284 &dyn
.out_type_counts
[ICMP4_TIME_EXCEEDED
],
285 &dyn
.out_type_counts
[ICMP4_PARAM_PROB
],
286 &dyn
.out_type_counts
[ICMP4_SOURCE_QUENCH
],
287 &dyn
.out_type_counts
[ICMP4_REDIRECT
],
288 &dyn
.out_type_counts
[ICMP4_ECHO_REQUEST
],
289 &dyn
.out_type_counts
[ICMP4_ECHO_REPLY
],
290 &dyn
.out_type_counts
[ICMP4_TIMESTAMP_REQUEST
],
291 &dyn
.out_type_counts
[ICMP4_TIMESTAMP_REPLY
],
292 &dyn
.out_type_counts
[ICMP4_MASK_REQUEST
],
293 &dyn
.out_type_counts
[ICMP4_MASK_REPLY
] );
294 status
= STATUS_SUCCESS
;
295 if (dynamic_data
) *(struct nsi_ip_icmpstats_dynamic
*)dynamic_data
= dyn
;
302 #elif defined(HAVE_SYS_SYSCTL_H) && defined(ICMPCTL_STATS)
304 int mib
[] = { CTL_NET
, PF_INET
, IPPROTO_ICMP
, ICMPCTL_STATS
};
305 struct icmpstat icmp_stat
;
306 size_t needed
= sizeof(icmp_stat
);
309 if (sysctl( mib
, ARRAY_SIZE(mib
), &icmp_stat
, &needed
, NULL
, 0 ) == -1) return STATUS_NOT_SUPPORTED
;
311 dyn
.in_msgs
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_badlen
;
312 for (i
= 0; i
<= ICMP_MAXTYPE
; i
++)
313 dyn
.in_msgs
+= icmp_stat
.icps_inhist
[i
];
315 dyn
.in_errors
= icmp_stat
.icps_badcode
+ icmp_stat
.icps_tooshort
+ icmp_stat
.icps_checksum
+ icmp_stat
.icps_badlen
;
317 dyn
.in_type_counts
[ICMP4_DST_UNREACH
] = icmp_stat
.icps_inhist
[ICMP_UNREACH
];
318 dyn
.in_type_counts
[ICMP4_TIME_EXCEEDED
] = icmp_stat
.icps_inhist
[ICMP_TIMXCEED
];
319 dyn
.in_type_counts
[ICMP4_PARAM_PROB
] = icmp_stat
.icps_inhist
[ICMP_PARAMPROB
];
320 dyn
.in_type_counts
[ICMP4_SOURCE_QUENCH
] = icmp_stat
.icps_inhist
[ICMP_SOURCEQUENCH
];
321 dyn
.in_type_counts
[ICMP4_REDIRECT
] = icmp_stat
.icps_inhist
[ICMP_REDIRECT
];
322 dyn
.in_type_counts
[ICMP4_ECHO_REQUEST
] = icmp_stat
.icps_inhist
[ICMP_ECHO
];
323 dyn
.in_type_counts
[ICMP4_ECHO_REPLY
] = icmp_stat
.icps_inhist
[ICMP_ECHOREPLY
];
324 dyn
.in_type_counts
[ICMP4_TIMESTAMP_REQUEST
] = icmp_stat
.icps_inhist
[ICMP_TSTAMP
];
325 dyn
.in_type_counts
[ICMP4_TIMESTAMP_REPLY
] = icmp_stat
.icps_inhist
[ICMP_TSTAMPREPLY
];
326 dyn
.in_type_counts
[ICMP4_MASK_REQUEST
] = icmp_stat
.icps_inhist
[ICMP_MASKREQ
];
327 dyn
.in_type_counts
[ICMP4_MASK_REPLY
] = icmp_stat
.icps_inhist
[ICMP_MASKREPLY
];
329 dyn
.out_msgs
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
330 for (i
= 0; i
<= ICMP_MAXTYPE
; i
++)
331 dyn
.out_msgs
+= icmp_stat
.icps_outhist
[i
];
333 dyn
.out_errors
= icmp_stat
.icps_oldshort
+ icmp_stat
.icps_oldicmp
;
335 dyn
.out_type_counts
[ICMP4_DST_UNREACH
] = icmp_stat
.icps_outhist
[ICMP_UNREACH
];
336 dyn
.out_type_counts
[ICMP4_TIME_EXCEEDED
] = icmp_stat
.icps_outhist
[ICMP_TIMXCEED
];
337 dyn
.out_type_counts
[ICMP4_PARAM_PROB
] = icmp_stat
.icps_outhist
[ICMP_PARAMPROB
];
338 dyn
.out_type_counts
[ICMP4_SOURCE_QUENCH
] = icmp_stat
.icps_outhist
[ICMP_SOURCEQUENCH
];
339 dyn
.out_type_counts
[ICMP4_REDIRECT
] = icmp_stat
.icps_outhist
[ICMP_REDIRECT
];
340 dyn
.out_type_counts
[ICMP4_ECHO_REQUEST
] = icmp_stat
.icps_outhist
[ICMP_ECHO
];
341 dyn
.out_type_counts
[ICMP4_ECHO_REPLY
] = icmp_stat
.icps_outhist
[ICMP_ECHOREPLY
];
342 dyn
.out_type_counts
[ICMP4_TIMESTAMP_REQUEST
] = icmp_stat
.icps_outhist
[ICMP_TSTAMP
];
343 dyn
.out_type_counts
[ICMP4_TIMESTAMP_REPLY
] = icmp_stat
.icps_outhist
[ICMP_TSTAMPREPLY
];
344 dyn
.out_type_counts
[ICMP4_MASK_REQUEST
] = icmp_stat
.icps_outhist
[ICMP_MASKREQ
];
345 dyn
.out_type_counts
[ICMP4_MASK_REPLY
] = icmp_stat
.icps_outhist
[ICMP_MASKREPLY
];
346 if (dynamic_data
) *(struct nsi_ip_icmpstats_dynamic
*)dynamic_data
= dyn
;
347 return STATUS_SUCCESS
;
350 FIXME( "not implemented\n" );
351 return STATUS_NOT_IMPLEMENTED
;
355 static NTSTATUS
ipv6_icmpstats_get_all_parameters( const void *key
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
356 void *dynamic_data
, DWORD dynamic_size
, void *static_data
, DWORD static_size
)
358 struct nsi_ip_icmpstats_dynamic dyn
;
360 TRACE( "%p %d %p %d %p %d %p %d\n", key
, key_size
, rw_data
, rw_size
, dynamic_data
, dynamic_size
,
361 static_data
, static_size
);
363 memset( &dyn
, 0, sizeof(dyn
) );
372 static const struct data in_list
[] =
374 { "Icmp6InDestUnreachs", ICMP6_DST_UNREACH
},
375 { "Icmp6InPktTooBigs", ICMP6_PACKET_TOO_BIG
},
376 { "Icmp6InTimeExcds", ICMP6_TIME_EXCEEDED
},
377 { "Icmp6InParmProblems", ICMP6_PARAM_PROB
},
378 { "Icmp6InEchos", ICMP6_ECHO_REQUEST
},
379 { "Icmp6InEchoReplies", ICMP6_ECHO_REPLY
},
380 { "Icmp6InGroupMembQueries", ICMP6_MEMBERSHIP_QUERY
},
381 { "Icmp6InGroupMembResponses", ICMP6_MEMBERSHIP_REPORT
},
382 { "Icmp6InGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION
},
383 { "Icmp6InRouterSolicits", ND_ROUTER_SOLICIT
},
384 { "Icmp6InRouterAdvertisements", ND_ROUTER_ADVERT
},
385 { "Icmp6InNeighborSolicits", ND_NEIGHBOR_SOLICIT
},
386 { "Icmp6InNeighborAdvertisements", ND_NEIGHBOR_ADVERT
},
387 { "Icmp6InRedirects", ND_REDIRECT
},
388 { "Icmp6InMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT
},
390 static const struct data out_list
[] =
392 { "Icmp6OutDestUnreachs", ICMP6_DST_UNREACH
},
393 { "Icmp6OutPktTooBigs", ICMP6_PACKET_TOO_BIG
},
394 { "Icmp6OutTimeExcds", ICMP6_TIME_EXCEEDED
},
395 { "Icmp6OutParmProblems", ICMP6_PARAM_PROB
},
396 { "Icmp6OutEchos", ICMP6_ECHO_REQUEST
},
397 { "Icmp6OutEchoReplies", ICMP6_ECHO_REPLY
},
398 { "Icmp6OutGroupMembQueries", ICMP6_MEMBERSHIP_QUERY
},
399 { "Icmp6OutGroupMembResponses", ICMP6_MEMBERSHIP_REPORT
},
400 { "Icmp6OutGroupMembReductions", ICMP6_MEMBERSHIP_REDUCTION
},
401 { "Icmp6OutRouterSolicits", ND_ROUTER_SOLICIT
},
402 { "Icmp6OutRouterAdvertisements", ND_ROUTER_ADVERT
},
403 { "Icmp6OutNeighborSolicits", ND_NEIGHBOR_SOLICIT
},
404 { "Icmp6OutNeighborAdvertisements", ND_NEIGHBOR_ADVERT
},
405 { "Icmp6OutRedirects", ND_REDIRECT
},
406 { "Icmp6OutMLDv2Reports", ICMP6_V2_MEMBERSHIP_REPORT
},
408 char buf
[512], *ptr
, *value
;
412 if (!(fp
= fopen( "/proc/net/snmp6", "r" ))) return STATUS_NOT_SUPPORTED
;
414 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
416 if (!(value
= strchr( buf
, ' ' ))) continue;
418 /* terminate the valuename */
422 /* and strip leading spaces from value */
424 while (*value
== ' ') value
++;
425 if ((ptr
= strchr( value
, '\n' ))) *ptr
='\0';
427 if (!ascii_strcasecmp( buf
, "Icmp6InMsgs" ))
429 if (sscanf( value
, "%d", &res
)) dyn
.in_msgs
= res
;
433 if (!ascii_strcasecmp( buf
, "Icmp6InErrors" ))
435 if (sscanf( value
, "%d", &res
)) dyn
.in_errors
= res
;
439 for (i
= 0; i
< ARRAY_SIZE(in_list
); i
++)
441 if (!ascii_strcasecmp( buf
, in_list
[i
].name
))
443 if (sscanf( value
, "%d", &res
))
444 dyn
.in_type_counts
[in_list
[i
].pos
] = res
;
449 if (!ascii_strcasecmp( buf
, "Icmp6OutMsgs" ))
451 if (sscanf( value
, "%d", &res
)) dyn
.out_msgs
= res
;
455 if (!ascii_strcasecmp( buf
, "Icmp6OutErrors" ))
457 if (sscanf( value
, "%d", &res
)) dyn
.out_errors
= res
;
461 for (i
= 0; i
< ARRAY_SIZE(out_list
); i
++)
463 if (!ascii_strcasecmp( buf
, out_list
[i
].name
))
465 if (sscanf( value
, "%d", &res
))
466 dyn
.out_type_counts
[out_list
[i
].pos
] = res
;
472 if (dynamic_data
) *(struct nsi_ip_icmpstats_dynamic
*)dynamic_data
= dyn
;
473 return STATUS_SUCCESS
;
476 FIXME( "not implemented\n" );
477 return STATUS_NOT_IMPLEMENTED
;
481 static NTSTATUS
ipv4_ipstats_get_all_parameters( const void *key
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
482 void *dynamic_data
, DWORD dynamic_size
, void *static_data
, DWORD static_size
)
484 struct nsi_ip_ipstats_dynamic dyn
;
485 struct nsi_ip_ipstats_static stat
;
487 TRACE( "%p %d %p %d %p %d %p %d\n", key
, key_size
, rw_data
, rw_size
, dynamic_data
, dynamic_size
,
488 static_data
, static_size
);
490 memset( &dyn
, 0, sizeof(dyn
) );
491 memset( &stat
, 0, sizeof(stat
) );
495 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
496 static const char hdr
[] = "Ip:";
500 if (!(fp
= fopen( "/proc/net/snmp", "r" ))) return STATUS_NOT_SUPPORTED
;
502 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
504 if (ascii_strncasecmp( buf
, hdr
, sizeof(hdr
) - 1 )) continue;
505 /* last line was a header, get another */
506 if (!(ptr
= fgets( buf
, sizeof(buf
), fp
))) break;
507 if (!ascii_strncasecmp( buf
, hdr
, sizeof(hdr
) - 1 ))
509 DWORD in_recv
, in_hdr_errs
, fwd_dgrams
, in_delivers
, out_reqs
;
511 sscanf( ptr
, "%*u %*u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
529 /* no routingDiscards */
530 dyn
.in_recv
= in_recv
;
531 dyn
.in_hdr_errs
= in_hdr_errs
;
532 dyn
.fwd_dgrams
= fwd_dgrams
;
533 dyn
.in_delivers
= in_delivers
;
534 dyn
.out_reqs
= out_reqs
;
535 if (dynamic_data
) *(struct nsi_ip_ipstats_dynamic
*)dynamic_data
= dyn
;
536 if (static_data
) *(struct nsi_ip_ipstats_static
*)static_data
= stat
;
537 status
= STATUS_SUCCESS
;
544 #elif defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) && (defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL) || defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL))
546 int mib
[] = { CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_STATS
};
547 #if defined(HAVE_STRUCT_IPSTAT_IPS_TOTAL)
548 struct ipstat ip_stat
;
549 #elif defined(HAVE_STRUCT_IP_STATS_IPS_TOTAL)
550 struct ip_stats ip_stat
;
554 needed
= sizeof(ip_stat
);
555 if (sysctl( mib
, ARRAY_SIZE(mib
), &ip_stat
, &needed
, NULL
, 0 ) == -1) return STATUS_NOT_SUPPORTED
;
557 dyn
.in_recv
= ip_stat
.ips_total
;
558 dyn
.in_hdr_errs
= ip_stat
.ips_badhlen
+ ip_stat
.ips_badsum
+ ip_stat
.ips_tooshort
+ ip_stat
.ips_badlen
+
559 ip_stat
.ips_badvers
+ ip_stat
.ips_badoptions
;
560 /* ips_badaddr also includes outgoing packets with a bad address, but we can't account for that right now */
561 dyn
.in_addr_errs
= ip_stat
.ips_cantforward
+ ip_stat
.ips_badaddr
+ ip_stat
.ips_notmember
;
562 dyn
.fwd_dgrams
= ip_stat
.ips_forward
;
563 dyn
.in_unk_protos
= ip_stat
.ips_noproto
;
564 dyn
.in_discards
= ip_stat
.ips_fragdropped
;
565 dyn
.in_delivers
= ip_stat
.ips_delivered
;
566 dyn
.out_reqs
= ip_stat
.ips_localout
;
567 dyn
.out_discards
= ip_stat
.ips_odropped
;
568 dyn
.out_no_routes
= ip_stat
.ips_noroute
;
569 stat
.reasm_timeout
= ip_stat
.ips_fragtimeout
;
570 dyn
.reasm_reqds
= ip_stat
.ips_fragments
;
571 dyn
.reasm_oks
= ip_stat
.ips_reassembled
;
572 dyn
.reasm_fails
= ip_stat
.ips_fragments
- ip_stat
.ips_reassembled
;
573 dyn
.frag_oks
= ip_stat
.ips_fragmented
;
574 dyn
.frag_fails
= ip_stat
.ips_cantfrag
;
575 dyn
.frag_creates
= ip_stat
.ips_ofragments
;
577 if (dynamic_data
) *(struct nsi_ip_ipstats_dynamic
*)dynamic_data
= dyn
;
578 if (static_data
) *(struct nsi_ip_ipstats_static
*)static_data
= stat
;
579 return STATUS_SUCCESS
;
582 FIXME( "not implemented\n" );
583 return STATUS_NOT_IMPLEMENTED
;
587 static NTSTATUS
ipv6_ipstats_get_all_parameters( const void *key
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
588 void *dynamic_data
, DWORD dynamic_size
, void *static_data
, DWORD static_size
)
590 struct nsi_ip_ipstats_dynamic dyn
;
591 struct nsi_ip_ipstats_static stat
;
593 memset( &dyn
, 0, sizeof(dyn
) );
594 memset( &stat
, 0, sizeof(stat
) );
605 #define X(x) &x, sizeof(x)
606 { "Ip6InReceives", X( dyn
.in_recv
) },
607 { "Ip6InHdrErrors", X( dyn
.in_hdr_errs
) },
608 { "Ip6InAddrErrors", X( dyn
.in_addr_errs
) },
609 { "Ip6OutForwDatagrams", X( dyn
.fwd_dgrams
) },
610 { "Ip6InUnknownProtos", X( dyn
.in_unk_protos
) },
611 { "Ip6InDiscards", X( dyn
.in_discards
) },
612 { "Ip6InDelivers", X( dyn
.in_delivers
) },
613 { "Ip6OutRequests", X( dyn
.out_reqs
) },
614 { "Ip6OutDiscards", X( dyn
.out_discards
) },
615 { "Ip6OutNoRoutes", X( dyn
.out_no_routes
) },
616 { "Ip6ReasmTimeout", X( stat
.reasm_timeout
) },
617 { "Ip6ReasmReqds", X( dyn
.reasm_reqds
) },
618 { "Ip6ReasmOKs", X( dyn
.reasm_oks
) },
619 { "Ip6ReasmFails", X( dyn
.reasm_fails
) },
620 { "Ip6FragOKs", X( dyn
.frag_oks
) },
621 { "Ip6FragFails", X( dyn
.frag_fails
) },
622 { "Ip6FragCreates", X( dyn
.frag_creates
) },
623 /* no routingDiscards */
626 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
627 char buf
[512], *ptr
, *value
;
631 if (!(fp
= fopen( "/proc/net/snmp6", "r" ))) return STATUS_NOT_SUPPORTED
;
633 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
635 if (!(value
= strchr( buf
, ' ' ))) continue;
636 /* terminate the valuename */
638 /* and strip leading spaces from value */
639 while (*value
== ' ') value
++;
640 if ((ptr
= strchr( value
, '\n' ))) *ptr
= '\0';
642 for (i
= 0; i
< ARRAY_SIZE(ipstatlist
); i
++)
643 if (!ascii_strcasecmp( buf
, ipstatlist
[i
].name
))
645 if (ipstatlist
[i
].size
== sizeof(long))
646 *(long *)ipstatlist
[i
].elem
= strtoul( value
, NULL
, 10 );
648 *(long long *)ipstatlist
[i
].elem
= strtoull( value
, NULL
, 10 );
649 status
= STATUS_SUCCESS
;
653 if (dynamic_data
) *(struct nsi_ip_ipstats_dynamic
*)dynamic_data
= dyn
;
654 if (static_data
) *(struct nsi_ip_ipstats_static
*)static_data
= stat
;
658 FIXME( "not implemented\n" );
659 return STATUS_NOT_IMPLEMENTED
;
663 static void unicast_fill_entry( struct ifaddrs
*entry
, void *key
, struct nsi_ip_unicast_rw
*rw
,
664 struct nsi_ip_unicast_dynamic
*dyn
, struct nsi_ip_unicast_static
*stat
)
666 struct nsi_ipv6_unicast_key placeholder
, *key6
= key
;
667 struct nsi_ipv4_unicast_key
*key4
= key
;
673 key4
= (struct nsi_ipv4_unicast_key
*)&placeholder
;
676 convert_unix_name_to_luid( entry
->ifa_name
, &key6
->luid
);
678 if (entry
->ifa_addr
->sa_family
== AF_INET
)
680 memcpy( &key4
->addr
, &((struct sockaddr_in
*)entry
->ifa_addr
)->sin_addr
, sizeof(key4
->addr
) );
683 else if (entry
->ifa_addr
->sa_family
== AF_INET6
)
685 memcpy( &key6
->addr
, &((struct sockaddr_in6
*)entry
->ifa_addr
)->sin6_addr
, sizeof(key6
->addr
) );
686 scope_id
= ((struct sockaddr_in6
*)entry
->ifa_addr
)->sin6_scope_id
;
691 rw
->preferred_lifetime
= 60000;
692 rw
->valid_lifetime
= 60000;
694 if (key6
->luid
.Info
.IfType
!= IF_TYPE_SOFTWARE_LOOPBACK
)
696 rw
->prefix_origin
= IpPrefixOriginDhcp
;
697 rw
->suffix_origin
= IpSuffixOriginDhcp
;
701 rw
->prefix_origin
= IpPrefixOriginManual
;
702 rw
->suffix_origin
= IpSuffixOriginManual
;
704 if (entry
->ifa_netmask
&& entry
->ifa_netmask
->sa_family
== AF_INET
)
705 rw
->on_link_prefix
= mask_v4_to_prefix( &((struct sockaddr_in
*)entry
->ifa_netmask
)->sin_addr
);
706 else if (entry
->ifa_netmask
&& entry
->ifa_netmask
->sa_family
== AF_INET6
)
707 rw
->on_link_prefix
= mask_v6_to_prefix( &((struct sockaddr_in6
*)entry
->ifa_netmask
)->sin6_addr
);
708 else rw
->on_link_prefix
= 0;
715 dyn
->scope_id
= scope_id
;
716 dyn
->dad_state
= IpDadStatePreferred
;
719 if (stat
) stat
->creation_time
= get_boot_time();
722 static NTSTATUS
ip_unicast_enumerate_all( int family
, void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
723 void *dynamic_data
, DWORD dynamic_size
,
724 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
727 NTSTATUS status
= STATUS_SUCCESS
;
728 BOOL want_data
= key_size
|| rw_size
|| dynamic_size
|| static_size
;
729 struct ifaddrs
*addrs
, *entry
;
731 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data
, key_size
, rw_data
, rw_size
,
732 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
734 if (getifaddrs( &addrs
)) return STATUS_NO_MORE_ENTRIES
;
736 for (entry
= addrs
; entry
; entry
= entry
->ifa_next
)
738 if (!entry
->ifa_addr
|| entry
->ifa_addr
->sa_family
!= family
) continue;
742 unicast_fill_entry( entry
, key_data
, rw_data
, dynamic_data
, static_data
);
743 key_data
= (BYTE
*)key_data
+ key_size
;
744 rw_data
= (BYTE
*)rw_data
+ rw_size
;
745 dynamic_data
= (BYTE
*)dynamic_data
+ dynamic_size
;
746 static_data
= (BYTE
*)static_data
+ static_size
;
751 freeifaddrs( addrs
);
753 if (!want_data
|| num
<= *count
) *count
= num
;
754 else status
= STATUS_BUFFER_OVERFLOW
;
759 static NTSTATUS
ipv4_unicast_enumerate_all( void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
760 void *dynamic_data
, DWORD dynamic_size
,
761 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
763 return ip_unicast_enumerate_all( AF_INET
, key_data
, key_size
, rw_data
, rw_size
,
764 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
767 static NTSTATUS
ipv6_unicast_enumerate_all( void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
768 void *dynamic_data
, DWORD dynamic_size
,
769 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
771 return ip_unicast_enumerate_all( AF_INET6
, key_data
, key_size
, rw_data
, rw_size
,
772 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
775 static NTSTATUS
ip_unicast_get_all_parameters( const void *key
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
776 void *dynamic_data
, DWORD dynamic_size
,
777 void *static_data
, DWORD static_size
)
779 int family
= (key_size
== sizeof(struct nsi_ipv4_unicast_key
)) ? AF_INET
: AF_INET6
;
780 NTSTATUS status
= STATUS_NOT_FOUND
;
781 const struct nsi_ipv6_unicast_key
*key6
= key
;
782 const struct nsi_ipv4_unicast_key
*key4
= key
;
783 struct ifaddrs
*addrs
, *entry
;
784 const char *unix_name
;
786 TRACE( "%p %d %p %d %p %d %p %d\n", key
, key_size
, rw_data
, rw_size
, dynamic_data
, dynamic_size
,
787 static_data
, static_size
);
789 if (!convert_luid_to_unix_name( &key6
->luid
, &unix_name
)) return STATUS_NOT_FOUND
;
791 if (getifaddrs( &addrs
)) return STATUS_NO_MORE_ENTRIES
;
793 for (entry
= addrs
; entry
; entry
= entry
->ifa_next
)
795 if (!entry
->ifa_addr
|| entry
->ifa_addr
->sa_family
!= family
) continue;
796 if (strcmp( entry
->ifa_name
, unix_name
)) continue;
798 if (family
== AF_INET
&&
799 memcmp( &key4
->addr
, &((struct sockaddr_in
*)entry
->ifa_addr
)->sin_addr
, sizeof(key4
->addr
) )) continue;
800 if (family
== AF_INET6
&&
801 memcmp( &key6
->addr
, &((struct sockaddr_in6
*)entry
->ifa_addr
)->sin6_addr
, sizeof(key6
->addr
) )) continue;
803 unicast_fill_entry( entry
, NULL
, rw_data
, dynamic_data
, static_data
);
804 status
= STATUS_SUCCESS
;
808 freeifaddrs( addrs
);
812 struct ipv4_neighbour_data
817 BYTE phys_addr
[IF_MAX_PHYS_ADDRESS_LENGTH
];
819 USHORT phys_addr_len
;
824 static void ipv4_neighbour_fill_entry( struct ipv4_neighbour_data
*entry
, struct nsi_ipv4_neighbour_key
*key
, struct nsi_ip_neighbour_rw
*rw
,
825 struct nsi_ip_neighbour_dynamic
*dyn
, void *stat
)
827 USHORT phys_addr_len
= entry
->phys_addr_len
> sizeof(rw
->phys_addr
) ? 0 : entry
->phys_addr_len
;
831 key
->luid
= entry
->luid
;
832 key
->luid2
= entry
->luid
;
833 key
->addr
.WS_s_addr
= entry
->addr
.s_addr
;
839 memcpy( rw
->phys_addr
, entry
->phys_addr
, phys_addr_len
);
840 memset( rw
->phys_addr
+ entry
->phys_addr_len
, 0, sizeof(rw
->phys_addr
) - phys_addr_len
);
845 memset( dyn
, 0, sizeof(*dyn
) );
846 dyn
->state
= entry
->state
;
847 dyn
->flags
.is_router
= entry
->is_router
;
848 dyn
->flags
.is_unreachable
= entry
->is_unreachable
;
849 dyn
->phys_addr_len
= phys_addr_len
;
853 static NTSTATUS
ipv4_neighbour_enumerate_all( void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
854 void *dynamic_data
, DWORD dynamic_size
,
855 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
858 NTSTATUS status
= STATUS_SUCCESS
;
859 BOOL want_data
= key_size
|| rw_size
|| dynamic_size
|| static_size
;
860 struct ipv4_neighbour_data entry
;
862 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data
, key_size
, rw_data
, rw_size
,
863 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
871 if (!(fp
= fopen( "/proc/net/arp", "r" ))) return STATUS_NOT_SUPPORTED
;
873 /* skip header line */
874 ptr
= fgets( buf
, sizeof(buf
), fp
);
875 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
877 entry
.addr
.s_addr
= inet_addr( ptr
);
878 while (*ptr
&& !isspace( *ptr
)) ptr
++;
879 strtoul( ptr
+ 1, &ptr
, 16 ); /* hw type (skip) */
880 atf_flags
= strtoul( ptr
+ 1, &ptr
, 16 );
882 if (atf_flags
& ATF_PERM
) entry
.state
= NlnsPermanent
;
883 else if (atf_flags
& ATF_COM
) entry
.state
= NlnsReachable
;
884 else entry
.state
= NlnsStale
;
887 entry
.is_unreachable
= !(atf_flags
& (ATF_PERM
| ATF_COM
));
889 while (*ptr
&& isspace( *ptr
)) ptr
++;
890 entry
.phys_addr_len
= 0;
891 while (*ptr
&& !isspace( *ptr
))
893 if (entry
.phys_addr_len
>= sizeof(entry
.phys_addr
))
895 entry
.phys_addr_len
= 0;
896 while (*ptr
&& !isspace( *ptr
)) ptr
++;
899 entry
.phys_addr
[entry
.phys_addr_len
++] = strtoul( ptr
, &ptr
, 16 );
902 while (*ptr
&& isspace( *ptr
)) ptr
++;
903 while (*ptr
&& !isspace( *ptr
)) ptr
++; /* mask (skip) */
904 while (*ptr
&& isspace( *ptr
)) ptr
++;
906 if (!convert_unix_name_to_luid( ptr
, &entry
.luid
)) continue;
907 if (!convert_luid_to_index( &entry
.luid
, &entry
.if_index
)) continue;
911 ipv4_neighbour_fill_entry( &entry
, key_data
, rw_data
, dynamic_data
, static_data
);
913 if (key_data
) key_data
= (BYTE
*)key_data
+ key_size
;
914 if (rw_data
) rw_data
= (BYTE
*)rw_data
+ rw_size
;
915 if (dynamic_data
) dynamic_data
= (BYTE
*)dynamic_data
+ dynamic_size
;
916 if (static_data
) static_data
= (BYTE
*)static_data
+ static_size
;
922 #elif defined(HAVE_SYS_SYSCTL_H)
924 int mib
[] = { CTL_NET
, PF_ROUTE
, 0, AF_INET
, NET_RT_FLAGS
, RTF_LLINFO
}, sinarp_len
;
926 char *buf
= NULL
, *lim
, *next
;
927 struct rt_msghdr
*rtm
;
928 struct sockaddr_inarp
*sinarp
;
929 struct sockaddr_dl
*sdl
;
931 if (sysctl( mib
, ARRAY_SIZE(mib
), NULL
, &needed
, NULL
, 0 ) == -1) return STATUS_NOT_SUPPORTED
;
933 buf
= malloc( needed
);
934 if (!buf
) return STATUS_NO_MEMORY
;
936 if (sysctl( mib
, ARRAY_SIZE(mib
), buf
, &needed
, NULL
, 0 ) == -1)
939 return STATUS_NOT_SUPPORTED
;
946 rtm
= (struct rt_msghdr
*)next
;
947 sinarp
= (struct sockaddr_inarp
*)(rtm
+ 1);
948 if (sinarp
->sin_len
) sinarp_len
= (sinarp
->sin_len
+ sizeof(int)-1) & ~(sizeof(int)-1);
949 else sinarp_len
= sizeof(int);
950 sdl
= (struct sockaddr_dl
*)((char *)sinarp
+ sinarp_len
);
952 if (sdl
->sdl_alen
) /* arp entry */
954 entry
.addr
= sinarp
->sin_addr
;
955 entry
.if_index
= sdl
->sdl_index
;
956 if (!convert_index_to_luid( entry
.if_index
, &entry
.luid
)) break;
957 entry
.phys_addr_len
= min( 8, sdl
->sdl_alen
);
958 if (entry
.phys_addr_len
> sizeof(entry
.phys_addr
)) entry
.phys_addr_len
= 0;
959 memcpy( entry
.phys_addr
, &sdl
->sdl_data
[sdl
->sdl_nlen
], entry
.phys_addr_len
);
960 if (rtm
->rtm_rmx
.rmx_expire
== 0) entry
.state
= NlnsPermanent
;
961 else entry
.state
= NlnsReachable
;
963 entry
.is_router
= sinarp
->sin_other
& SIN_ROUTER
;
967 entry
.is_unreachable
= 0; /* FIXME */
971 ipv4_neighbour_fill_entry( &entry
, key_data
, rw_data
, dynamic_data
, static_data
);
973 if (key_data
) key_data
= (BYTE
*)key_data
+ key_size
;
974 if (rw_data
) rw_data
= (BYTE
*)rw_data
+ rw_size
;
975 if (dynamic_data
) dynamic_data
= (BYTE
*)dynamic_data
+ dynamic_size
;
976 if (static_data
) static_data
= (BYTE
*)static_data
+ static_size
;
980 next
+= rtm
->rtm_msglen
;
985 FIXME( "not implemented\n" );
986 return STATUS_NOT_IMPLEMENTED
;
989 if (!want_data
|| num
<= *count
) *count
= num
;
990 else status
= STATUS_BUFFER_OVERFLOW
;
995 static NTSTATUS
ipv6_neighbour_enumerate_all( void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
996 void *dynamic_data
, DWORD dynamic_size
,
997 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
999 FIXME( "not implemented\n" );
1000 return STATUS_NOT_IMPLEMENTED
;
1003 struct ipv4_route_data
1007 struct in_addr prefix
;
1009 struct in_addr next_hop
;
1015 static void ipv4_forward_fill_entry( struct ipv4_route_data
*entry
, struct nsi_ipv4_forward_key
*key
,
1016 struct nsi_ip_forward_rw
*rw
, struct nsi_ipv4_forward_dynamic
*dyn
,
1017 struct nsi_ip_forward_static
*stat
)
1022 key
->prefix
.WS_s_addr
= entry
->prefix
.s_addr
;
1023 key
->prefix_len
= entry
->prefix_len
;
1024 memset( key
->unk2
, 0, sizeof(key
->unk2
) );
1025 memset( key
->unk3
, 0, sizeof(key
->unk3
) );
1026 key
->luid
= entry
->luid
;
1027 key
->luid2
= entry
->luid
;
1028 key
->next_hop
.WS_s_addr
= entry
->next_hop
.s_addr
;
1034 rw
->site_prefix_len
= 0;
1035 rw
->valid_lifetime
= ~0u;
1036 rw
->preferred_lifetime
= ~0u;
1037 rw
->metric
= entry
->metric
;
1038 rw
->protocol
= entry
->protocol
;
1039 rw
->loopback
= entry
->loopback
;
1043 memset( rw
->unk
, 0, sizeof(rw
->unk
) );
1049 memset( dyn
, 0, sizeof(*dyn
) );
1054 stat
->origin
= NlroManual
;
1055 stat
->if_index
= entry
->if_index
;
1059 static NTSTATUS
ipv4_forward_enumerate_all( void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
1060 void *dynamic_data
, DWORD dynamic_size
,
1061 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
1064 NTSTATUS status
= STATUS_SUCCESS
;
1065 BOOL want_data
= key_size
|| rw_size
|| dynamic_size
|| static_size
;
1066 struct ipv4_route_data entry
;
1068 TRACE( "%p %d %p %d %p %d %p %d %p\n", key_data
, key_size
, rw_data
, rw_size
,
1069 dynamic_data
, dynamic_size
, static_data
, static_size
, count
);
1073 char buf
[512], *ptr
;
1074 struct in_addr mask
;
1078 if (!(fp
= fopen( "/proc/net/route", "r" ))) return STATUS_NOT_SUPPORTED
;
1080 /* skip header line */
1081 fgets( buf
, sizeof(buf
), fp
);
1082 while ((ptr
= fgets( buf
, sizeof(buf
), fp
)))
1084 while (!isspace( *ptr
)) ptr
++;
1087 if (!convert_unix_name_to_luid( buf
, &entry
.luid
)) continue;
1088 if (!convert_luid_to_index( &entry
.luid
, &entry
.if_index
)) continue;
1090 entry
.prefix
.s_addr
= strtoul( ptr
, &ptr
, 16 );
1091 entry
.next_hop
.s_addr
= strtoul( ptr
+ 1, &ptr
, 16 );
1092 rtf_flags
= strtoul( ptr
+ 1, &ptr
, 16 );
1093 strtoul( ptr
+ 1, &ptr
, 16 ); /* refcount, skip */
1094 strtoul( ptr
+ 1, &ptr
, 16 ); /* use, skip */
1095 entry
.metric
= strtoul( ptr
+ 1, &ptr
, 16 );
1096 mask
.s_addr
= strtoul( ptr
+ 1, &ptr
, 16 );
1097 entry
.prefix_len
= mask_v4_to_prefix( &mask
);
1098 entry
.protocol
= (rtf_flags
& RTF_GATEWAY
) ? MIB_IPPROTO_NETMGMT
: MIB_IPPROTO_LOCAL
;
1099 entry
.loopback
= entry
.protocol
== MIB_IPPROTO_LOCAL
&& entry
.prefix_len
== 32;
1103 ipv4_forward_fill_entry( &entry
, key_data
, rw_data
, dynamic_data
, static_data
);
1104 key_data
= (BYTE
*)key_data
+ key_size
;
1105 rw_data
= (BYTE
*)rw_data
+ rw_size
;
1106 dynamic_data
= (BYTE
*)dynamic_data
+ dynamic_size
;
1107 static_data
= (BYTE
*)static_data
+ static_size
;
1113 #elif defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
1115 int mib
[6] = { CTL_NET
, PF_ROUTE
, 0, PF_INET
, NET_RT_DUMP
, 0 };
1117 char *buf
= NULL
, *lim
, *next
, *addr_ptr
;
1118 struct rt_msghdr
*rtm
;
1120 if (sysctl( mib
, ARRAY_SIZE(mib
), NULL
, &needed
, NULL
, 0 ) < 0) return STATUS_NOT_SUPPORTED
;
1122 buf
= malloc( needed
);
1123 if (!buf
) return STATUS_NO_MEMORY
;
1125 if (sysctl( mib
, 6, buf
, &needed
, NULL
, 0 ) < 0)
1128 return STATUS_NOT_SUPPORTED
;
1132 for (next
= buf
; next
< lim
; next
+= rtm
->rtm_msglen
)
1135 sa_family_t dst_family
= AF_UNSPEC
;
1137 rtm
= (struct rt_msghdr
*)next
;
1139 if (rtm
->rtm_type
!= RTM_GET
)
1141 WARN( "Got unexpected message type 0x%x!\n", rtm
->rtm_type
);
1145 /* Ignore gateway routes which are multicast */
1146 if ((rtm
->rtm_flags
& RTF_GATEWAY
) && (rtm
->rtm_flags
& RTF_MULTICAST
)) continue;
1148 entry
.if_index
= rtm
->rtm_index
;
1149 if (!convert_index_to_luid( entry
.if_index
, &entry
.luid
)) continue;
1150 entry
.protocol
= (rtm
->rtm_flags
& RTF_GATEWAY
) ? MIB_IPPROTO_NETMGMT
: MIB_IPPROTO_LOCAL
;
1151 entry
.metric
= rtm
->rtm_rmx
.rmx_hopcount
;
1153 addr_ptr
= (char *)(rtm
+ 1);
1155 for (i
= 1; i
; i
<<= 1)
1157 struct sockaddr
*sa
;
1158 struct in_addr addr
;
1160 if (!(i
& rtm
->rtm_addrs
)) continue;
1162 sa
= (struct sockaddr
*)addr_ptr
;
1163 if (addr_ptr
+ sa
->sa_len
> next
+ rtm
->rtm_msglen
)
1165 ERR( "struct sockaddr extends beyond the route message, %p > %p\n",
1166 addr_ptr
+ sa
->sa_len
, next
+ rtm
->rtm_msglen
);
1169 if (sa
->sa_len
) addr_ptr
+= (sa
->sa_len
+ sizeof(int)-1) & ~(sizeof(int)-1);
1170 else addr_ptr
+= sizeof(int);
1171 /* Apple's netstat prints the netmask together with the destination
1172 * and only looks at the destination's address family. The netmask's
1173 * sa_family sometimes contains the non-existent value 0xff. */
1174 switch (i
== RTA_NETMASK
? dst_family
: sa
->sa_family
)
1178 /* Netmasks (and possibly other addresses) have only enough size
1179 * to represent the non-zero bits, e.g. a netmask of 255.0.0.0 has
1180 * 5 bytes (1 sa_len, 1 sa_family, 2 sa_port and 1 for the first
1181 * byte of sin_addr). */
1182 struct sockaddr_in sin
= {0};
1183 memcpy( &sin
, sa
, sa
->sa_len
);
1184 addr
= sin
.sin_addr
;
1189 if (i
== RTA_GATEWAY
&& entry
.protocol
== MIB_IPPROTO_NETMGMT
)
1191 /* For direct route we may simply use dest addr as next hop */
1192 C_ASSERT(RTA_DST
< RTA_GATEWAY
);
1193 addr
= entry
.prefix
;
1199 WARN( "Received unsupported sockaddr family 0x%x\n", sa
->sa_family
);
1205 entry
.prefix
= addr
;
1206 dst_family
= sa
->sa_family
;
1208 case RTA_GATEWAY
: entry
.next_hop
= addr
; break;
1209 case RTA_NETMASK
: entry
.prefix_len
= mask_v4_to_prefix( &addr
); break;
1211 WARN( "Unexpected address type 0x%x\n", i
);
1217 ipv4_forward_fill_entry( &entry
, key_data
, rw_data
, dynamic_data
, static_data
);
1218 key_data
= (BYTE
*)key_data
+ key_size
;
1219 rw_data
= (BYTE
*)rw_data
+ rw_size
;
1220 dynamic_data
= (BYTE
*)dynamic_data
+ dynamic_size
;
1221 static_data
= (BYTE
*)static_data
+ static_size
;
1228 FIXME( "not implemented\n" );
1229 return STATUS_NOT_IMPLEMENTED
;
1232 if (!want_data
|| num
<= *count
) *count
= num
;
1233 else status
= STATUS_BUFFER_OVERFLOW
;
1238 static NTSTATUS
ipv6_forward_enumerate_all( void *key_data
, DWORD key_size
, void *rw_data
, DWORD rw_size
,
1239 void *dynamic_data
, DWORD dynamic_size
,
1240 void *static_data
, DWORD static_size
, DWORD_PTR
*count
)
1242 FIXME( "not implemented\n" );
1244 return STATUS_SUCCESS
;
1247 static struct module_table ipv4_tables
[] =
1250 NSI_IP_COMPARTMENT_TABLE
,
1252 sizeof(DWORD
), sizeof(struct nsi_ip_cmpt_rw
),
1253 sizeof(struct nsi_ip_cmpt_dynamic
), 0
1256 ipv4_cmpt_get_all_parameters
,
1259 NSI_IP_ICMPSTATS_TABLE
,
1262 sizeof(struct nsi_ip_icmpstats_dynamic
), 0
1265 ipv4_icmpstats_get_all_parameters
,
1268 NSI_IP_IPSTATS_TABLE
,
1271 sizeof(struct nsi_ip_ipstats_dynamic
), sizeof(struct nsi_ip_ipstats_static
)
1274 ipv4_ipstats_get_all_parameters
,
1277 NSI_IP_UNICAST_TABLE
,
1279 sizeof(struct nsi_ipv4_unicast_key
), sizeof(struct nsi_ip_unicast_rw
),
1280 sizeof(struct nsi_ip_unicast_dynamic
), sizeof(struct nsi_ip_unicast_static
)
1282 ipv4_unicast_enumerate_all
,
1283 ip_unicast_get_all_parameters
,
1286 NSI_IP_NEIGHBOUR_TABLE
,
1288 sizeof(struct nsi_ipv4_neighbour_key
), sizeof(struct nsi_ip_neighbour_rw
),
1289 sizeof(struct nsi_ip_neighbour_dynamic
), 0
1291 ipv4_neighbour_enumerate_all
,
1294 NSI_IP_FORWARD_TABLE
,
1296 sizeof(struct nsi_ipv4_forward_key
), sizeof(struct nsi_ip_forward_rw
),
1297 sizeof(struct nsi_ipv4_forward_dynamic
), sizeof(struct nsi_ip_forward_static
)
1299 ipv4_forward_enumerate_all
,
1306 const struct module ipv4_module
=
1308 &NPI_MS_IPV4_MODULEID
,
1312 static struct module_table ipv6_tables
[] =
1315 NSI_IP_COMPARTMENT_TABLE
,
1317 sizeof(DWORD
), sizeof(struct nsi_ip_cmpt_rw
),
1318 sizeof(struct nsi_ip_cmpt_dynamic
), 0
1321 ipv6_cmpt_get_all_parameters
,
1324 NSI_IP_ICMPSTATS_TABLE
,
1327 sizeof(struct nsi_ip_icmpstats_dynamic
), 0
1330 ipv6_icmpstats_get_all_parameters
,
1333 NSI_IP_IPSTATS_TABLE
,
1336 sizeof(struct nsi_ip_ipstats_dynamic
), sizeof(struct nsi_ip_ipstats_static
)
1339 ipv6_ipstats_get_all_parameters
,
1342 NSI_IP_UNICAST_TABLE
,
1344 sizeof(struct nsi_ipv6_unicast_key
), sizeof(struct nsi_ip_unicast_rw
),
1345 sizeof(struct nsi_ip_unicast_dynamic
), sizeof(struct nsi_ip_unicast_static
)
1347 ipv6_unicast_enumerate_all
,
1348 ip_unicast_get_all_parameters
,
1351 NSI_IP_NEIGHBOUR_TABLE
,
1353 sizeof(struct nsi_ipv6_neighbour_key
), sizeof(struct nsi_ip_neighbour_rw
),
1354 sizeof(struct nsi_ip_neighbour_dynamic
), 0
1356 ipv6_neighbour_enumerate_all
,
1359 NSI_IP_FORWARD_TABLE
,
1361 sizeof(struct nsi_ipv6_forward_key
), sizeof(struct nsi_ip_forward_rw
),
1362 sizeof(struct nsi_ipv6_forward_dynamic
), sizeof(struct nsi_ip_forward_static
)
1364 ipv6_forward_enumerate_all
,
1371 const struct module ipv6_module
=
1373 &NPI_MS_IPV6_MODULEID
,