Current section
Files
Jump to
Current section
Files
lib/ifone.ex
defmodule Ifone do
@moduledoc """
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"}}}
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.
"""
@typedoc """
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)
"""
@type interfaces_result :: %{
configuration: non_neg_integer(),
interfaces: %{non_neg_integer() => String.t() | nil}
}
@doc """
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}
"""
@spec list_ncm_data_interfaces(String.t() | non_neg_integer()) ::
{:ok, interfaces_result()} | {:error, atom()}
defdelegate list_ncm_data_interfaces(identifier), to: Ifone.USB
@doc """
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}
"""
@spec get_serial_for_interface(String.t()) :: {:ok, String.t()} | {:error, atom()}
defdelegate get_serial_for_interface(interface_name), to: Ifone.USB
end