Commit 4b9734e5 authored by David S. Miller's avatar David S. Miller

Merge branch 'cdc_mbim-next'

Bjørn Mork says:

====================
cdc_mbim: cleanups and new features

This series depends on commit 6b5eeb7f ("net: cdc_mbim: handle
unaccelerated VLAN tagged frames"), which is currently in "net" but
not yet in "net-next".

Patch 4 might have a minor context collision with the "cdc_ncm: add
buffer tuning and stats using ethtool" series I just posted for
review.  Please let me know if I should submit an adjusted version
in either direction.  These two series' are otherwise completely
independent of each other.

The major new feature here is in patch 1, which I hope will solve
some problems with the original design without changing the existing
API, optionally allowing IP session 0 to be treated like any other
MBIM session.

The rest are some minor cleanups and finally some documentation of
the current driver APIs, after this series has been applied.  I
started feeling a bit more mortal than usual lately, which probably
is healthy, and realized that I should put some of the stuff in my
head in a somewhat less volatile storage.

v2:

Fixed patch 1 so that it actually does what it claims to do. This time
it is even tested for functionality, and not just build tested...
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7ad24ea4 50a0ffaf
This diff is collapsed.
...@@ -24,13 +24,21 @@ ...@@ -24,13 +24,21 @@
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/addrconf.h> #include <net/addrconf.h>
/* alternative VLAN for IP session 0 if not untagged */
#define MBIM_IPS0_VID 4094
/* driver specific data - must match cdc_ncm usage */ /* driver specific data - must match cdc_ncm usage */
struct cdc_mbim_state { struct cdc_mbim_state {
struct cdc_ncm_ctx *ctx; struct cdc_ncm_ctx *ctx;
atomic_t pmcount; atomic_t pmcount;
struct usb_driver *subdriver; struct usb_driver *subdriver;
struct usb_interface *control; unsigned long _unused;
struct usb_interface *data; unsigned long flags;
};
/* flags for the cdc_mbim_state.flags field */
enum cdc_mbim_flags {
FLAG_IPS0_VLAN = 1 << 0, /* IP session 0 is tagged */
}; };
/* using a counter to merge subdriver requests with our own into a combined state */ /* using a counter to merge subdriver requests with our own into a combined state */
...@@ -62,16 +70,91 @@ static int cdc_mbim_wdm_manage_power(struct usb_interface *intf, int status) ...@@ -62,16 +70,91 @@ static int cdc_mbim_wdm_manage_power(struct usb_interface *intf, int status)
return cdc_mbim_manage_power(dev, status); return cdc_mbim_manage_power(dev, status);
} }
static int cdc_mbim_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct usbnet *dev = netdev_priv(netdev);
struct cdc_mbim_state *info = (void *)&dev->data;
/* creation of this VLAN is a request to tag IP session 0 */
if (vid == MBIM_IPS0_VID)
info->flags |= FLAG_IPS0_VLAN;
else
if (vid >= 512) /* we don't map these to MBIM session */
return -EINVAL;
return 0;
}
static int cdc_mbim_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct usbnet *dev = netdev_priv(netdev);
struct cdc_mbim_state *info = (void *)&dev->data;
/* this is a request for an untagged IP session 0 */
if (vid == MBIM_IPS0_VID)
info->flags &= ~FLAG_IPS0_VLAN;
return 0;
}
static const struct net_device_ops cdc_mbim_netdev_ops = {
.ndo_open = usbnet_open,
.ndo_stop = usbnet_stop,
.ndo_start_xmit = usbnet_start_xmit,
.ndo_tx_timeout = usbnet_tx_timeout,
.ndo_change_mtu = usbnet_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_add_vid = cdc_mbim_rx_add_vid,
.ndo_vlan_rx_kill_vid = cdc_mbim_rx_kill_vid,
};
/* Change the control interface altsetting and update the .driver_info
* pointer if the matching entry after changing class codes points to
* a different struct
*/
static int cdc_mbim_set_ctrlalt(struct usbnet *dev, struct usb_interface *intf, u8 alt)
{
struct usb_driver *driver = to_usb_driver(intf->dev.driver);
const struct usb_device_id *id;
struct driver_info *info;
int ret;
ret = usb_set_interface(dev->udev,
intf->cur_altsetting->desc.bInterfaceNumber,
alt);
if (ret)
return ret;
id = usb_match_id(intf, driver->id_table);
if (!id)
return -ENODEV;
info = (struct driver_info *)id->driver_info;
if (info != dev->driver_info) {
dev_dbg(&intf->dev, "driver_info updated to '%s'\n",
info->description);
dev->driver_info = info;
}
return 0;
}
static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf) static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
{ {
struct cdc_ncm_ctx *ctx; struct cdc_ncm_ctx *ctx;
struct usb_driver *subdriver = ERR_PTR(-ENODEV); struct usb_driver *subdriver = ERR_PTR(-ENODEV);
int ret = -ENODEV; int ret = -ENODEV;
u8 data_altsetting = cdc_ncm_select_altsetting(dev, intf); u8 data_altsetting = 1;
struct cdc_mbim_state *info = (void *)&dev->data; struct cdc_mbim_state *info = (void *)&dev->data;
/* Probably NCM, defer for cdc_ncm_bind */ /* should we change control altsetting on a NCM/MBIM function? */
if (cdc_ncm_select_altsetting(intf) == CDC_NCM_COMM_ALTSETTING_MBIM) {
data_altsetting = CDC_NCM_DATA_ALTSETTING_MBIM;
ret = cdc_mbim_set_ctrlalt(dev, intf, CDC_NCM_COMM_ALTSETTING_MBIM);
if (ret)
goto err;
ret = -ENODEV;
}
/* we will hit this for NCM/MBIM functions if prefer_mbim is false */
if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
goto err; goto err;
...@@ -101,7 +184,10 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -101,7 +184,10 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->flags |= IFF_NOARP; dev->net->flags |= IFF_NOARP;
/* no need to put the VLAN tci in the packet headers */ /* no need to put the VLAN tci in the packet headers */
dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX; dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER;
/* monitor VLAN additions and removals */
dev->net->netdev_ops = &cdc_mbim_netdev_ops;
err: err:
return ret; return ret;
} }
...@@ -164,12 +250,24 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb ...@@ -164,12 +250,24 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
skb_pull(skb, ETH_HLEN); skb_pull(skb, ETH_HLEN);
} }
/* Is IP session <0> tagged too? */
if (info->flags & FLAG_IPS0_VLAN) {
/* drop all untagged packets */
if (!tci)
goto error;
/* map MBIM_IPS0_VID to IPS<0> */
if (tci == MBIM_IPS0_VID)
tci = 0;
}
/* mapping VLANs to MBIM sessions: /* mapping VLANs to MBIM sessions:
* no tag => IPS session <0> * no tag => IPS session <0> if !FLAG_IPS0_VLAN
* 1 - 255 => IPS session <vlanid> * 1 - 255 => IPS session <vlanid>
* 256 - 511 => DSS session <vlanid - 256> * 256 - 511 => DSS session <vlanid - 256>
* 512 - 4095 => unsupported, drop * 512 - 4093 => unsupported, drop
* 4094 => IPS session <0> if FLAG_IPS0_VLAN
*/ */
switch (tci & 0x0f00) { switch (tci & 0x0f00) {
case 0x0000: /* VLAN ID 0 - 255 */ case 0x0000: /* VLAN ID 0 - 255 */
if (!is_ip) if (!is_ip)
...@@ -178,6 +276,8 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb ...@@ -178,6 +276,8 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
c[3] = tci; c[3] = tci;
break; break;
case 0x0100: /* VLAN ID 256 - 511 */ case 0x0100: /* VLAN ID 256 - 511 */
if (is_ip)
goto error;
sign = cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN); sign = cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN);
c = (u8 *)&sign; c = (u8 *)&sign;
c[3] = tci; c[3] = tci;
...@@ -268,7 +368,7 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_ ...@@ -268,7 +368,7 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_
__be16 proto = htons(ETH_P_802_3); __be16 proto = htons(ETH_P_802_3);
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
if (tci < 256) { /* IPS session? */ if (tci < 256 || tci == MBIM_IPS0_VID) { /* IPS session? */
if (len < sizeof(struct iphdr)) if (len < sizeof(struct iphdr))
goto err; goto err;
...@@ -338,6 +438,9 @@ static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) ...@@ -338,6 +438,9 @@ static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
case cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN): case cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN):
c = (u8 *)&ndp16->dwSignature; c = (u8 *)&ndp16->dwSignature;
tci = c[3]; tci = c[3];
/* tag IPS<0> packets too if MBIM_IPS0_VID exists */
if (!tci && info->flags & FLAG_IPS0_VLAN)
tci = MBIM_IPS0_VID;
break; break;
case cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN): case cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN):
c = (u8 *)&ndp16->dwSignature; c = (u8 *)&ndp16->dwSignature;
......
...@@ -541,10 +541,10 @@ void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf) ...@@ -541,10 +541,10 @@ void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
} }
EXPORT_SYMBOL_GPL(cdc_ncm_unbind); EXPORT_SYMBOL_GPL(cdc_ncm_unbind);
/* Select the MBIM altsetting iff it is preferred and available, /* Return the number of the MBIM control interface altsetting iff it
* returning the number of the corresponding data interface altsetting * is preferred and available,
*/ */
u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf) u8 cdc_ncm_select_altsetting(struct usb_interface *intf)
{ {
struct usb_host_interface *alt; struct usb_host_interface *alt;
...@@ -563,15 +563,15 @@ u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf) ...@@ -563,15 +563,15 @@ u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf)
* the rules given in section 6 (USB Device Model) of this * the rules given in section 6 (USB Device Model) of this
* specification." * specification."
*/ */
if (prefer_mbim && intf->num_altsetting == 2) { if (intf->num_altsetting < 2)
return intf->cur_altsetting->desc.bAlternateSetting;
if (prefer_mbim) {
alt = usb_altnum_to_altsetting(intf, CDC_NCM_COMM_ALTSETTING_MBIM); alt = usb_altnum_to_altsetting(intf, CDC_NCM_COMM_ALTSETTING_MBIM);
if (alt && cdc_ncm_comm_intf_is_mbim(alt) && if (alt && cdc_ncm_comm_intf_is_mbim(alt))
!usb_set_interface(dev->udev, return CDC_NCM_COMM_ALTSETTING_MBIM;
intf->cur_altsetting->desc.bInterfaceNumber,
CDC_NCM_COMM_ALTSETTING_MBIM))
return CDC_NCM_DATA_ALTSETTING_MBIM;
} }
return CDC_NCM_DATA_ALTSETTING_NCM; return CDC_NCM_COMM_ALTSETTING_NCM;
} }
EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting); EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting);
...@@ -580,12 +580,11 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf) ...@@ -580,12 +580,11 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
int ret; int ret;
/* MBIM backwards compatible function? */ /* MBIM backwards compatible function? */
cdc_ncm_select_altsetting(dev, intf); if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
return -ENODEV; return -ENODEV;
/* NCM data altsetting is always 1 */ /* The NCM data altsetting is fixed */
ret = cdc_ncm_bind_common(dev, intf, 1); ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM);
/* /*
* We should get an event when network connection is "connected" or * We should get an event when network connection is "connected" or
......
...@@ -121,7 +121,7 @@ struct cdc_ncm_ctx { ...@@ -121,7 +121,7 @@ struct cdc_ncm_ctx {
u16 connected; u16 connected;
}; };
u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf); u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting); int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting);
void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf); void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign); struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment