Skip to content

Commit a82c7ce

Browse files
bmorkdavem330
authored andcommitted
net: cdc_ncm: map MBIM IPS SessionID to VLAN ID
MBIM devices can support up to 256 independent IP Streams. The main network device will only handle SessionID 0. Mapping SessionIDs 1 to 255 to VLANs using the SessionID as VLAN ID allow userspace to use these streams with traditional tools like vconfig. Signed-off-by: Bjørn Mork <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bd329e1 commit a82c7ce

File tree

1 file changed

+43
-8
lines changed

1 file changed

+43
-8
lines changed

drivers/net/usb/cdc_mbim.c

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/module.h>
1414
#include <linux/netdevice.h>
1515
#include <linux/ethtool.h>
16+
#include <linux/if_vlan.h>
1617
#include <linux/ip.h>
1718
#include <linux/mii.h>
1819
#include <linux/usb.h>
@@ -107,6 +108,9 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
107108

108109
/* MBIM cannot do ARP */
109110
dev->net->flags |= IFF_NOARP;
111+
112+
/* no need to put the VLAN tci in the packet headers */
113+
dev->net->features |= NETIF_F_HW_VLAN_TX;
110114
err:
111115
return ret;
112116
}
@@ -131,6 +135,9 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
131135
struct sk_buff *skb_out;
132136
struct cdc_mbim_state *info = (void *)&dev->data;
133137
struct cdc_ncm_ctx *ctx = info->ctx;
138+
__le32 sign = cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN);
139+
u16 tci = 0;
140+
u8 *c;
134141

135142
if (!ctx)
136143
goto error;
@@ -139,6 +146,24 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
139146
if (skb->len <= sizeof(ETH_HLEN))
140147
goto error;
141148

149+
/* mapping VLANs to MBIM sessions:
150+
* no tag => IPS session <0>
151+
* 1 - 255 => IPS session <vlanid>
152+
* 256 - 4095 => unsupported, drop
153+
*/
154+
vlan_get_tag(skb, &tci);
155+
156+
switch (tci & 0x0f00) {
157+
case 0x0000: /* VLAN ID 0 - 255 */
158+
c = (u8 *)&sign;
159+
c[3] = tci;
160+
break;
161+
default:
162+
netif_err(dev, tx_err, dev->net,
163+
"unsupported tci=0x%04x\n", tci);
164+
goto error;
165+
}
166+
142167
skb_reset_mac_header(skb);
143168
switch (eth_hdr(skb)->h_proto) {
144169
case htons(ETH_P_IP):
@@ -151,7 +176,7 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
151176
}
152177

153178
spin_lock_bh(&ctx->mtx);
154-
skb_out = cdc_ncm_fill_tx_frame(ctx, skb, cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN));
179+
skb_out = cdc_ncm_fill_tx_frame(ctx, skb, sign);
155180
spin_unlock_bh(&ctx->mtx);
156181
return skb_out;
157182

@@ -162,11 +187,14 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
162187
return NULL;
163188
}
164189

165-
static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_t len)
190+
static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_t len, u16 tci)
166191
{
167192
__be16 proto;
168193
struct sk_buff *skb = NULL;
169194

195+
if (len < sizeof(struct iphdr))
196+
goto err;
197+
170198
switch (*buf & 0xf0) {
171199
case 0x40:
172200
proto = htons(ETH_P_IP);
@@ -191,14 +219,19 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_
191219

192220
/* add datagram */
193221
memcpy(skb_put(skb, len), buf, len);
222+
223+
/* map MBIM session to VLAN */
224+
if (tci)
225+
vlan_put_tag(skb, tci);
194226
err:
195227
return skb;
196228
}
197229

198230
static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
199231
{
200232
struct sk_buff *skb;
201-
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
233+
struct cdc_mbim_state *info = (void *)&dev->data;
234+
struct cdc_ncm_ctx *ctx = info->ctx;
202235
int len;
203236
int nframes;
204237
int x;
@@ -207,6 +240,8 @@ static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
207240
struct usb_cdc_ncm_dpe16 *dpe16;
208241
int ndpoffset;
209242
int loopcount = 50; /* arbitrary max preventing infinite loop */
243+
u8 *c;
244+
u16 tci;
210245

211246
ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
212247
if (ndpoffset < 0)
@@ -219,9 +254,10 @@ static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
219254

220255
ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
221256

222-
/* only supporting IPS Session #0 for now */
223-
switch (ndp16->dwSignature) {
257+
switch (ndp16->dwSignature & cpu_to_le32(0x00ffffff)) {
224258
case cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN):
259+
c = (u8 *)&ndp16->dwSignature;
260+
tci = c[3];
225261
break;
226262
default:
227263
netif_dbg(dev, rx_err, dev->net,
@@ -247,16 +283,15 @@ static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
247283
}
248284

249285
/* sanity checking */
250-
if (((offset + len) > skb_in->len) || (len > ctx->rx_max) ||
251-
(len < sizeof(struct iphdr))) {
286+
if (((offset + len) > skb_in->len) || (len > ctx->rx_max)) {
252287
netif_dbg(dev, rx_err, dev->net,
253288
"invalid frame detected (ignored) offset[%u]=%u, length=%u, skb=%p\n",
254289
x, offset, len, skb_in);
255290
if (!x)
256291
goto err_ndp;
257292
break;
258293
} else {
259-
skb = cdc_mbim_process_dgram(dev, skb_in->data + offset, len);
294+
skb = cdc_mbim_process_dgram(dev, skb_in->data + offset, len, tci);
260295
if (!skb)
261296
goto error;
262297
usbnet_skb_return(dev, skb);

0 commit comments

Comments
 (0)