尝试写gadget zero驱动

gadget zero驱动可以用于usb通道测试, 也可以用于gadget 驱动参考。

 

他的功能如下:

1. 他是个双配置的usb设备

     配置1: 有一个接口, 一个altsetting(即没有备选设置)

                接口内有两个bulk端点, 分别对应in/out

     配置2: 一个接口, 两个altsetting,即有两种设置

               设置1: Bulk In + Bulk Out

               设置2: Isoch In + Isoch Out

 

2. 如果内核参数 loopdefaut = 1, 实现loopback回环功能。

即out端点数据发送给in端点。 

也即主机端通过OUT端点发送的数据又可以通过IN端点获取。

 

3. 如何编写gadget zero驱动, 以前直接注册usb_gadget_driver并实现相关回调函数, 

利用gadget api实现descriptor, 控制端点功能及Bulk, Isoch端点功能即可。

最新Linux内核中更改了结构, 内部需要使用f_sourcesink及f_loopback模块。

故后续再去写gadget zero驱动...

 

 

4. 这里主要针对主机端如何进行usb gadget zero回环测试进行说明。

    windows 自带驱动无法识别gadget zero驱动,  网上也未找到。

    Linux主机自带usbtest.ko驱动(drivers/usb/misc/usbtest.c)

    用户态有对应测试程序, 请参考 http://www.linux-usb.org/usbtest/


    由于g_zero是个lagency驱动,  最新版本尝试几次遇到一些问题, 就不去使用usbtest.ko了。

    直接基于usb_skeleton.ko和libusb实现两套可运行的程序。

 

* 基于usb_skeleton.ko, 很简单, 更改下id_table使加载即可....

 #define USB_SKEL_VENDOR_ID› 0x0525                                                                          
 #define USB_SKEL_PRODUCT_ID› 0xa4a0


拔出usb线,
insmod usb_skeleton.ko
插入usb线,

ok...  主机端就会优先加载usb_skeleton驱动, 而不去使用usbtest驱动了。

文件系统产生/dev/skel0节点


echo 123456 > /dev/skel0

cat /dev/skel0

(如果设备端配置了loopdefaut=1, 就能看到loopback的数据)
123456

* 基于libusb自己写个用户态程序, 如下:

#include <stdio.h>
#include <string.h>
#include <libusb.h>

#define TIMEOUT 2000
#define STR_LEN 20

