Initial commit
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2021 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
# List of options the script accepts. Trailing column means that the option
|
||||
# requires an argument.
|
||||
ARGUMENT_LIST=(
|
||||
"help"
|
||||
"product-id:"
|
||||
"product-name:"
|
||||
"host-mac:"
|
||||
"bind-device:"
|
||||
"dev-mac:"
|
||||
"dev-type:"
|
||||
"gadget-dir-name:"
|
||||
"iface-name:"
|
||||
)
|
||||
|
||||
print_usage() {
|
||||
cat <<HELP
|
||||
$0 [OPTIONS] [stop|start]
|
||||
Create USB Gadget Configuration
|
||||
--product-id USB Product Id for the gadget.
|
||||
--product-name Product name string (en) for the gadget.
|
||||
--host-mac MAC address of the host part of the connection. Optional.
|
||||
--dev-mac MAC address of the device (gadget) part of the connection. Optional.
|
||||
--dev-type Type of gadget to instantiate. Default: "eem"
|
||||
--bind-device Name of the device to bind, as listed in /sys/class/udc/
|
||||
--gadget-dir-name Optional base name for gadget directory. Default: iface-name
|
||||
--iface-name name of the network interface.
|
||||
--help Print this help and exit.
|
||||
HELP
|
||||
}
|
||||
|
||||
gadget_start() {
|
||||
# Always provide a basic network configuration
|
||||
mkdir -p /run/systemd/network || return
|
||||
cat >/run/systemd/network/+-bmc-"${IFACE_NAME}".network <<EOF
|
||||
[Match]
|
||||
Name=${IFACE_NAME}
|
||||
EOF
|
||||
|
||||
# Add the gbmcbr configuration if this is a relevant device
|
||||
if (( ID_VENDOR == 0x18d1 && ID_PRODUCT == 0x22b )); then
|
||||
cat >>/run/systemd/network/+-bmc-"${IFACE_NAME}".network <<EOF
|
||||
[Network]
|
||||
Bridge=gbmcbr
|
||||
[Bridge]
|
||||
Cost=85
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Ignore any failures due to systemd being unavailable at boot
|
||||
networkctl reload || true
|
||||
|
||||
local gadget_dir="${CONFIGFS_HOME}/usb_gadget/${GADGET_DIR_NAME}"
|
||||
mkdir -p "${gadget_dir}" || return
|
||||
echo "${ID_VENDOR}" >"${gadget_dir}/idVendor" || return
|
||||
echo "${ID_PRODUCT}" >"${gadget_dir}/idProduct" || return
|
||||
|
||||
local str_en_dir="${gadget_dir}/strings/0x409"
|
||||
mkdir -p "${str_en_dir}" || return
|
||||
echo "${STR_EN_VENDOR}" >"${str_en_dir}/manufacturer" || return
|
||||
echo "${STR_EN_PRODUCT}" >"${str_en_dir}/product" || return
|
||||
|
||||
local config_dir="${gadget_dir}/configs/c.1"
|
||||
mkdir -p "${config_dir}" || return
|
||||
echo 100 > "${config_dir}/MaxPower" || return
|
||||
mkdir -p "${config_dir}/strings/0x409" || return
|
||||
echo "${DEV_TYPE^^}" > "${config_dir}/strings/0x409/configuration" || return
|
||||
|
||||
local func_dir="${gadget_dir}/functions/${DEV_TYPE}.${IFACE_NAME}"
|
||||
mkdir -p "${func_dir}" || return
|
||||
|
||||
if [[ -n $HOST_MAC_ADDR ]]; then
|
||||
echo "${HOST_MAC_ADDR}" >"${func_dir}"/host_addr || return
|
||||
fi
|
||||
|
||||
if [[ -n $DEV_MAC_ADDR ]]; then
|
||||
echo "${DEV_MAC_ADDR}" >"${func_dir}"/dev_addr || return
|
||||
fi
|
||||
|
||||
ln -s "${func_dir}" "${config_dir}" || return
|
||||
|
||||
# This only works on kernel 5.12+, we have to ignore failures for now
|
||||
echo "$IFACE_NAME" >"${func_dir}"/ifname || true
|
||||
|
||||
echo "${BIND_DEVICE}" >"${gadget_dir}"/UDC || return
|
||||
# Try to reconfigure a few times in case we race with systemd-networkd
|
||||
local start=$SECONDS
|
||||
while (( SECONDS - start < 5 )); do
|
||||
local ifname
|
||||
ifname="$(<"${func_dir}"/ifname)" || return
|
||||
[ "${IFACE_NAME}" = "$ifname" ] && break
|
||||
ip link set dev "$ifname" down && \
|
||||
ip link set dev "$ifname" name "${IFACE_NAME}" && break
|
||||
sleep 1
|
||||
done
|
||||
ip link set dev "$IFACE_NAME" up || return
|
||||
}
|
||||
|
||||
gadget_stop() {
|
||||
local gadget_dir="${CONFIGFS_HOME}/usb_gadget/${GADGET_DIR_NAME}"
|
||||
rm -f "${gadget_dir}/configs/c.1/${DEV_TYPE}.${IFACE_NAME}"
|
||||
rmdir "${gadget_dir}/functions/${DEV_TYPE}.${IFACE_NAME}" \
|
||||
"${gadget_dir}/configs/c.1/strings/0x409" \
|
||||
"${gadget_dir}/configs/c.1" \
|
||||
"${gadget_dir}/strings/0x409" \
|
||||
"${gadget_dir}" || true
|
||||
|
||||
rm -f /run/systemd/network/+-bmc-"${IFACE_NAME}".network
|
||||
networkctl reload || true
|
||||
}
|
||||
|
||||
opts="$(getopt \
|
||||
--longoptions "$(printf "%s," "${ARGUMENT_LIST[@]}")" \
|
||||
--name "$(basename "$0")" \
|
||||
--options "" \
|
||||
-- "$@"
|
||||
)"
|
||||
|
||||
eval set -- "$opts"
|
||||
|
||||
CONFIGFS_HOME=${CONFIGFS_HOME:-/sys/kernel/config}
|
||||
ID_VENDOR="0x18d1" # Google
|
||||
ID_PRODUCT=""
|
||||
STR_EN_VENDOR="Google"
|
||||
STR_EN_PRODUCT=""
|
||||
DEV_MAC_ADDR=""
|
||||
DEV_TYPE="eem"
|
||||
HOST_MAC_ADDR=""
|
||||
BIND_DEVICE=""
|
||||
ACTION="start"
|
||||
GADGET_DIR_NAME=""
|
||||
IFACE_NAME=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--product-id)
|
||||
ID_PRODUCT=$2
|
||||
shift 2
|
||||
;;
|
||||
--product-name)
|
||||
STR_EN_PRODUCT=$2
|
||||
shift 2
|
||||
;;
|
||||
--host-mac)
|
||||
HOST_MAC_ADDR=$2
|
||||
shift 2
|
||||
;;
|
||||
--dev-mac)
|
||||
DEV_MAC_ADDR=$2
|
||||
shift 2
|
||||
;;
|
||||
--dev-type)
|
||||
DEV_TYPE=$2
|
||||
shift 2
|
||||
;;
|
||||
--bind-device)
|
||||
BIND_DEVICE=$2
|
||||
shift 2
|
||||
;;
|
||||
--gadget-dir-name)
|
||||
GADGET_DIR_NAME=$2
|
||||
shift 2
|
||||
;;
|
||||
--iface-name)
|
||||
IFACE_NAME=$2
|
||||
shift 2
|
||||
;;
|
||||
--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
start)
|
||||
ACTION="start"
|
||||
shift 1
|
||||
break
|
||||
;;
|
||||
stop)
|
||||
ACTION="stop"
|
||||
shift 1
|
||||
break
|
||||
;;
|
||||
--)
|
||||
shift 1
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$GADGET_DIR_NAME" ]; then
|
||||
GADGET_DIR_NAME="$IFACE_NAME"
|
||||
fi
|
||||
|
||||
if [[ $ACTION == "stop" ]]; then
|
||||
gadget_stop
|
||||
else
|
||||
if [ -z "$ID_PRODUCT" ]; then
|
||||
echo "Product ID is missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$IFACE_NAME" ]; then
|
||||
echo "Interface name is missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$BIND_DEVICE" ]; then
|
||||
echo "Bind device is missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rc=0
|
||||
gadget_start || rc=$?
|
||||
(( rc == 0 )) || gadget_stop || true
|
||||
exit $rc
|
||||
fi
|
||||
Reference in New Issue
Block a user