Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: cdc_mbim: optionally use VLAN ID 4094 for IP session 0

The cdc_mbim driver maps 802.1q VLANs to MBIM IP and DSS
sessions. MBIM IP session 0 is handled as an exception and
is mapped to untagged frames.

This patch adds optional support for remapping MBIM IP
session 0 to 802.1q VLAN ID 4094 instead. The default
behaviour is not changed. The new behaviour is triggered
by adding a link for this previously unsupported VLAN.

The untagged mapping was chosen initially to support the
assumed most common use case: Most current MBIM devices only
support a single IP session (i.e. session 0 only), and using
untagged frames lets the users completely ignore the
additonal complexity of the multiplexing layer.

But when the multiplexing features of MBIM are used, then
this netdev gets a double meaning: It becomes the master
interface for all the VLAN subdevs the additional sessions
are mapped to, while still serving as the untagged IP
interface for session 0.

This can be problematic, especially when using Device Service
Streams (DSS), as have become apparent recently with the
availability of devices with real DSS support. Some use cases
need to e.g set a MTU which is higher than allowed for IP
Session 0. The dual role also leads to the situation where
the IP Session 0 interface cannot be taken down without
breaking unrelated IP or DSS sessions - a devastating side
effect which applications managing a simple IP session cannot
be expected to be aware of. A typical DHCP client will assume
that it should bring the interface down after releasing the
IP lease.

These problems can be avoided by tagging IP session 0 packets
too, making this session similar to all other multiplexed
sessions. This redefines the main netdev as an upper master
interface only.

Cc: Greg Suarez <gsuarez@smithmicro.com>
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Bjørn Mork and committed by
David S. Miller
146a08d2 7ad24ea4

+68 -6
+68 -6
drivers/net/usb/cdc_mbim.c
··· 24 24 #include <net/ipv6.h> 25 25 #include <net/addrconf.h> 26 26 27 + /* alternative VLAN for IP session 0 if not untagged */ 28 + #define MBIM_IPS0_VID 4094 29 + 27 30 /* driver specific data - must match cdc_ncm usage */ 28 31 struct cdc_mbim_state { 29 32 struct cdc_ncm_ctx *ctx; 30 33 atomic_t pmcount; 31 34 struct usb_driver *subdriver; 32 - struct usb_interface *control; 33 - struct usb_interface *data; 35 + unsigned long _unused; 36 + unsigned long flags; 37 + }; 38 + 39 + /* flags for the cdc_mbim_state.flags field */ 40 + enum cdc_mbim_flags { 41 + FLAG_IPS0_VLAN = 1 << 0, /* IP session 0 is tagged */ 34 42 }; 35 43 36 44 /* using a counter to merge subdriver requests with our own into a combined state */ ··· 70 62 return cdc_mbim_manage_power(dev, status); 71 63 } 72 64 65 + static int cdc_mbim_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) 66 + { 67 + struct usbnet *dev = netdev_priv(netdev); 68 + struct cdc_mbim_state *info = (void *)&dev->data; 69 + 70 + /* creation of this VLAN is a request to tag IP session 0 */ 71 + if (vid == MBIM_IPS0_VID) 72 + info->flags |= FLAG_IPS0_VLAN; 73 + else 74 + if (vid >= 512) /* we don't map these to MBIM session */ 75 + return -EINVAL; 76 + return 0; 77 + } 78 + 79 + static int cdc_mbim_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) 80 + { 81 + struct usbnet *dev = netdev_priv(netdev); 82 + struct cdc_mbim_state *info = (void *)&dev->data; 83 + 84 + /* this is a request for an untagged IP session 0 */ 85 + if (vid == MBIM_IPS0_VID) 86 + info->flags &= ~FLAG_IPS0_VLAN; 87 + return 0; 88 + } 89 + 90 + static const struct net_device_ops cdc_mbim_netdev_ops = { 91 + .ndo_open = usbnet_open, 92 + .ndo_stop = usbnet_stop, 93 + .ndo_start_xmit = usbnet_start_xmit, 94 + .ndo_tx_timeout = usbnet_tx_timeout, 95 + .ndo_change_mtu = usbnet_change_mtu, 96 + .ndo_set_mac_address = eth_mac_addr, 97 + .ndo_validate_addr = eth_validate_addr, 98 + .ndo_vlan_rx_add_vid = cdc_mbim_rx_add_vid, 99 + .ndo_vlan_rx_kill_vid = cdc_mbim_rx_kill_vid, 100 + }; 73 101 74 102 static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf) 75 103 { ··· 145 101 dev->net->flags |= IFF_NOARP; 146 102 147 103 /* no need to put the VLAN tci in the packet headers */ 148 - dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX; 104 + dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER; 105 + 106 + /* monitor VLAN additions and removals */ 107 + dev->net->netdev_ops = &cdc_mbim_netdev_ops; 149 108 err: 150 109 return ret; 151 110 } ··· 211 164 skb_pull(skb, ETH_HLEN); 212 165 } 213 166 167 + /* Is IP session <0> tagged too? */ 168 + if (info->flags & FLAG_IPS0_VLAN) { 169 + /* drop all untagged packets */ 170 + if (!tci) 171 + goto error; 172 + /* map MBIM_IPS0_VID to IPS<0> */ 173 + if (tci == MBIM_IPS0_VID) 174 + tci = 0; 175 + } 176 + 214 177 /* mapping VLANs to MBIM sessions: 215 - * no tag => IPS session <0> 178 + * no tag => IPS session <0> if !FLAG_IPS0_VLAN 216 179 * 1 - 255 => IPS session <vlanid> 217 180 * 256 - 511 => DSS session <vlanid - 256> 218 - * 512 - 4095 => unsupported, drop 181 + * 512 - 4093 => unsupported, drop 182 + * 4094 => IPS session <0> if FLAG_IPS0_VLAN 219 183 */ 184 + 220 185 switch (tci & 0x0f00) { 221 186 case 0x0000: /* VLAN ID 0 - 255 */ 222 187 if (!is_ip) ··· 327 268 __be16 proto = htons(ETH_P_802_3); 328 269 struct sk_buff *skb = NULL; 329 270 330 - if (tci < 256) { /* IPS session? */ 271 + if (tci < 256 || tci == MBIM_IPS0_VID) { /* IPS session? */ 331 272 if (len < sizeof(struct iphdr)) 332 273 goto err; 333 274 ··· 397 338 case cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN): 398 339 c = (u8 *)&ndp16->dwSignature; 399 340 tci = c[3]; 341 + /* tag IPS<0> packets too if MBIM_IPS0_VID exists */ 342 + if (!tci && info->flags & FLAG_IPS0_VLAN) 343 + tci = MBIM_IPS0_VID; 400 344 break; 401 345 case cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN): 402 346 c = (u8 *)&ndp16->dwSignature;