Fast direct USB connectivity

This commit is contained in:
Ryuichi Leo Takashige
2026-03-11 18:17:59 +00:00
parent f221a6c85c
commit cfc8f09004
3 changed files with 384 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
set -Eeuo pipefail
msg() {
printf '\n==> %s\n' "$*"
}
msg "Bringing down old Apple USB fallback interfaces"
sudo ifconfig en4 down 2>/dev/null || true
sudo ifconfig en5 down 2>/dev/null || true
sudo ifconfig en6 down 2>/dev/null || true
msg "Bringing down current anpi interfaces"
sudo ifconfig anpi0 down 2>/dev/null || true
sudo ifconfig anpi1 down 2>/dev/null || true
sudo ifconfig anpi2 down 2>/dev/null || true
msg "Stopping likely bad exporter services"
sudo launchctl bootout system/com.apple.usbmuxd 2>/dev/null || true
sudo launchctl bootout system/com.apple.remoted 2>/dev/null || true
launchctl bootout "gui/$(id -u)/com.apple.remoted" 2>/dev/null || true
sudo pkill -x usbmuxd 2>/dev/null || true
sudo pkill -x remoted 2>/dev/null || true
cat <<'EOF'
Now unplug and replug the cable.
After reconnect, press Enter to continue.
EOF
read -r _
msg "Bringing up anpi interfaces and requesting DHCP"
for ifn in anpi0 anpi1 anpi2; do
sudo ifconfig "$ifn" up 2>/dev/null || true
sudo ipconfig set "$ifn" DHCP 2>/dev/null || true
done
sleep 3
msg "Resulting interface state"
for ifn in anpi0 anpi1 anpi2; do
echo
echo "--- $ifn ---"
ifconfig "$ifn" 2>/dev/null || true
ipconfig getifaddr "$ifn" 2>/dev/null || true
done
echo
echo "Use whichever interface got 10.42.0.x or 10.43.0.x"
+177
View File
@@ -0,0 +1,177 @@
#!/usr/bin/env bash
set -Eeuo pipefail
KVER="$(uname -r)"
WORKDIR="${HOME}/apple1905-cdcncm"
SRCVER="6.14.0-1015.15"
SRCNAME="linux-nvidia-6.14"
BASE_URL="https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/${SRCNAME}/${SRCVER}"
ORIG="${SRCNAME}_6.14.0.orig.tar.gz"
DIFF="${SRCNAME}_${SRCVER}.diff.gz"
DSC="${SRCNAME}_${SRCVER}.dsc"
KBUILD="/lib/modules/${KVER}/build"
msg() { printf '\n==> %s\n' "$*"; }
die() { echo "ERROR: $*" >&2; exit 1; }
need_cmd() { command -v "$1" >/dev/null 2>&1 || die "Missing command: $1"; }
[[ $EUID -eq 0 ]] || die "Run with sudo"
[[ -d "$KBUILD" ]] || die "Missing kernel headers/build dir: $KBUILD"
need_cmd curl
need_cmd dpkg-source
need_cmd make
need_cmd python3
need_cmd modprobe
need_cmd insmod
need_cmd modinfo
need_cmd ip
need_cmd dmesg
need_cmd find
msg "Installing build deps"
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends \
build-essential \
linux-headers-"${KVER}" \
dpkg-dev \
ca-certificates \
curl \
kmod \
zstd \
python3
msg "Preparing workspace"
rm -rf "$WORKDIR"
mkdir -p "$WORKDIR"
cd "$WORKDIR"
msg "Downloading exact source package for ${SRCNAME} ${SRCVER}"
curl -fL "${BASE_URL}/${ORIG}" -o "${ORIG}"
curl -fL "${BASE_URL}/${DIFF}" -o "${DIFF}"
curl -fL "${BASE_URL}/${DSC}" -o "${DSC}"
msg "Extracting source"
dpkg-source -x "${DSC}"
SRCDIR="$(find . -maxdepth 1 -mindepth 1 -type d -name "${SRCNAME}-*" | head -n1)"
[[ -n "${SRCDIR}" ]] || die "Could not find extracted source directory"
cd "${SRCDIR}"
[[ -f drivers/net/usb/cdc_ncm.c ]] || die "cdc_ncm.c not found in source tree"
msg "Patching cdc_ncm.c"
python3 <<'PY'
from pathlib import Path
import re
p = Path("drivers/net/usb/cdc_ncm.c")
s = p.read_text()
if "0x05ac, 0x1905, 0" not in s:
block = (
'\t/* Apple Mac direct USB-C networking quirk */\n'
'\t{ USB_DEVICE_INTERFACE_NUMBER(0x05ac, 0x1905, 0),\n'
'\t .driver_info = (unsigned long)&apple_private_interface_info,\n'
'\t},\n'
'\t{ USB_DEVICE_INTERFACE_NUMBER(0x05ac, 0x1905, 2),\n'
'\t .driver_info = (unsigned long)&apple_private_interface_info,\n'
'\t},\n'
)
pat = re.compile(
r'(\{\s*USB_INTERFACE_INFO\s*\(\s*USB_CLASS_COMM\s*,\s*USB_CDC_SUBCLASS_NCM\s*,\s*USB_CDC_PROTO_NONE\s*\)\s*,\s*\.driver_info\s*=\s*\(unsigned long\)&cdc_ncm_info\s*,\s*\},)',
re.S,
)
s2, n = pat.subn(block + r'\1', s, count=1)
if n != 1:
raise SystemExit("Could not find generic CDC NCM class-match entry to patch")
s = s2
# Patch old bind check if needed.
# Old style:
# if (!dev->in || !dev->out || !dev->status)
# New behavior for this Mac:
# allow missing status endpoint for 05ac:1905
old = re.compile(
r'if\s*\(\s*!dev->in\s*\|\|\s*!dev->out\s*\|\|\s*!dev->status\s*\)',
re.S,
)
repl = (
'if (!dev->in || !dev->out || '
'(!dev->status && '
'!(le16_to_cpu(dev->udev->descriptor.idVendor) == 0x05ac && '
'le16_to_cpu(dev->udev->descriptor.idProduct) == 0x1905)))'
)
s, n = old.subn(repl, s, count=1)
# If the tree already has the newer FLAG_LINK_INTR logic, leave it alone.
if n == 0 and "FLAG_LINK_INTR" not in s:
raise SystemExit("Could not patch bind_common() missing-status check")
# Add a loud marker so we know the patched module actually loaded.
if 'Apple 05ac:1905 quirk test module loaded' not in s:
m = re.search(r'static\s+int\s+__init\s+cdc_ncm_init\s*\(\s*void\s*\)\s*\{', s)
if m:
insert_at = m.end()
s = s[:insert_at] + '\n\tpr_info("cdc_ncm: Apple 05ac:1905 quirk test module loaded\\n");' + s[insert_at:]
p.write_text(s)
print("Patched", p)
PY
msg "Preparing out-of-tree build dir"
mkdir -p buildmod
cp drivers/net/usb/cdc_ncm.c buildmod/
cat > buildmod/Makefile <<'EOF'
obj-m += cdc_ncm.o
ccflags-y += -Wno-error
all:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
EOF
msg "Building patched module"
cd buildmod
make -C "$KBUILD" M="$PWD" modules
PATCHED_KO="$PWD/cdc_ncm.ko"
[[ -f "$PATCHED_KO" ]] || die "Patched cdc_ncm.ko was not built"
msg "Patched module info"
modinfo "$PATCHED_KO" | sed -n '1,20p'
msg "Reloading module stack"
modprobe -r cdc_mbim 2>/dev/null || true
modprobe -r cdc_ncm 2>/dev/null || true
insmod "$PATCHED_KO"
msg "Recent dmesg"
dmesg | tail -n 60
cat <<EOF
Done.
Now:
1. run: sudo dmesg -w
2. unplug and replug the USB-C cable to the Mac
3. then run:
ip -br link
lsusb | grep 05ac:1905
You want to see:
- cdc_ncm: Apple 05ac:1905 quirk test module loaded
- no bind() failure for 05ac:1905
- a new interface appearing
Workspace:
$WORKDIR
EOF
+155
View File
@@ -0,0 +1,155 @@
#!/usr/bin/env bash
set -Eeuo pipefail
PATCHED_CDC_NCM="/root/apple1905-cdcncm/linux-nvidia-6.14-6.14.0/buildmod/cdc_ncm.ko"
need() {
command -v "$1" >/dev/null 2>&1 || {
echo "Missing command: $1" >&2
exit 1
}
}
msg() {
printf '\n==> %s\n' "$*"
}
[[ $EUID -eq 0 ]] || {
echo "Run with sudo." >&2
exit 1
}
need modprobe
need insmod
need nmcli
need lsusb
need ip
need awk
need grep
[[ -f $PATCHED_CDC_NCM ]] || {
echo "Patched module not found: $PATCHED_CDC_NCM" >&2
exit 1
}
msg "Removing old hard-block config if present"
rm -f /etc/modprobe.d/zz-kill-mac-usb-net.conf
depmod -a
msg "Loading USB4 / Type-C / Thunderbolt support"
modprobe typec || true
modprobe typec_ucsi || true
modprobe ucsi_acpi || true
modprobe thunderbolt || true
modprobe typec_thunderbolt || true
modprobe thunderbolt_net || true
msg "Unloading stock USB network stack"
modprobe -r cdc_mbim cdc_wdm cdc_ncm cdc_ether usbnet 2>/dev/null || true
msg "Loading dependency modules"
modprobe usbnet
modprobe cdc_ether
msg "Loading patched cdc_ncm"
if lsmod | grep -q '^cdc_ncm '; then
echo "cdc_ncm already loaded"
else
insmod "$PATCHED_CDC_NCM"
fi
msg "Current module state"
lsmod | grep -E 'typec|ucsi|thunderbolt|cdc_ncm|cdc_ether|usbnet' || true
cat <<'EOF'
Now do this on the Mac:
1. Run the Mac script below
2. Replug the cable
3. Wait for the Mac to land on the fast bus
Then run this same script again with:
sudo ./spark-usbc-setup.sh finalize
EOF
if [[ ${1:-} != "finalize" ]]; then
exit 0
fi
msg "Waiting for Apple Mac on fast bus (Bus 004 @ 10000M or equivalent)"
for _ in $(seq 1 60); do
if lsusb -t | grep -q '05ac:1905\|Driver=\[none\], 10000M'; then
break
fi
sleep 1
done
msg "lsusb -t snapshot"
lsusb -t
echo
lsusb | grep '05ac:1905' || true
msg "Waiting for new Apple USB NICs"
for _ in $(seq 1 30); do
mapfile -t APPLE_IFS < <(
ip -o link | awk -F': ' '{print $2}' |
grep '^enx36be1bab12' || true
)
if [[ ${#APPLE_IFS[@]} -ge 2 ]]; then
break
fi
sleep 1
done
if [[ ${#APPLE_IFS[@]} -lt 2 ]]; then
echo "Did not find two Apple USB interfaces." >&2
ip -br link
exit 1
fi
IF0="${APPLE_IFS[0]}"
IF1="${APPLE_IFS[1]}"
msg "Found interfaces: $IF0 and $IF1"
msg "Resetting old NetworkManager profiles"
nmcli connection delete mac-usb-dhcp-0 2>/dev/null || true
nmcli connection delete mac-usb-dhcp-1 2>/dev/null || true
msg "Bringing up shared DHCP on both interfaces"
nmcli connection add type ethernet ifname "$IF0" con-name mac-usb-dhcp-0
nmcli connection modify mac-usb-dhcp-0 \
ipv4.method shared \
ipv6.method disabled \
ipv4.addresses 10.42.0.1/24
nmcli connection up mac-usb-dhcp-0
nmcli connection add type ethernet ifname "$IF1" con-name mac-usb-dhcp-1
nmcli connection modify mac-usb-dhcp-1 \
ipv4.method shared \
ipv6.method disabled \
ipv4.addresses 10.43.0.1/24
nmcli connection up mac-usb-dhcp-1
msg "Current addresses"
ip -br addr show dev "$IF0"
ip -br addr show dev "$IF1"
msg "Recent NetworkManager log"
journalctl -u NetworkManager -n 60 --no-pager || true
cat <<EOF
Done.
DGX shared-DHCP interfaces:
$IF0 -> 10.42.0.1/24
$IF1 -> 10.43.0.1/24
Next on the Mac:
sudo ipconfig set anpi0 DHCP
sudo ipconfig set anpi1 DHCP
sudo ipconfig set anpi2 DHCP
EOF