int main(int argc, char *argv[]) {
    int ret = 0;
    libusb_device_handle *handle;
    libusb_device **list;
    libusb_device *usbdev;
    struct libusb_device_descriptor dev_desc;
    struct libusb_config_descriptor *config_desc;
    const struct libusb_endpoint_descriptor *ep_desc;
    unsigned char ep_bulkin = 0 , ep_bulkout = 0;
    int i = 0, is_match = 0;
    int ep_cnt;
    char send_data[STR_LEN] = {0,};
    char recv_data[STR_LEN] = {0,};
    int transfered = 0;
    int count = 0;

    ret = libusb_init(NULL);
    if (ret < 0) {
        fprintf(stderr, "libusb_init failed, ret(%d)\n", ret);

        return -1;
    }

    // get usb device list
    ret = libusb_get_device_list(NULL, &list);
    if (ret < 0) {
        fprintf(stderr, "libusb_get_device_list failed,"
                "ret(%d)\n", ret);

        goto get_failed;
    }

    /* print/check the matched device */
    while ((usbdev = list[i++]) != NULL) {
        libusb_get_device_descriptor(usbdev, &dev_desc);

#if 0
        printf("usb-%d: pid(0x%x), vid(0x%x)\n",
               i++,
               dev_desc.idVendor,
               dev_desc.idProduct);
#endif

        if (dev_desc.idVendor == 0x0525 &&
                dev_desc.idProduct == 0xa4a0) {
            printf("match, break!\n");
            is_match = 1;
            break;
        }
    }

    if (!is_match) {
        fprintf(stderr, "no matched usb device...\n");

        goto match_fail;
    }

    /* open usb device */
    ret = libusb_open(usbdev, &handle);
    if (ret < 0) {
        fprintf(stderr, "libusb_open failed. ret(%d)\n", ret);

        goto open_failed;
    }

    printf("this usb device has %d configs, "
            "but still use default config 0\n",
            dev_desc.bNumConfigurations);

    /* get config descriptor */
    ret = libusb_get_config_descriptor(usbdev, 1, &config_desc);
    if (ret < 0) {
        fprintf(stderr, "get config descriptor failed...\n");
        goto configdesc_fail;
    }

    printf("the config has %d interface..."
            "just use the 1st interface this time\n",
            config_desc->bNumInterfaces);

    ep_cnt = config_desc->interface->altsetting[0].bNumEndpoints;

    printf("this interface has %d endpoint\n", ep_cnt);

    /* get bulk in/out ep */
    for (i=0; i<ep_cnt; i++) {
        ep_desc = &config_desc->interface->altsetting[0].endpoint[i];
        if ((ep_desc->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) & LIBUSB_TRANSFER_TYPE_BULK) {
            if ((ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) & LIBUSB_ENDPOINT_IN)  {
                if (!ep_bulkin) {
                    ep_bulkin = ep_desc->bEndpointAddress;
                }
            } else {
                if (!ep_bulkout) {
                    ep_bulkout = ep_desc->bEndpointAddress;
                }
            }

            printf("ep_addr = 0x%x\n", ep_desc->bEndpointAddress);
        }
    }

    if (ep_bulkin) {
        printf("yes, got 1 bulk in endppint!\n");
    }

    if (ep_bulkout) {
        printf("yes, got 1 bulk out endppint!\n");
    }

    /* claim the interface */
    printf("claim usb interface\n");
    ret = libusb_claim_interface(handle, 0);
    if (ret < 0) {
        printf("claim usb interface failed... ret(%d)\n", ret);
        goto claim_failed;
    }


    printf("start bulk transfer...\n");
    /* use bulk trandfer data directly */
    while (count++ < 20) {
        snprintf(send_data, STR_LEN, "hello,world - %d", count);
        ret = libusb_bulk_transfer(handle, ep_bulkout, (unsigned char*)send_data, sizeof(send_data),
                &transfered, TIMEOUT);

        if (ret == 0) {
            ret = libusb_bulk_transfer(handle, ep_bulkin, (unsigned char *)recv_data,
                    sizeof(recv_data), &transfered, TIMEOUT);

            if (ret == 0) {
                printf("recv: %s\n", recv_data);
            } else {
                printf("bulk in failed, ret(%d), transfered(%d)\n",
                        ret, transfered);
            }
        } else {
            printf("bulk out failed, ret(%d), transfered(%d)\n",
                    ret, transfered);
        }
    }

    // libusb_open(dev, &handle);
    libusb_close(handle);

    libusb_free_device_list(list, 1);

    libusb_exit(NULL);

    return 0;

configdesc_fail:
claim_failed:
    libusb_close(handle);

open_failed:
match_fail:
    libusb_free_device_list(list, 1);

get_failed:
    libusb_exit(NULL);

    return ret;
}
CC=gcc
CFLAGS=-g -Wall
CFLAGS+=`pkg-config --cflags libusb-1.0`
LDFLAGS=`pkg-config --libs libusb-1.0`

target=usbtest
objs=$(patsubst %.c, %.o, $(wildcard *.c))

all:$(target)

$(target):$(objs)
	$(CC) $^ -o $@ $(LDFLAGS)

.c.o:
	$(CC) -c $< $(CFLAGS)

.PHONY:
	clean

clean:
	rm *.o $(target) -rf

ok... 程序相对简单, 记录下libusb的函数调用

- libusb_init

- libusb_get_device_list    // 获取设备列表, 返回设备数组

- libusb_get_device_descriptor    // 获取设备描述符, 该结构体下面能找到配置, 接口, 端点,  字符串等描述符

- libusb_open     // 打开设备

- 查看描述信息, 选择自己要用的配置项, libusb_set_configuration

- libusb_claim_interface    // claim(认领, 索取)一个接口,  这个函数是必须调用的, 否则会有一些warning

- libusb_bulk_transfer      // bulk传输, 其他控制, 登时有对应接口

- ****释放各种资源的函数,  暂不列举了....

 

ok,  就写这么多, 后面尽快写个gadget 驱动程序... 以加深gadget api相关。

上一篇:USB DEVICE


下一篇:Fortigate SSLVPN漏洞分析和利用