Skip to content

Commit

Permalink
Added USB gadget configuration to CLI, ToDo: validation (avoid kernel…
Browse files Browse the repository at this point in the history
… panic by consuming too many endpoints); auto-deploy by default
  • Loading branch information
mame82 committed May 4, 2018
1 parent 064ac0e commit b7092eb
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 23 deletions.
107 changes: 89 additions & 18 deletions cli_client/cmd_usb.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"github.com/spf13/cobra"
"log"

"github.com/davecgh/go-spew/spew"
)

//Empty settings used to store cobra flags
var (
//tmpGadgetSettings = pb.GadgetSettings{CdcEcmSettings:&pb.GadgetSettingsEthernet{},RndisSettings:&pb.GadgetSettingsEthernet{}}
tmpDisableGadget bool = false
tmpUseHIDKeyboard uint8 = 0
tmpUseHIDMouse uint8 = 0
tmpUseHIDRaw uint8 = 0
Expand All @@ -19,6 +21,12 @@ var (
tmpUseUMS uint8 = 0
)

func init(){
//Configure spew for struct deep printing (disable using printer interface for gRPC structs)
spew.Config.Indent="\t"
spew.Config.DisableMethods = true
spew.Config.DisablePointerAddresses = true
}

// usbCmd represents the usb command
var usbCmd = &cobra.Command{
Expand All @@ -33,6 +41,20 @@ var usbGetCmd = &cobra.Command{
Run: cobraUsbGet,
}

var usbGetDeployedCmd = &cobra.Command{
Use: "deployed",
Short: "Get deployed USB Gadget settings (the currently running configuration for the kernel module)",
Long: ``,
Run: cobraUsbGetDeployed,
}

var usbSetDeployeCmd = &cobra.Command{
Use: "deploy",
Short: "Deployed the USB Gadget settings (as running configuration for the kernel module)",
Long: ``,
Run: cobraUsbDeploySettings,
}

var usbSetCmd = &cobra.Command{
Use: "set",
Short: "set USB Gadget settings",
Expand All @@ -47,7 +69,15 @@ func cobraUsbSet(cmd *cobra.Command, args []string) {
return
}

fmt.Printf("USB Gadget Settings retreived: %+v\n", gs)
fmt.Printf("Old USB Gadget Settings:\n%s", spew.Sdump(gs))

if tmpDisableGadget {
fmt.Println("Gadget set to disabled (won't get bound to UDC after deployment)")
gs.Enabled = false
} else {
fmt.Println("Gadget set to enabled (will be usable after deployment)")
gs.Enabled = true
}

if (cmd.Flags().Lookup("rndis").Changed) {
if tmpUseRNDIS == 0 {
Expand All @@ -60,7 +90,7 @@ func cobraUsbSet(cmd *cobra.Command, args []string) {
}

if (cmd.Flags().Lookup("cdc-ecm").Changed) {
if tmpUseRNDIS == 0 {
if tmpUseECM == 0 {
fmt.Println("Disabeling CDC ECM")
gs.Use_CDC_ECM = false
} else {
Expand All @@ -70,7 +100,7 @@ func cobraUsbSet(cmd *cobra.Command, args []string) {
}

if (cmd.Flags().Lookup("serial").Changed) {
if tmpUseRNDIS == 0 {
if tmpUseSerial == 0 {
fmt.Println("Disabeling Serial")
gs.Use_SERIAL = false
} else {
Expand All @@ -80,7 +110,7 @@ func cobraUsbSet(cmd *cobra.Command, args []string) {
}

if (cmd.Flags().Lookup("hid-keyboard").Changed) {
if tmpUseRNDIS == 0 {
if tmpUseHIDKeyboard == 0 {
fmt.Println("Disabeling HID keyboard")
gs.Use_HID_KEYBOARD = false
} else {
Expand All @@ -89,8 +119,38 @@ func cobraUsbSet(cmd *cobra.Command, args []string) {
}
}

if (cmd.Flags().Lookup("hid-mouse").Changed) {
if tmpUseHIDMouse == 0 {
fmt.Println("Disabeling HID mouse")
gs.Use_HID_MOUSE = false
} else {
fmt.Println("Enabeling HID mouse")
gs.Use_HID_MOUSE = true
}
}

//ToDo: Implement the rest (HID, UMS etc.)
if (cmd.Flags().Lookup("hid-raw").Changed) {
if tmpUseHIDRaw == 0 {
fmt.Println("Disabeling HID raw device")
gs.Use_HID_RAW = false
} else {
fmt.Println("Enabeling HID raw device")
gs.Use_HID_RAW = true
}
}

if (cmd.Flags().Lookup("ums").Changed) {
if tmpUseUMS == 0 {
fmt.Println("Disabeling USB Mass Storage")
gs.Use_UMS = false
} else {
fmt.Println("Enabeling USB Mass Storage")
gs.Use_UMS = true
}
}


//ToDo: Implement detailed UMS settings

//Try to set the change config
err = ClientSetGadgetSettings(StrRemoteHost, StrRemotePort, *gs)
Expand All @@ -104,34 +164,45 @@ func cobraUsbSet(cmd *cobra.Command, args []string) {
return
}

fmt.Printf("USB Gadget Settings set: %+v\n", gs)
fmt.Printf("New USB Gadget Settings:\n%s", spew.Sdump(gs))
return
}

func cobraUsbGet(cmd *cobra.Command, args []string) {
if gs, err := ClientGetGadgetSettings(StrRemoteHost, StrRemotePort); err == nil {
fmt.Printf("USB Gadget Settings: %+v\n", gs)
fmt.Printf("USB Gadget Settings:\n%s", spew.Sdump(gs))
} else {
log.Println(err)
}
}

func init() {
rootCmd.AddCommand(usbCmd)
usbCmd.AddCommand(usbGetCmd)
usbCmd.AddCommand(usbSetCmd)
func cobraUsbDeploySettings(cmd *cobra.Command, args []string) {

if gs, err := ClientDeployGadgetSettings(StrRemoteHost, StrRemotePort); err != nil {
fmt.Printf("Error deploying Gadget Settings: %v\nReverted to:\n%s", err, spew.Sdump(gs))
} else {
fmt.Printf("Successfully deployed:\n%s", spew.Sdump(gs))
}

// Here you will define your flags and configuration settings.
}

// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// usbCmd.PersistentFlags().String("foo", "", "A help for foo")

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// usbCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
func cobraUsbGetDeployed(cmd *cobra.Command, args []string) {
if gs, err := ClientGetDeployedGadgetSettings(StrRemoteHost, StrRemotePort); err == nil {
fmt.Printf("Deployed USB Gadget Settings:\n%s", spew.Sdump(gs))
} else {
log.Println(err)
}
}

func init() {
rootCmd.AddCommand(usbCmd)
usbCmd.AddCommand(usbGetCmd)
usbCmd.AddCommand(usbSetCmd)
usbGetCmd.AddCommand(usbGetDeployedCmd)
usbSetCmd.AddCommand(usbSetDeployeCmd)

usbSetCmd.Flags().BoolVarP(&tmpDisableGadget, "disabled","d", false, "If this option is set, the gadget stays inactive after deployment (not bound to UDC)")
usbSetCmd.Flags().Uint8VarP(&tmpUseRNDIS, "rndis", "n",0,"Use the RNDIS gadget function (0: disable, 1..n: enable)")
usbSetCmd.Flags().Uint8VarP(&tmpUseECM, "cdc-ecm", "e",0,"Use the CDC ECM gadget function (0: disable, 1..n: enable)")
usbSetCmd.Flags().Uint8VarP(&tmpUseSerial, "serial", "s",0,"Use the SERIAL gadget function (0: disable, 1..n: enable)")
Expand Down
34 changes: 34 additions & 0 deletions cli_client/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,40 @@ func ClientGetGadgetSettings(host string, port string) (gs *pb.GadgetSettings, e
}

gs, err = client.GetGadgetSettings(ctx, &pb.Empty{})
if err != nil {
log.Printf("Error getting USB Gadget Settings: %+v", err)
}

ClientDisconnectServer(cancel, conn)
return
}

func ClientDeployGadgetSettings(host string, port string) (gs *pb.GadgetSettings, err error) {
conn, client, ctx, cancel, err := ClientConnectServer(host, port)
if err != nil {
return
}
defer ClientDisconnectServer(cancel, conn)

gs, err = client.DeployGadgetSetting(ctx, &pb.Empty{})
if err != nil {
log.Printf("Error deploying current USB Gadget Settings: %+v", err)
//We have an error case, thus gs isn't submitted by the gRPC server (even if the value is provided)
//in case of an error `gs`should reflect the Gadget Settings which are deployed, now that deployment of the
//new settings failed. So we fetch the result manually
gs, _ = client.GetDeployedGadgetSetting(ctx, &pb.Empty{}) //We ignore a new error this time, if it occures `gs` will be nil
}

return
}

func ClientGetDeployedGadgetSettings(host string, port string) (gs *pb.GadgetSettings, err error) {
conn, client, ctx, cancel, err := ClientConnectServer(host, port)
if err != nil {
return
}

gs, err = client.GetDeployedGadgetSetting(ctx, &pb.Empty{})
if err != nil {
log.Printf("Error getting USB Gadget Settings count: %+v", err)
}
Expand Down
4 changes: 4 additions & 0 deletions service/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ func (s *server) GetDeployedGadgetSetting(ctx context.Context, e *pb.Empty) (gs

func (s *server) DeployGadgetSetting(context.Context, *pb.Empty) (gs *pb.GadgetSettings, err error) {
gs_backup,_ := ParseGadgetState(USB_GADGET_NAME)

//ToDo: Former gadgets are destroyed without testing if there're changes, this should be aborted if GadgetSettingsState == GetDeployedGadgetSettings()
DestroyGadget(USB_GADGET_NAME)

errg := DeployGadgetSettings(GadgetSettingsState)
err = nil
if errg != nil {
Expand Down
16 changes: 11 additions & 5 deletions service/usb.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ var (

func ValidateGadgetSetting(gs pb.GadgetSettings) error {
/* ToDo: validations
- check host_addr/dev_addr of RNDIS + CDC ECM to be valid MAC adresses via regex
- check host_addr/dev_addr of RNDIS + CDC ECM to be valid MAC addresses via regex
- check host_addr/dev_addr of RNDIS + CDC ECM for duplicates
- check EP consumption to be not more than 7 (ECM 2 EP, RNDIS 2 EP, HID Mouse 1 EP, HID Keyboard 1 EP, HID Raw 1 EP, Serial 2 EP ??, UMS ??)
- check serial, product, Manufacturer to not be empty
Expand Down Expand Up @@ -200,8 +200,6 @@ func getUDCName() (string, error) {
func ParseGadgetState(gadgetName string) (result *pb.GadgetSettings, err error) {
err = nil
result = &pb.GadgetSettings{}
result.CdcEcmSettings = &pb.GadgetSettingsEthernet{}
result.RndisSettings = &pb.GadgetSettingsEthernet{}

//gadget_root := "./test"
gadget_dir := USB_GADGET_DIR_BASE + "/" + gadgetName
Expand Down Expand Up @@ -256,6 +254,8 @@ func ParseGadgetState(gadgetName string) (result *pb.GadgetSettings, err error)
if _, err1 := os.Stat(gadget_dir+"/configs/c.1/rndis.usb0"); !os.IsNotExist(err1) {
result.Use_RNDIS = true

result.RndisSettings = &pb.GadgetSettingsEthernet{}

if res, err := ioutil.ReadFile(gadget_dir + "/functions/rndis.usb0/host_addr"); err != nil {
err1 := errors.New(fmt.Sprintf("Gadget %s error reading RNDIS host_addr", gadgetName))
return nil, err1
Expand All @@ -275,6 +275,8 @@ func ParseGadgetState(gadgetName string) (result *pb.GadgetSettings, err error)
if _, err1 := os.Stat(gadget_dir+"/configs/c.1/ecm.usb1"); !os.IsNotExist(err1) {
result.Use_CDC_ECM = true

result.CdcEcmSettings = &pb.GadgetSettingsEthernet{}

if res, err := ioutil.ReadFile(gadget_dir + "/functions/ecm.usb1/host_addr"); err != nil {
err1 := errors.New(fmt.Sprintf("Gadget %s error reading CDC ECM host_addr", gadgetName))
return nil, err1
Expand Down Expand Up @@ -319,6 +321,7 @@ func ParseGadgetState(gadgetName string) (result *pb.GadgetSettings, err error)
return nil, err1
} else {
udc_name_set := strings.TrimSuffix(string(res), "\n")
log.Printf("UDC test: udc_name_set %s, udc_name %s", udc_name_set, udc_name)
if udc_name == udc_name_set {
result.Enabled = true
}
Expand All @@ -343,7 +346,7 @@ func DeployGadgetSettings(settings pb.GadgetSettings) error {

//create gadget folder
os.Mkdir(USB_GADGET_DIR, os.ModePerm)
log.Printf("Creating composite gadget '%s'", USB_GADGET_NAME)
log.Printf("Creating composite gadget '%s'\nSettings:\n%+v", USB_GADGET_NAME, settings)

//set vendor ID, product ID
ioutil.WriteFile(USB_GADGET_DIR+"/idVendor", []byte(settings.Vid), os.ModePerm)
Expand Down Expand Up @@ -495,7 +498,10 @@ func DeployGadgetSettings(settings pb.GadgetSettings) error {
if err != nil {
return err
}
ioutil.WriteFile(USB_GADGET_DIR+"/UDC", []byte(udc_name), os.ModePerm)
log.Printf("Enabeling gadget for UDC: %s\n", udc_name)
if err = ioutil.WriteFile(USB_GADGET_DIR+"/UDC", []byte(udc_name), os.ModePerm); err != nil {
return err
}
}


Expand Down

0 comments on commit b7092eb

Please sign in to comment.