Ifone (Ifone v1.0.0)

View Source

iOS device USB interface discovery.

This module provides functions to discover NCM (Network Control Model) data interfaces on connected iOS devices, and to look up USB device information from network interface names.

Usage

List NCM data interfaces for a device by serial number:

iex> Ifone.list_ncm_data_interfaces("00008101000000000000001E")
{:ok, %{configuration: 5, interfaces: %{3 => "en16", 5 => "en17"}}}

Or by USB location ID:

iex> Ifone.list_ncm_data_interfaces(0x02100000)
{:ok, %{configuration: 5, interfaces: %{3 => "en16", 5 => "en17"}}}

Enumerate every connected device at once:

iex> Ifone.list_devices()
{:ok, %{"00008101000000000000001E" => %{configuration: 5, interfaces: %{3 => "en16", 5 => "en17"}}}}

Look up which device a network interface belongs to:

iex> Ifone.get_serial_for_interface("en16")
{:ok, "00008101000000000000001E"}

Platform Support

  • macOS: Uses IOKit via a NIF
  • Linux: Uses sysfs traversal (pure Elixir)

Note: On Linux, USB location ID lookup is not supported — use serial numbers instead.

Summary

Types

Result of listing NCM data interfaces.

Functions

Gets the USB serial number for a network interface.

Lists all connected iOS devices and their NCM interfaces in one call.

Lists NCM data interfaces for a USB device.

Types

interfaces_result()

@type interfaces_result() :: %{
  configuration: non_neg_integer(),
  interfaces: %{required(non_neg_integer()) => String.t() | nil}
}

Result of listing NCM data interfaces.

  • configuration - The current USB configuration number
  • interfaces - Map of USB interface number to network interface name (or nil if not yet bound)

Functions

get_serial_for_interface(interface_name)

@spec get_serial_for_interface(String.t()) :: {:ok, String.t()} | {:error, atom()}

Gets the USB serial number for a network interface.

Given a network interface name (e.g., "en16"), returns the USB serial number of the iOS device that owns that interface. This is useful for correlating network interfaces back to specific devices.

Arguments

  • interface_name - Network interface name (e.g., "en16")

Returns

  • {:ok, serial} - The USB serial number of the device
  • {:error, :not_found} - Interface not found or not a USB NCM interface

Examples

iex> Ifone.get_serial_for_interface("en16")
{:ok, "00008101000000000000001E"}

iex> Ifone.get_serial_for_interface("lo0")
{:error, :not_found}

list_devices()

@spec list_devices() ::
  {:ok, %{required(String.t()) => interfaces_result()}} | {:error, atom()}

Lists all connected iOS devices and their NCM interfaces in one call.

Returns a map keyed by USB serial number, where each value has the same shape as list_ncm_data_interfaces/1 — the current USB configuration and a map of NCM interface numbers to network interface names. This is the discovery counterpart of list_ncm_data_interfaces/1: it tells you which devices are present without needing to know a serial number up front.

Only iOS devices are listed. On platforms where no device can be enumerated, returns {:ok, %{}}.

Returns

  • {:ok, %{serial => %{configuration: N, interfaces: %{...}}}} - Connected devices
  • {:error, reason} - Error

Examples

# macOS — interfaces keyed by CDC-Data interface number
iex> Ifone.list_devices()
{:ok, %{"00008101000000000000001E" => %{configuration: 5, interfaces: %{3 => "en16", 5 => "en17"}}}}

# Linux — interfaces keyed by CDC-Control interface number
iex> Ifone.list_devices()
{:ok, %{"00008101000000000000001E" => %{configuration: 5, interfaces: %{2 => "enx8e7aaa54ae75", 4 => "enxb60457655ed3"}}}}

iex> Ifone.list_devices()
{:ok, %{}}

list_ncm_data_interfaces(identifier)

@spec list_ncm_data_interfaces(String.t() | non_neg_integer()) ::
  {:ok, interfaces_result()} | {:error, atom()}

Lists NCM data interfaces for a USB device.

Returns the current USB configuration and a map of NCM interfaces that belong to the specified device. Each interface is mapped to its corresponding network interface name (e.g., "en16" on macOS or "enx8e7aaa54ae75" on Linux), or nil if the interface exists but has no network interface bound yet.

Arguments

  • identifier - Either a USB serial number (string) or USB location ID (integer)

Returns

  • {:ok, %{configuration: N, interfaces: %{...}}} - Map with configuration and interfaces
  • {:error, :not_found} - Device not found
  • {:error, reason} - Other error

Platform Differences

The interface numbers in the returned map differ by platform. On macOS, network interfaces are reported on the CDC-Data interface (e.g., interface 3). On Linux, they are reported on the CDC-Control interface (e.g., interface 2). To write cross-platform code, check for both:

case Ifone.list_ncm_data_interfaces("00008101000000000000001E") do
  {:ok, %{configuration: 5, interfaces: interfaces}} ->
    ifname = interfaces[2] || interfaces[3]
    # ...

  {:error, reason} ->
    # ...
end

Examples

# macOS — keyed by CDC-Data interface number
iex> Ifone.list_ncm_data_interfaces("00008101000000000000001E")
{:ok, %{configuration: 5, interfaces: %{3 => "en16", 5 => "en17"}}}

# Linux — keyed by CDC-Control interface number
iex> Ifone.list_ncm_data_interfaces("00008101000000000000001E")
{:ok, %{configuration: 5, interfaces: %{2 => "enx8e7aaa54ae75", 4 => "enxb60457655ed3"}}}

iex> Ifone.list_ncm_data_interfaces(0x02100000)
{:ok, %{configuration: 5, interfaces: %{3 => "en16", 5 => "en17"}}}

iex> Ifone.list_ncm_data_interfaces("nonexistent")
{:error, :not_found}