open Virt_mem_types
open Kernel_net_device
+open Kernel_net
-type linkage = Next | DevList of int
+let max_net_devices = 10000
let rec find_net_devices debug image ksymmap kernel_version =
if not (net_device_known kernel_version) then (
) else (
let size = net_device_size kernel_version in
- (* In kernels < around 2.6.22, this is a simple linked list:
+ (* In kernels < ~ 2.6.22, this is a simple linked list:
* dev_base -> next -> next
* In kernels >= 2.6.23, this is a list_head:
* dev_base_head -> list_head dev_list -> ...
*)
- let linkage =
+ let map =
let { field_available = available } =
field_signature_of_net_device_next kernel_version in
if available then
- Some Next
+ Some map_next
else (
let { field_available = available; field_offset = offset } =
field_signature_of_net_device_dev_list'next kernel_version in
if available then
- Some (DevList offset)
+ Some (map_dev_list offset)
else (
eprintf (f_"%s: kernel net_device table is not linked through either next pointer or dev_list list_head. Cannot read net devices.\n") image.domname;
None
)
) in
- match linkage with
- | None -> image, None
- | Some Next ->
- printf "linkage = Next\n%!";
+ match map with
+ | None -> image, None
- (* Linkage through old-style chain of next pointers. *)
- let dev_base =
+ | Some map ->
+ (* What is the starting point for iteration? In older kernels
+ * it was the symbol 'dev_base'. Then briefly (2.6.22-2.6.24)
+ * it became 'sruct list_head dev_base_head'. Then when net
+ * namespaces were introduced (>= 2.6.25) it became 'struct
+ * list_head init_net.dev_base_head'.
+ *)
+ let addr =
try Some (Ksymmap.find "dev_base" ksymmap)
with Not_found ->
- eprintf (f_"%s: could not find dev_base symbol in kernel image\n") image.domname;
- None in
- (match dev_base with
- | None -> image, None
- | Some dev_base ->
- do_next image kernel_version dev_base size
- );
-
- | Some (DevList offset) ->
- printf "linkage = DevList %d\n%!" offset;
-
- (* Linkage through new-style list_head dev_list. *)
- let dev_base_head =
- try Some (Ksymmap.find "dev_base_head" ksymmap)
- with Not_found ->
- eprintf (f_"%s: could not find dev_base_head symbol in kernel image\n") image.domname;
- None in
- (match dev_base_head with
- | None -> image, None
- | Some dev_base_head ->
- let dev_base_head =
- Virt_mem_mmap.follow_pointer image.mem dev_base_head in
-
- do_dev_list image kernel_version dev_base_head offset size
- );
+ try
+ let addr = Ksymmap.find "dev_base_head" ksymmap in
+ let addr = Virt_mem_mmap.follow_pointer image.mem addr in
+ Some addr
+ with Not_found ->
+ try
+ let addr = Ksymmap.find "init_net" ksymmap in
+ if not (net_known kernel_version) then (
+ eprintf (f_"%s: struct net not available in this kernel version.\n") image.domname;
+ raise Not_found
+ );
+ let init_net = get_net kernel_version image.mem addr in
+ let addr = init_net.net_dev_base_head'next in
+ Some addr
+ with Not_found ->
+ eprintf (f_"%s: cannot find dev_base, dev_base_head or init_net symbols in kernel image.\n") image.domname;
+ None in
+
+ match addr with
+ | None -> image, None
+
+ | Some addr ->
+ (* Map over the structure using previously defined map function. *)
+ let image, netdevs =
+ map image kernel_version addr size (
+ fun netdev ->
+ { netdev_name = truncate_c_string netdev.net_device_name;
+ netdev_dev_addr = netdev.net_device_dev_addr }
+ ) in
+
+ image, Some netdevs
)
-(* Iterate dev_base_head -> list_head dev_list -> ... *)
-and do_dev_list image kernel_version dev_base_head offset size =
+(* Map dev_base_head -> list_head dev_list -> ... *)
+and map_dev_list offset image kernel_version first_addr size f =
+ eprintf "map_dev_list: first_addr is %Lx\n" first_addr;
+
(* The list_head points into the middle of the structure.
* Adjust this address to point to the start of the
* structure.
*)
- let addr = Int64.sub dev_base_head (Int64.of_int offset) in
-
- printf "do_dev_list, size = %d\n" size;
+ let addr = Int64.sub first_addr (Int64.of_int offset) in
+ eprintf "map_dev_list: after subtracting, addr is %Lx\n" addr;
- let image =
- let rec loop image addr =
+ let rec loop i image acc addr =
+ if i <= max_net_devices then (
+ eprintf "map_dev_list: called at %Lx\n" addr;
let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
let image =
if not mapped then
else
image in
let dev = get_net_device kernel_version image.mem addr in
- printf "net_device_name = %S\n" dev.net_device_name;
+ eprintf "map_dev_list: %Lx %S\n" addr dev.net_device_name;
+ let acc = f dev :: acc in
let addr = Option.get dev.net_device_dev_list'next in
- if addr <> dev_base_head then
- loop image addr
+ if addr <> first_addr then
+ loop (i+1) image acc addr
else
- image
- in
- loop image addr in
- image, Some dev_base_head
+ image, acc
+ ) else
+ failwith (sprintf (f_"%s: too many network devices") image.domname);
+ in
+ loop 0 image [] addr
(* Iterate dev_base -> next -> next ... *)
-and do_next image kernel_version addr size =
- printf "do_next, size = %d\n" size;
-
- let image =
- let rec loop image addr =
+and map_next image kernel_version addr size f =
+ let rec loop i image acc addr =
+ if i <= max_net_devices then (
if addr <> 0L then (
let mapped = Virt_mem_mmap.is_mapped_range image.mem addr size in
let image =
else
image in
let dev = get_net_device kernel_version image.mem addr in
- printf "net_device_name = %S\n" dev.net_device_name;
+ eprintf "map_next: %S\n" dev.net_device_name;
+ let acc = f dev :: acc in
let addr =
match dev.net_device_next with
| None -> assert false | Some addr -> addr in
- loop image addr
+ loop (i+1) image acc addr
) else
- image
- in
- loop image addr in
- image, Some addr
+ image, acc
+ ) else
+ failwith (sprintf (f_"%s: too many network devices") image.domname);
+ in
+ loop 0 image [] addr