diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 4e35ed9654b7..2a7d57cd14cb 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1426,17 +1426,39 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) */ if (!ncm_opts->bound) { mutex_lock(&ncm_opts->lock); + ncm_opts->net = gether_setup_default(); + if (IS_ERR(ncm_opts->net)) { + status = PTR_ERR(ncm_opts->net); + mutex_unlock(&ncm_opts->lock); + goto error; + } gether_set_gadget(ncm_opts->net, cdev->gadget); status = gether_register_netdev(ncm_opts->net); mutex_unlock(&ncm_opts->lock); - if (status) - return status; + if (status) { + free_netdev(ncm_opts->net); + goto error; + } ncm_opts->bound = true; } + + /* export host's Ethernet address in CDC format */ + status = gether_get_host_addr_cdc(ncm_opts->net, ncm->ethaddr, + sizeof(ncm->ethaddr)); + if (status < 12) { /* strlen("01234567890a") */ + ERROR(cdev, "%s: failed to get host eth addr, err %d\n", + __func__, status); + status = -EINVAL; + goto netdev_cleanup; + } + ncm->port.ioport = netdev_priv(ncm_opts->net); + us = usb_gstrings_attach(cdev, ncm_strings, ARRAY_SIZE(ncm_string_defs)); - if (IS_ERR(us)) - return PTR_ERR(us); + if (IS_ERR(us)) { + status = PTR_ERR(us); + goto netdev_cleanup; + } ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id; ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id; ncm_data_intf.iInterface = us[STRING_DATA_IDX].id; @@ -1540,7 +1562,10 @@ fail: kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); } +netdev_cleanup: + gether_cleanup(netdev_priv(ncm_opts->net)); +error: ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; @@ -1588,8 +1613,6 @@ static void ncm_free_inst(struct usb_function_instance *f) opts = container_of(f, struct f_ncm_opts, func_inst); if (opts->bound) gether_cleanup(netdev_priv(opts->net)); - else - free_netdev(opts->net); kfree(opts); } @@ -1602,12 +1625,6 @@ static struct usb_function_instance *ncm_alloc_inst(void) return ERR_PTR(-ENOMEM); mutex_init(&opts->lock); opts->func_inst.free_func_inst = ncm_free_inst; - opts->net = gether_setup_default(); - if (IS_ERR(opts->net)) { - struct net_device *net = opts->net; - kfree(opts); - return ERR_CAST(net); - } config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type); @@ -1630,6 +1647,8 @@ static void ncm_free(struct usb_function *f) static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_ncm *ncm = func_to_ncm(f); + struct f_ncm_opts *opts = container_of(f->fi, struct f_ncm_opts, + func_inst); DBG(c->cdev, "ncm unbind\n"); @@ -1641,13 +1660,15 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) kfree(ncm->notify_req->buf); usb_ep_free_request(ncm->notify, ncm->notify_req); + + gether_cleanup(netdev_priv(opts->net)); + opts->bound = false; } static struct usb_function *ncm_alloc(struct usb_function_instance *fi) { struct f_ncm *ncm; struct f_ncm_opts *opts; - int status; /* allocate and initialize one new instance */ ncm = kzalloc(sizeof(*ncm), GFP_KERNEL); @@ -1657,20 +1678,9 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi) opts = container_of(fi, struct f_ncm_opts, func_inst); mutex_lock(&opts->lock); opts->refcnt++; - - /* export host's Ethernet address in CDC format */ - status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr, - sizeof(ncm->ethaddr)); - if (status < 12) { /* strlen("01234567890a") */ - kfree(ncm); - mutex_unlock(&opts->lock); - return ERR_PTR(-EINVAL); - } ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr; - spin_lock_init(&ncm->lock); ncm_reset_values(ncm); - ncm->port.ioport = netdev_priv(opts->net); mutex_unlock(&opts->lock); ncm->port.is_fixed = true; ncm->port.supports_multi_frame = true;