diff --git a/cli_client/cmd_usb.go b/cli_client/cmd_usb.go index 6b68362..6c01f87 100644 --- a/cli_client/cmd_usb.go +++ b/cli_client/cmd_usb.go @@ -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 @@ -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{ @@ -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", @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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) @@ -104,13 +164,32 @@ 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 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)) + } + +} + + +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) } @@ -120,18 +199,10 @@ func init() { rootCmd.AddCommand(usbCmd) usbCmd.AddCommand(usbGetCmd) usbCmd.AddCommand(usbSetCmd) + usbGetCmd.AddCommand(usbGetDeployedCmd) + usbSetCmd.AddCommand(usbSetDeployeCmd) - // 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") - - + 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)") diff --git a/cli_client/rpc.go b/cli_client/rpc.go index 359d788..17a0209 100644 --- a/cli_client/rpc.go +++ b/cli_client/rpc.go @@ -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) } diff --git a/service/rpc.go b/service/rpc.go index d9e6454..9f707e6 100644 --- a/service/rpc.go +++ b/service/rpc.go @@ -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 { diff --git a/service/usb.go b/service/usb.go index 10fbf3b..e0b866e 100644 --- a/service/usb.go +++ b/service/usb.go @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 } @@ -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) @@ -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 + } }