diff --git a/dongle.c b/dongle.c index 90ea905939898e80dc6262e35e40d6b2e3ee7410..43995bdcb7f9b66a2511c1107877559af77a603e 100644 --- a/dongle.c +++ b/dongle.c @@ -7,27 +7,36 @@ struct ubus_context *global_ctx; int debug; struct uloop_timeout timeout = { .cb = devices_status }; - static struct option long_options[] = { {"debug", required_argument, NULL, 'd'}, {0, 0, 0, 0} }; -void uloop_add_get_devices(struct uloop_timeout *t) -{ - uloop_timeout_set(t, 5000); - uloop_timeout_add(t); -} +enum { + DEV, + __DEV_MAX +}; + +const struct blobmsg_policy dev_policy[__DEV_MAX] = { + [DEV] = {.name = "dev", .type = BLOBMSG_TYPE_STRING}, +}; + +LIST_HEAD(devices); +LIST_HEAD(stack); +LIST_HEAD(visited); int parse_args(int argc, char **argv) { char ch; - while ((ch = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) { - switch (ch) { + while ((ch = getopt_long(argc, argv, "d:", long_options, NULL)) != -1) + { + switch (ch) + { case 'd': debug = atoi(optarg); - if (debug > 1 || debug < 0) { + if (debug > 1 || debug < 0) + { printf("%s: option '-%c' is invalid.\n", argv[0], optopt); //cant exactly do debug print in here... goto fail; } @@ -47,6 +56,514 @@ fail: return -1; } +int devices_status(struct uloop_timeout *t) +{ + get_devices(); + tag_missing_devices(); + + uloop_add_get_devices(t); + + return 0; +} + +int tag_missing_devices(void) +{ + struct device *dev, *tmp; + + list_for_each_entry_safe(dev, tmp, &devices, list) { + if (dev->present) { + dev->missing = 0; + dev->present = false; + continue; + } + + dev->missing++; + if (dev->missing == 1) + delete_device(dev); + } + + return 0; +} + +int add_device(struct device *new_dev) +{ + struct device *dev; + + dev = search_list(new_dev->usb.if_name); + if (dev) { + if (dev->ip) + free(dev->ip); + dev->ip = new_dev->ip; + + dev->present = true; + goto already_present; + } + + new_dev->present = true; + if (list_empty(&devices)) + INIT_LIST_HEAD(&devices); + + list_add_tail(&new_dev->list, &devices); + if (new_dev->ip) { + new_dev->ubus_obj = dongle_create_dynamic_object(new_dev); + if (new_dev->ubus_obj) + publish_ubus_object(global_ctx, new_dev->ubus_obj); + } + + return 0; +already_present: + return -1; +} + +int delete_all_devices(void) +{ + struct device *dev, *tmp; + + list_for_each_entry_safe(dev, tmp, &devices, list) { + delete_device(dev); + } + + return 0; +} + +int delete_device_by_name(char *name) +{ + struct device *dev, *tmp; + + list_for_each_entry_safe(dev, tmp, &devices, list) { + if (strncmp(dev->usb.if_name, name, 128) != 0) + continue; + + delete_device(dev); + return 0; + } + + return -1; +} + +int delete_device(struct device *dev) +{ + if (dev->ubus_obj) + unpublish_ubus_object(global_ctx, dev->ubus_obj); + // is it necessary to check if list contains this node? + list_del(&dev->list); + free_device(dev); + return 0; +} + +void free_device(struct device *dev) +{ + if (!dev) + return; + free(dev->ip); + free(&(dev->usb)); +} + +void free_usb(struct USB *usb) +{ + if (!usb) + return; + free(usb->product); + free(usb->product_id); + free(usb->vendor_id); + free(usb->if_name); +} + +struct device *search_list(char *name) +{ + struct device *dev; + + list_for_each_entry(dev, &devices, list) { + if (strncmp(name, dev->usb.if_name, 128) == 0) + return dev; + } + return NULL; +} + +char *lexer(char **input, char *delimiter) +{ + char *token, *substr; + + if (strlen(*input) == 0) { + debug_print("empty input!\n"); + return NULL; + } else if (strlen(delimiter) == 0) { + debug_print("empty delimiter!\n"); + return NULL; + } + + token = strstr(*input, delimiter); + + if (token) { + *token = '\0'; + substr = strdup(*input); + if (!substr) { + perror("strdup"); + goto fail_strdup; + } + + *input = token + strlen(delimiter); + } else { + substr = strdup(*input); + if (!substr) { + perror("strdup"); + goto fail_strdup; + } + + *input[0] = '\0'; + } + +fail_strdup: + return substr; +} + +void remove_newline(char *input) +{ + char *pos; + + pos = strchr(input, '\n'); + if (!pos) + return; + + *pos = '\0'; +} + +char *get_usb_stat(char *path, char *dir, char *stat) +{ + char stat_path[PATH_MAX], contents[1024]; + FILE *f; + + snprintf(stat_path, PATH_MAX, "%s/%s/%s", path, dir, stat); + f = fopen(stat_path, "r"); + if (!f) { + perror("fopen"); + goto fail; + } + + fgets(contents, 1024, f); + remove_newline(contents); + fclose(f); + + return strdup(contents); +fail: + return NULL; +} + +char *get_device_name(char *dir_name) +{ + char path[PATH_MAX], *name = NULL; + struct directory *dr, *sub_dr; + struct dirent *de; + struct stat st; + DIR *dir; + + dr = (struct directory *)malloc(sizeof(*dr)); + if (!dr) { + perror("malloc"); + goto fail_dr; + } + + dr->path = strdup(dir_name); + if (!dr->path) + goto fail_path; + + push(dr, &stack); + + while (!list_empty(&stack) && !name) { + dr = pop(&stack); + dir = opendir(dr->path); + if (!dir) + continue; + + push(dr, &visited); + + while ((de = readdir(dir)) != NULL) { + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + continue; + + if (fstatat(dirfd(dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { + perror("fstatat"); + continue; + } + + if (!S_ISDIR(st.st_mode)) + continue; + + if (!strstr(dr->path, "net")) { + snprintf(path, PATH_MAX, "%s%s/", dr->path, de->d_name); + + if (search(path, &visited)) + continue; + + sub_dr = (struct directory *)malloc(sizeof(*sub_dr)); + if (!sub_dr) { + perror("malloc"); + continue; + } + + sub_dr->path = strdup(path); + if (!sub_dr->path) { + free(sub_dr); + continue; + } + + push(sub_dr, &stack); + continue; + } + + if (!strstr(de->d_name, "eth") && !strstr(de->d_name, "usb")) + break; + + name = strdup(de->d_name); + // how to manage failure on this strdup + break; + } + closedir(dir); + } + + clear_list(&visited); + clear_list(&stack); + return name; +fail_path: + free(dr); +fail_dr: + return NULL; +} + +int get_devices(void) +{ + char usb_path[PATH_MAX], product_path[PATH_MAX], path[PATH_MAX], *name; + struct dirent *de; + DIR *dir; + struct stat st; + struct device *dev; + int rv; + + strncpy(usb_path, "/sys/bus/usb/devices/", PATH_MAX); + dir = opendir(usb_path); + if (!dir) { + perror("opendir"); + goto fail_dr; + } + while ((de = readdir(dir)) != NULL) { + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + continue; + if (strstr(de->d_name, ":") || strstr(de->d_name, "usb")) + continue; + + snprintf(product_path, PATH_MAX, "%s%s/product", usb_path, de->d_name); + memset(&st, 0, sizeof(st)); + + rv = stat(product_path, &st); + if (rv < 0) { + //perror("stat"); + continue; + } + + snprintf(path, PATH_MAX, "%s%s/", usb_path, de->d_name); + name = get_device_name(path); + if (!name) + continue; + + dev = (struct device *)calloc(1, sizeof(*dev)); + if (!dev) { + perror("calloc"); + goto fail_dev; + } + + dev->usb.product = get_usb_stat(usb_path, de->d_name, "product"); + dev->usb.product_id = get_usb_stat(usb_path, de->d_name, "idProduct"); + dev->usb.vendor_id = get_usb_stat(usb_path, de->d_name, "idVendor"); + dev->usb.if_name = name; + dev->ip = get_device_ip(dev->usb.if_name); + + add_device(dev); + } + + closedir(dir); + return 0; +fail_dev: + closedir(dir); +fail_dr: + return -1; +} + +char *get_device_ip(char *device_name) +{ + char *iface, *destination, *gateway, *flags, *route, *ipv4_addr = NULL; + bool host_flag; + struct in_addr addr; + FILE *fp; + + fp = fopen("/proc/net/route", "r"); + if (!fp) { + perror("fopen"); + goto fail; + } + + route = (char *)malloc(1024); + if (!route) { + perror("malloc"); + goto fail_route; + } + memset(route, 0, 1024); + while ((fgets(route, 1024, fp)) != NULL) { + remove_newline(route); + + iface = lexer(&route, "\t"); + destination = lexer(&route, "\t"); + gateway = lexer(&route, "\t"); + flags = lexer(&route, "\t"); + + if (strncmp(iface, device_name, 10) != 0) + continue; + + host_flag = atoi(flags) & 4; + if (!host_flag) + continue; + + ipv4_addr = (char *)calloc(1, IPV4_MAX); + if (!ipv4_addr) + break; + + addr.s_addr = strtoul(destination, NULL, IPV4_MAX); + inet_ntop(AF_INET, &(addr.s_addr), ipv4_addr, IPV4_MAX); + printf("ipv4_addr %s\n", ipv4_addr); + } + + free(iface); + free(destination); + free(gateway); + free(flags); +fail_route: + fclose(fp); +fail: + return ipv4_addr; +} + +int list_to_blob(void) +{ + struct device *net_dev; + struct blob_buf bb; + void *arr, *table; + int rv; + + memset(&bb, 0, sizeof(bb)); + rv = blob_buf_init(&bb, 0); + if (rv != 0) + goto fail; + + arr = blobmsg_open_array(&bb, "network_devices"); + if (!arr) + goto fail_arr; + + list_for_each_entry(net_dev, &devices, list) + { + table = blobmsg_open_table(&bb, ""); + if (!table) + goto fail_table; + + rv = blobmsg_add_string(&bb, "product", net_dev->usb.product); + if (rv < 0) + goto fail_string; + + rv = blobmsg_add_string(&bb, "interface_name", net_dev->usb.if_name); + if (rv < 0) + goto fail_string; + + rv = blobmsg_add_string(&bb, "idproduct", net_dev->usb.product_id); + if (rv < 0) + goto fail_string; + + rv = blobmsg_add_string(&bb, "idvendor", net_dev->usb.vendor_id); + if (rv < 0) + goto fail_string; + + if (net_dev->ip) + { + rv = blobmsg_add_string(&bb, "ip", net_dev->ip); + if (rv < 0) + goto fail_string; + } + blobmsg_close_table(&bb, table); + } + blobmsg_close_array(&bb, arr); + ubus_send_reply(ctx, req, bb.head); + + blob_buf_free(&bb); + return 0; +fail_string: +fail_table: +fail_arr: + blob_buf_free(&bb); +fail: + return UBUS_STATUS_UNKNOWN_ERROR; +} + +int print_list(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + return list_to_blob(); +} + +int clear(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + printf("%d\n", delete_all_devices()); + return 0; +} + +int test(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + printf("%s\n", get_device_ip("usb0")); + return 0; +} + +int remove_device(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__DEV_MAX]; + char *dev; + + blobmsg_parse(dev_policy, __DEV_MAX, tb, blob_data(msg), blob_len(msg)); + + if (!tb[DEV]) + goto fail; + dev = (char *)blobmsg_data(tb[DEV]); + + printf("%d\n", delete_device_by_name(dev)); + + return 0; +fail: + return UBUS_STATUS_INVALID_ARGUMENT; +} + +struct ubus_method infrastructure_object_methods[] = { + UBUS_METHOD_NOARG("test", test), + UBUS_METHOD_NOARG("list", print_list), + UBUS_METHOD_NOARG("clear", clear), + UBUS_METHOD("remove_device", remove_device, dev_policy)}; + +struct ubus_object_type infrastructure_object_type = UBUS_OBJECT_TYPE("dongle", infrastructure_object_methods); + +struct ubus_object infrastructure_object = { + .name = "dongle", + .type = &infrastructure_object_type, + .methods = infrastructure_object_methods, + .n_methods = ARRAY_SIZE(infrastructure_object_methods), +}; + +void uloop_add_get_devices(struct uloop_timeout *t) +{ + uloop_timeout_set(t, 5000); + uloop_timeout_add(t); +} + void init_ubus(void) { global_ctx = ubus_connect(NULL); diff --git a/dongle_infrastructure.c b/dongle_infrastructure.c index 409bd29bea7c2bc6dab3c4cbf90cef5262693d56..7f0cc790eef080d980bd80c2c86c39e13f378065 100644 --- a/dongle_infrastructure.c +++ b/dongle_infrastructure.c @@ -18,7 +18,6 @@ #include "dongle.h" #include "stack_operations.h" - struct ubus_object *dongle_create_dynamic_object(struct device *dev_instance); int publish_ubus_object(struct ubus_context *ctx, struct ubus_object *obj); int unpublish_ubus_object(struct ubus_context *ctx, struct ubus_object *obj); @@ -35,6 +34,7 @@ void free_device(struct device *dev); void free_usb(struct USB *usb); struct device *search_list(char *name); +<<<<<<< HEAD const struct blobmsg_policy dev_policy[__DEV_MAX] = { [DEV] = {.name = "dev", .type = BLOBMSG_TYPE_STRING}, @@ -294,251 +294,10 @@ char *get_device_name(char *dir_name) free(sub_dr); continue; } +======= +>>>>>>> 7e47c50... refactor static dongle object from dongle_infrastructure to dongle.c - push(sub_dr, &stack); - continue; - } - - if (!strstr(de->d_name, "eth") && !strstr(de->d_name, "usb")) - break; - - name = strdup(de->d_name); - // how to manage failure on this strdup - break; - } - closedir(dir); - } - - clear_list(&visited); - clear_list(&stack); - return name; -fail_path: - free(dr); -fail_dr: - return NULL; -} - -int get_devices(void) -{ - char usb_path[PATH_MAX], product_path[PATH_MAX], path[PATH_MAX], *name; - struct dirent *de; - DIR *dir; - struct stat st; - struct device *dev; - int rv; - - strncpy(usb_path, "/sys/bus/usb/devices/", PATH_MAX); - dir = opendir(usb_path); - if (!dir) { - perror("opendir"); - goto fail_dr; - } - while ((de = readdir(dir)) != NULL) { - if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) - continue; - if (strstr(de->d_name, ":") || strstr(de->d_name, "usb")) - continue; - - snprintf(product_path, PATH_MAX, "%s%s/product", usb_path, de->d_name); - memset(&st, 0, sizeof(st)); - - rv = stat(product_path, &st); - if (rv < 0) { - //perror("stat"); - continue; - } - - snprintf(path, PATH_MAX, "%s%s/", usb_path, de->d_name); - name = get_device_name(path); - if (!name) - continue; - - dev = (struct device *)calloc(1, sizeof(*dev)); - if (!dev) { - perror("calloc"); - goto fail_dev; - } - - dev->usb.product = get_usb_stat(usb_path, de->d_name, "product"); - dev->usb.product_id = get_usb_stat(usb_path, de->d_name, "idProduct"); - dev->usb.vendor_id = get_usb_stat(usb_path, de->d_name, "idVendor"); - dev->usb.if_name = name; - dev->ip = get_device_ip(dev->usb.if_name); - - add_device(dev); - } - - closedir(dir); - return 0; -fail_dev: - closedir(dir); -fail_dr: - return -1; -} - -char *get_device_ip(char *device_name) -{ - char *iface, *destination, *gateway, *flags, *route, *ipv4_addr = NULL; - bool host_flag; - struct in_addr addr; - FILE *fp; - - fp = fopen("/proc/net/route", "r"); - if (!fp) { - perror("fopen"); - goto fail; - } - - route = (char *)malloc(1024); - if (!route) { - perror("malloc"); - goto fail_route; - } - memset(route, 0, 1024); - while ((fgets(route, 1024, fp)) != NULL) { - remove_newline(route); - - iface = lexer(&route, "\t"); - destination = lexer(&route, "\t"); - gateway = lexer(&route, "\t"); - flags = lexer(&route, "\t"); - - if (strncmp(iface, device_name, 10) != 0) - continue; - - host_flag = atoi(flags) & 4; - if (!host_flag) - continue; - - ipv4_addr = (char *)calloc(1, IPV4_MAX); - if (!ipv4_addr) - break; - - addr.s_addr = strtoul(destination, NULL, IPV4_MAX); - inet_ntop(AF_INET, &(addr.s_addr), ipv4_addr, IPV4_MAX); - printf("ipv4_addr %s\n", ipv4_addr); - } - free(iface); - free(destination); - free(gateway); - free(flags); -fail_route: - fclose(fp); -fail: - return ipv4_addr; -} - -int print_list(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct device *net_dev; - struct blob_buf bb; - void *arr, *table; - int rv; - - memset(&bb, 0, sizeof(bb)); - rv = blob_buf_init(&bb, 0); - if (rv != 0) - goto fail; - - arr = blobmsg_open_array(&bb, "network_devices"); - if (!arr) - goto fail_arr; - - list_for_each_entry(net_dev, &devices, list) { - table = blobmsg_open_table(&bb, ""); - if (!table) - goto fail_table; - - rv = blobmsg_add_string(&bb, "product", net_dev->usb.product); - if (rv < 0) - goto fail_string; - - rv = blobmsg_add_string(&bb, "interface_name", net_dev->usb.if_name); - if (rv < 0) - goto fail_string; - - rv = blobmsg_add_string(&bb, "idproduct", net_dev->usb.product_id); - if (rv < 0) - goto fail_string; - - rv = blobmsg_add_string(&bb, "idvendor", net_dev->usb.vendor_id); - if (rv < 0) - goto fail_string; - - if (net_dev->ip) { - rv = blobmsg_add_string(&bb, "ip", net_dev->ip); - if (rv < 0) - goto fail_string; - } - blobmsg_close_table(&bb, table); - } - blobmsg_close_array(&bb, arr); - ubus_send_reply(ctx, req, bb.head); - - blob_buf_free(&bb); - return 0; -fail_string: -fail_table: -fail_arr: - blob_buf_free(&bb); -fail: - return UBUS_STATUS_UNKNOWN_ERROR; -} - -int clear(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - printf("%d\n", delete_all_devices()); - return 0; -} - -int test(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - printf("%s\n", get_device_ip("usb0")); - return 0; -} - -int remove_device(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) -{ - struct blob_attr *tb[__DEV_MAX]; - char *dev; - - blobmsg_parse(dev_policy, __DEV_MAX, tb, blob_data(msg), blob_len(msg)); - - if (!tb[DEV]) - goto fail; - dev = (char *)blobmsg_data(tb[DEV]); - - printf("%d\n", delete_device_by_name(dev)); - - return 0; -fail: - return UBUS_STATUS_INVALID_ARGUMENT; -} - -struct ubus_method infrastructure_object_methods[] = { - UBUS_METHOD_NOARG("test", test), - UBUS_METHOD_NOARG("list", print_list), - UBUS_METHOD_NOARG("clear", clear), - UBUS_METHOD("remove_device", remove_device, dev_policy) -}; - -struct ubus_object_type infrastructure_object_type = UBUS_OBJECT_TYPE("dongle", infrastructure_object_methods); - -struct ubus_object infrastructure_object = { - .name = "dongle", - .type = &infrastructure_object_type, - .methods = infrastructure_object_methods, - .n_methods = ARRAY_SIZE(infrastructure_object_methods), -}; int expose_infrastructure_object(struct ubus_context *ctx) {