blob: 8b7bf539c849bf72478413f18b85b59131247b91 [file] [log] [blame]
Maksym Sloyko96342732021-08-03 21:54:28 +00001#!/bin/bash
2# Copyright 2021 Google LLC
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
17# List of options the script accepts. Trailing column means that the option
18# requires an argument.
19ARGUMENT_LIST=(
20 "help"
21 "product-id:"
22 "product-name:"
23 "host-mac:"
24 "bind-device:"
25 "dev-mac:"
William A. Kennington IIIf8a77742022-02-28 18:05:54 -080026 "dev-type:"
Maksym Sloyko96342732021-08-03 21:54:28 +000027 "gadget-dir-name:"
28 "iface-name:"
29)
30
31print_usage() {
32 cat <<HELP
33$0 [OPTIONS] [stop|start]
34 Create USB Gadget Configuration
35 --product-id USB Product Id for the gadget.
36 --product-name Product name string (en) for the gadget.
37 --host-mac MAC address of the host part of the connection. Optional.
38 --dev-mac MAC address of the device (gadget) part of the connection. Optional.
William A. Kennington IIIf8a77742022-02-28 18:05:54 -080039 --dev-type Type of gadget to instantiate. Default: "eem"
Maksym Sloyko96342732021-08-03 21:54:28 +000040 --bind-device Name of the device to bind, as listed in /sys/class/udc/
William A. Kennington III878454a2022-04-04 17:05:05 -070041 --gadget-dir-name Optional base name for gadget directory. Default: iface-name
William A. Kennington III69ebd2c2022-04-04 17:51:09 -070042 --iface-name name of the network interface.
Maksym Sloyko96342732021-08-03 21:54:28 +000043 --help Print this help and exit.
44HELP
45}
46
47gadget_start() {
William A. Kennington III87623eb2022-04-04 19:36:47 -070048 # Always provide a basic network configuration
49 mkdir -p /run/systemd/network || return
50 cat >/run/systemd/network/+-bmc-"${IFACE_NAME}".network <<EOF
William A. Kennington IIIa9de0df2022-02-22 17:11:13 -080051[Match]
52Name=${IFACE_NAME}
William A. Kennington III87623eb2022-04-04 19:36:47 -070053EOF
54
55 # Add the gbmcbr configuration if this is a relevant device
56 if (( ID_VENDOR == 0x18d1 && ID_PRODUCT == 0x22b )); then
57 cat >>/run/systemd/network/+-bmc-"${IFACE_NAME}".network <<EOF
William A. Kennington IIIa9de0df2022-02-22 17:11:13 -080058[Network]
59Bridge=gbmcbr
60[Bridge]
61Cost=85
62EOF
William A. Kennington IIIa9de0df2022-02-22 17:11:13 -080063 fi
64
William A. Kennington III87623eb2022-04-04 19:36:47 -070065 # Ignore any failures due to systemd being unavailable at boot
66 networkctl reload || true
67
Maksym Sloyko96342732021-08-03 21:54:28 +000068 local gadget_dir="${CONFIGFS_HOME}/usb_gadget/${GADGET_DIR_NAME}"
William A. Kennington IIIe1c8b872022-04-04 17:30:48 -070069 mkdir -p "${gadget_dir}" || return
70 echo ${ID_VENDOR} > "${gadget_dir}/idVendor" || return
71 echo ${ID_PRODUCT} > "${gadget_dir}/idProduct" || return
Maksym Sloyko96342732021-08-03 21:54:28 +000072
73 local str_en_dir="${gadget_dir}/strings/0x409"
William A. Kennington IIIe1c8b872022-04-04 17:30:48 -070074 mkdir -p "${str_en_dir}" || return
75 echo ${STR_EN_VENDOR} > "${str_en_dir}/manufacturer" || return
76 echo ${STR_EN_PRODUCT} > "${str_en_dir}/product" || return
Maksym Sloyko96342732021-08-03 21:54:28 +000077
78 local config_dir="${gadget_dir}/configs/c.1"
William A. Kennington IIIe1c8b872022-04-04 17:30:48 -070079 mkdir -p "${config_dir}" || return
80 echo 100 > "${config_dir}/MaxPower" || return
81 mkdir -p "${config_dir}/strings/0x409" || return
82 echo "${DEV_TYPE^^}" > "${config_dir}/strings/0x409/configuration" || return
Maksym Sloyko96342732021-08-03 21:54:28 +000083
William A. Kennington IIIf8a77742022-02-28 18:05:54 -080084 local func_dir="${gadget_dir}/functions/${DEV_TYPE}.${IFACE_NAME}"
William A. Kennington IIIe1c8b872022-04-04 17:30:48 -070085 mkdir -p "${func_dir}" || return
Maksym Sloyko96342732021-08-03 21:54:28 +000086
87 if [[ -n $HOST_MAC_ADDR ]]; then
William A. Kennington IIIe1c8b872022-04-04 17:30:48 -070088 echo ${HOST_MAC_ADDR} >${func_dir}/host_addr || return
Maksym Sloyko96342732021-08-03 21:54:28 +000089 fi
90
91 if [[ -n $DEV_MAC_ADDR ]]; then
William A. Kennington IIIe1c8b872022-04-04 17:30:48 -070092 echo ${DEV_MAC_ADDR} >${func_dir}/dev_addr || return
Maksym Sloyko96342732021-08-03 21:54:28 +000093 fi
94
William A. Kennington IIIe1c8b872022-04-04 17:30:48 -070095 ln -s "${func_dir}" "${config_dir}" || return
Maksym Sloyko96342732021-08-03 21:54:28 +000096
William A. Kennington IIIcb3143e2022-05-02 17:06:28 -070097 # This only works on kernel 5.12+, we have to ignore failures for now
98 echo "$IFACE_NAME" >"${func_dir}"/ifname || true
99
William A. Kennington IIIe1c8b872022-04-04 17:30:48 -0700100 echo "${BIND_DEVICE}" >${gadget_dir}/UDC || return
William A. Kennington III882921c2022-05-02 17:05:20 -0700101 # Try to reconfigure a few times in case we race with systemd-networkd
102 local start=$SECONDS
103 while (( SECONDS - start < 5 )); do
104 local ifname
105 ifname="$(<"${func_dir}"/ifname)" || return
106 [ "${IFACE_NAME}" = "$ifname" ] && break
107 ip link set dev "$ifname" down && \
108 ip link set dev "$ifname" name "${IFACE_NAME}" && break
109 sleep 1
110 done
William A. Kennington IIIf08c0cc2022-04-04 19:39:58 -0700111 ip link set dev "$IFACE_NAME" up || return
Maksym Sloyko96342732021-08-03 21:54:28 +0000112}
113
114gadget_stop() {
115 local gadget_dir="${CONFIGFS_HOME}/usb_gadget/${GADGET_DIR_NAME}"
William A. Kennington IIIf8a77742022-02-28 18:05:54 -0800116 rm -f ${gadget_dir}/configs/c.1/${DEV_TYPE}.${IFACE_NAME}
William A. Kennington III0ae2b8f2022-03-31 18:02:30 -0700117 rmdir ${gadget_dir}/functions/${DEV_TYPE}.${IFACE_NAME} \
118 ${gadget_dir}/configs/c.1/strings/0x409 \
119 ${gadget_dir}/configs/c.1 \
120 ${gadget_dir}/strings/0x409 \
121 ${gadget_dir} || true
William A. Kennington IIIa9de0df2022-02-22 17:11:13 -0800122
123 rm -f /run/systemd/network/+-bmc-"${IFACE_NAME}".network
William A. Kennington IIIe1c8b872022-04-04 17:30:48 -0700124 networkctl reload || true
Maksym Sloyko96342732021-08-03 21:54:28 +0000125}
126
127opts=$(getopt \
128 --longoptions "$(printf "%s," "${ARGUMENT_LIST[@]}")" \
129 --name "$(basename "$0")" \
130 --options "" \
131 -- "$@"
132)
133
134eval set --$opts
135
136CONFIGFS_HOME=${CONFIGFS_HOME:-/sys/kernel/config}
137ID_VENDOR="0x18d1" # Google
138ID_PRODUCT=""
139STR_EN_VENDOR="Google"
140STR_EN_PRODUCT=""
141DEV_MAC_ADDR=""
William A. Kennington IIIf8a77742022-02-28 18:05:54 -0800142DEV_TYPE="eem"
Maksym Sloyko96342732021-08-03 21:54:28 +0000143HOST_MAC_ADDR=""
144BIND_DEVICE=""
145ACTION="start"
William A. Kennington III878454a2022-04-04 17:05:05 -0700146GADGET_DIR_NAME=""
William A. Kennington III69ebd2c2022-04-04 17:51:09 -0700147IFACE_NAME=""
Maksym Sloyko96342732021-08-03 21:54:28 +0000148while [[ $# -gt 0 ]]; do
149 case "$1" in
150 --product-id)
151 ID_PRODUCT=$2
152 shift 2
153 ;;
154 --product-name)
155 STR_EN_PRODUCT=$2
156 shift 2
157 ;;
158 --host-mac)
159 HOST_MAC_ADDR=$2
160 shift 2
161 ;;
162 --dev-mac)
163 DEV_MAC_ADDR=$2
164 shift 2
165 ;;
William A. Kennington IIIf8a77742022-02-28 18:05:54 -0800166 --dev-type)
167 DEV_TYPE=$2
168 shift 2
169 ;;
Maksym Sloyko96342732021-08-03 21:54:28 +0000170 --bind-device)
171 BIND_DEVICE=$2
172 shift 2
173 ;;
174 --gadget-dir-name)
175 GADGET_DIR_NAME=$2
176 shift 2
177 ;;
178 --iface-name)
179 IFACE_NAME=$2
180 shift 2
181 ;;
182 --help)
183 print_usage
184 exit 0
185 ;;
186 start)
187 ACTION="start"
188 shift 1
189 break
190 ;;
191 stop)
192 ACTION="stop"
193 shift 1
194 break
195 ;;
196 --)
197 shift 1
198 ;;
199 *)
200 break
201 ;;
202 esac
203done
204
William A. Kennington III878454a2022-04-04 17:05:05 -0700205if [ -z "$GADGET_DIR_NAME" ]; then
206 GADGET_DIR_NAME="$IFACE_NAME"
207fi
208
Maksym Sloyko96342732021-08-03 21:54:28 +0000209if [[ $ACTION == "stop" ]]; then
210 gadget_stop
211else
William A. Kennington III69ebd2c2022-04-04 17:51:09 -0700212 if [ -z "$ID_PRODUCT" ]; then
213 echo "Product ID is missing" >&2
214 exit 1
215 fi
216
217 if [ -z "$IFACE_NAME" ]; then
218 echo "Interface name is missing" >&2
219 exit 1
220 fi
221
222 if [ -z "$BIND_DEVICE" ]; then
223 echo "Bind device is missing" >&2
224 exit 1
225 fi
226
William A. Kennington III986d3a62022-03-31 17:58:30 -0700227 rc=0
228 gadget_start || rc=$?
229 (( rc == 0 )) || gadget_stop || true
230 exit $rc
Maksym Sloyko96342732021-08-03 21:54:28 +0000231fi