#!/usr/bin/zsh
#USB Gadget Manager
#ANTI-CAPITALIST SOFTWARE LICENSE (v 1.4)
#Copyright © 2020 Daniel Nash
#This is anti-capitalist software, released for free use by individuals and organizations that do not operate by capitalist principles. Permission is hereby granted, free of charge, to any person or organization (the "User") obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify, merge, distribute, and/or sell copies of the Software, subject to the following conditions:
#1. The above copyright notice and this permission notice shall be included in all copies or modified versions of the Software. 
#2. The User is one of the following:
#a. An individual person, laboring for themselves
#b. A non-profit organization
#c. An educational institution
#d. An organization that seeks shared profit for all of its members, and allows non-members to set the cost of their labor
#3. If the User is an organization with owners, then all owners are workers and all workers are owners with equal equity and/or equal vote.
#4. If the User is an organization, then the User is not law enforcement or military, or working for or under either. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
export cmd=$1
if [ -z $cmd ];then
echo usage: $0 \<command\> \[name\] \[vendor id\] \[product id\] \[manufacturer\] \[serial number\] \[product name\] \[internal function name\] \[filename, if internal function name uses storage code\]. Any missing parameters will be interactively prompted
exit 1
fi
export name=$2
if [ -z $name ];then
echo enter gadget name
read name
fi
if [ -e /config/usb_gadget ];then
export config=/config/usb_gadget
else
export config=/sys/kernel/config/usb_gadget
fi
export home=$config"/"$name
function init
{
if [ -e $config ];then
true
else
echo configfs directory for USB gadget does not exist, you may need to load the libcomposite module
exit 3
fi
if ls /sys/class/udc|wc -l|grep -qw 0;then
echo this device does not support UDC, which is required to physically bind created functions to hardware. USB Gadget setup cannot continue
rm $name
exit 4
fi
export vid=0x$3
if echo $vid|grep -qw 0x;then
echo enter vendor id for $name
read vidnum
export vid="0x"$vidnum
fi
export pid=0x$4
if echo $pid|grep -qw 0x;then
echo enter product id for $name
read pnum
export pid="0x"$pnum
fi
export manufacturer=$5
if [ -z $manufacturer ];then
echo enter reported manufacturer for $name
read manufacturer
fi
export serial=$6
if [ -z $serial ];then
echo enter reported serial number for $name
read serial
fi
export product=$7
if [ -z $product ];then
echo enter reported product name for $name
read product
fi
export initfunc=$8
if [ -z $initfunc ];then
echo select initial function for for $name
echo 1: acm: usb terminal
echo 2: cdrom: CD/DVD ROM Storage
echo 3: hid: HID Keyboard
echo 4: Net: Network Device/USB Ethernet
echo 5: rostorage: Read Only Storage device
echo 6: rwstorage: Read/Write Storage, like a flash drive
echo 7: null: no initial function
read funcanswer
case "$funcanswer" in
1)
export initfunc=acm
;;
2)
export initfunc=cdrom
export file=$9
if [ -z $file ];then
echo enter full path for this simulated $initfunc device
read file
fi
;;
3)
export initfunc=hid
;;
4)
export initfunc=net
;;
5)
export initfunc=rostorage
export file=$9
if [ -z $file ];then
echo enter full path for this simulated $initfunc device
read file
fi
;;
6)
export initfunc=rwstorage
export file=$9
if [ -z $file ];then
echo enter full path for this simulated $initfunc device
read file
fi
;;
7)
true
;;
esac
fi
if [ -d $home ];then
echo gadget $name already exists
return 1
else
mkdir -p $home/strings/0x409
echo $vid > $home/idVendor
echo $pid > $home/idProduct
echo $manufacturer > $home/strings/0x409/manufacturer
echo $serial > $home/strings/0x409/serialnumber
echo $product > $home/strings/0x409/product
export n=$(($(ls $home/functions|wc -l)+1))
mkdir -p $home/configs/c.$n
case "$initfunc" in
acm)
acm
;;
cdrom)
storage $file cdrom
;;
hid)
hid
;;
net)
net
;;
null)
true
;;
rostorage)
storage $file ro
;;
rwstorage)
storage $file rw
;;
*)
echo function $initfunc not implemented
return 2
;;
esac
fi
}
function rm
{
echo > $home/UDC 
find $home -delete 2>/dev/null
}
function acm
{
echo > $home/UDC 
mkdir -p $home/functions/acm.usb$n
ln -s $home/functions/acm.usb$n $home/configs/c.$n
}
function hid
{
echo > $home/UDC 
mkdir -p $home/functions/hid.usb$n
echo 1 > $home/functions/hid.usb$n/protocol
echo 1 > $home/functions/hid.usb$n/subclass
echo 8 > $home/functions/hid.usb$n/report_length
echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > $home/functions/hid.usb$n/report_desc
ln -s $home/functions/hid.usb$n $home/configs/c.$n
echo `ls /sys/class/udc|head -n 1` > $home/UDC 
}
function net
{
echo > $home/UDC 
mkdir -p $home/functions/ecm.usb0
printf "%02x:%02x:%02x:%02x:%02x:%02x" $(($RANDOM&0xf)) $(($RANDOM&0xff)) $(($RANDOM&0xff)) $(($RANDOM&0xff)) $(($RANDOM&0xff)) $(($RANDOM&0xff)) > $home/functions/ecm.usb0/host_addr
printf "%02x:%02x:%02x:%02x:%02x:%02x" $(($RANDOM&0xf)) $(($RANDOM&0xff)) $(($RANDOM&0xff)) $(($RANDOM&0xff)) $(($RANDOM&0xff)) $(($RANDOM&0xff)) > $home/functions/ecm.usb0/dev_addr
ln -s $home/functions/ecm.usb0 $home/configs/c.$n
echo `ls /sys/class/udc|head -n 1` > $home/UDC 
}
function storage
{
export file=$1
export mode=$2
echo > $home/UDC 
mkdir -p $home/functions/mass_storage.usb$n
echo 1 > $home/functions/mass_storage.usb$n/stall
case "$mode" in
cdrom)
echo 1 > $home/functions/mass_storage.usb$n/lun.0/cdrom
echo 1 > $home/functions/mass_storage.usb$n/lun.0/ro
;;
ro)
echo 0 > $home/functions/mass_storage.usb$n/lun.0/cdrom
echo 1 > $home/functions/mass_storage.usb$n/lun.0/ro
;;
rw)
echo 0 > $home/functions/mass_storage.usb$n/lun.0/cdrom
echo 0 > $home/functions/mass_storage.usb$n/lun.0/ro
;;
*)
echo 0 > $home/functions/mass_storage.usb$n/lun.0/cdrom
echo 0 > $home/functions/mass_storage.usb$n/lun.0/ro
;;
esac
echo 0 > $home/functions/mass_storage.usb$n/lun.0/nofua
echo $file > $home/functions/mass_storage.usb$n/lun.0/file
ln -s $home/functions/mass_storage.usb$n $home/configs/c.$n
echo `ls /sys/class/udc|head -n 1` > $home/UDC 
}
case "$cmd" in
init)
init $@
;;
rm)
rm $@
;;
acm)
export n=$(($(ls $home/functions|wc -l)+1))
mkdir -p $home/configs/c.$n
acm
;;
cdrom)
export n=$(($(ls $home/functions|wc -l)+1))
mkdir -p $home/configs/c.$n
storage $3 cdrom
;;
hid)
export n=$(($(ls $home/functions|wc -l)+1))
mkdir -p $home/configs/c.$n
hid
;;
net)
export n=$(($(ls $home/functions|wc -l)+1))
mkdir -p $home/configs/c.$n
net
;;
rostorage)
export n=$(($(ls $home/functions|wc -l)+1))
mkdir -p $home/configs/c.$n
storage $3 ro
;;
rwstorage)
export n=$(($(ls $home/functions|wc -l)+1))
mkdir -p $home/configs/c.$n
storage $3 rw
;;
storage)
export n=$(($(ls $home/functions|wc -l)+1))
mkdir -p $home/configs/c.$n
storage $3 rw
;;
esac
