aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-05-13 17:46:19 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-13 17:46:19 -0400
commit4b9734e547aaa947e56480ecf6d509cf9cc307cc (patch)
tree6ffcf988584c3725a7e146afae06e9cd11ac2355
parent7ad24ea4bf620a32631d7b3069c3e30c078b0c3e (diff)
parent50a0ffaf75e9d2d97200b523f2c600f40e9756b1 (diff)
Merge branch 'cdc_mbim-next'
Bjørn Mork says: ==================== cdc_mbim: cleanups and new features This series depends on commit 6b5eeb7f874b ("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: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/cdc_mbim.txt339
-rw-r--r--drivers/net/usb/cdc_mbim.c119
-rw-r--r--drivers/net/usb/cdc_ncm.c27
-rw-r--r--include/linux/usb/cdc_ncm.h2
4 files changed, 464 insertions, 23 deletions
diff --git a/Documentation/networking/cdc_mbim.txt b/Documentation/networking/cdc_mbim.txt
new file mode 100644
index 000000000000..a15ea602aa52
--- /dev/null
+++ b/Documentation/networking/cdc_mbim.txt
@@ -0,0 +1,339 @@
1 cdc_mbim - Driver for CDC MBIM Mobile Broadband modems
2 ========================================================
3
4The cdc_mbim driver supports USB devices conforming to the "Universal
5Serial Bus Communications Class Subclass Specification for Mobile
6Broadband Interface Model" [1], which is a further development of
7"Universal Serial Bus Communications Class Subclass Specifications for
8Network Control Model Devices" [2] optimized for Mobile Broadband
9devices, aka "3G/LTE modems".
10
11
12Command Line Parameters
13=======================
14
15The cdc_mbim driver has no parameters of its own. But the probing
16behaviour for NCM 1.0 backwards compatible MBIM functions (an
17"NCM/MBIM function" as defined in section 3.2 of [1]) is affected
18by a cdc_ncm driver parameter:
19
20prefer_mbim
21-----------
22Type: Boolean
23Valid Range: N/Y (0-1)
24Default Value: Y (MBIM is preferred)
25
26This parameter sets the system policy for NCM/MBIM functions. Such
27functions will be handled by either the cdc_ncm driver or the cdc_mbim
28driver depending on the prefer_mbim setting. Setting prefer_mbim=N
29makes the cdc_mbim driver ignore these functions and lets the cdc_ncm
30driver handle them instead.
31
32The parameter is writable, and can be changed at any time. A manual
33unbind/bind is required to make the change effective for NCM/MBIM
34functions bound to the "wrong" driver
35
36
37Basic usage
38===========
39
40MBIM functions are inactive when unmanaged. The cdc_mbim driver only
41provides an userspace interface to the MBIM control channel, and will
42not participate in the management of the function. This implies that a
43userspace MBIM management application always is required to enable a
44MBIM function.
45
46Such userspace applications includes, but are not limited to:
47 - mbimcli (included with the libmbim [3] library), and
48 - ModemManager [4]
49
50Establishing a MBIM IP session reequires at least these actions by the
51management application:
52 - open the control channel
53 - configure network connection settings
54 - connect to network
55 - configure IP interface
56
57Management application development
58----------------------------------
59The driver <-> userspace interfaces are described below. The MBIM
60control channel protocol is described in [1].
61
62
63MBIM control channel userspace ABI
64==================================
65
66/dev/cdc-wdmX character device
67------------------------------
68The driver creates a two-way pipe to the MBIM function control channel
69using the cdc-wdm driver as a subdriver. The userspace end of the
70control channel pipe is a /dev/cdc-wdmX character device.
71
72The cdc_mbim driver does not process or police messages on the control
73channel. The channel is fully delegated to the userspace management
74application. It is therefore up to this application to ensure that it
75complies with all the control channel requirements in [1].
76
77The cdc-wdmX device is created as a child of the MBIM control
78interface USB device. The character device associated with a specific
79MBIM function can be looked up using sysfs. For example:
80
81 bjorn@nemi:~$ ls /sys/bus/usb/drivers/cdc_mbim/2-4:2.12/usbmisc
82 cdc-wdm0
83
84 bjorn@nemi:~$ grep . /sys/bus/usb/drivers/cdc_mbim/2-4:2.12/usbmisc/cdc-wdm0/dev
85 180:0
86
87
88USB configuration descriptors
89-----------------------------
90The wMaxControlMessage field of the CDC MBIM functional descriptor
91limits the maximum control message size. The managament application is
92responsible for negotiating a control message size complying with the
93requirements in section 9.3.1 of [1], taking this descriptor field
94into consideration.
95
96The userspace application can access the CDC MBIM functional
97descriptor of a MBIM function using either of the two USB
98configuration descriptor kernel interfaces described in [6] or [7].
99
100See also the ioctl documentation below.
101
102
103Fragmentation
104-------------
105The userspace application is responsible for all control message
106fragmentation and defragmentaion, as described in section 9.5 of [1].
107
108
109/dev/cdc-wdmX write()
110---------------------
111The MBIM control messages from the management application *must not*
112exceed the negotiated control message size.
113
114
115/dev/cdc-wdmX read()
116--------------------
117The management application *must* accept control messages of up the
118negotiated control message size.
119
120
121/dev/cdc-wdmX ioctl()
122--------------------
123IOCTL_WDM_MAX_COMMAND: Get Maximum Command Size
124This ioctl returns the wMaxControlMessage field of the CDC MBIM
125functional descriptor for MBIM devices. This is intended as a
126convenience, eliminating the need to parse the USB descriptors from
127userspace.
128
129 #include <stdio.h>
130 #include <fcntl.h>
131 #include <sys/ioctl.h>
132 #include <linux/types.h>
133 #include <linux/usb/cdc-wdm.h>
134 int main()
135 {
136 __u16 max;
137 int fd = open("/dev/cdc-wdm0", O_RDWR);
138 if (!ioctl(fd, IOCTL_WDM_MAX_COMMAND, &max))
139 printf("wMaxControlMessage is %d\n", max);
140 }
141
142
143Custom device services
144----------------------
145The MBIM specification allows vendors to freely define additional
146services. This is fully supported by the cdc_mbim driver.
147
148Support for new MBIM services, including vendor specified services, is
149implemented entirely in userspace, like the rest of the MBIM control
150protocol
151
152New services should be registered in the MBIM Registry [5].
153
154
155
156MBIM data channel userspace ABI
157===============================
158
159wwanY network device
160--------------------
161The cdc_mbim driver represents the MBIM data channel as a single
162network device of the "wwan" type. This network device is initially
163mapped to MBIM IP session 0.
164
165
166Multiplexed IP sessions (IPS)
167-----------------------------
168MBIM allows multiplexing up to 256 IP sessions over a single USB data
169channel. The cdc_mbim driver models such IP sessions as 802.1q VLAN
170subdevices of the master wwanY device, mapping MBIM IP session Z to
171VLAN ID Z for all values of Z greater than 0.
172
173The device maximum Z is given in the MBIM_DEVICE_CAPS_INFO structure
174described in section 10.5.1 of [1].
175
176The userspace management application is responsible for adding new
177VLAN links prior to establishing MBIM IP sessions where the SessionId
178is greater than 0. These links can be added by using the normal VLAN
179kernel interfaces, either ioctl or netlink.
180
181For example, adding a link for a MBIM IP session with SessionId 3:
182
183 ip link add link wwan0 name wwan0.3 type vlan id 3
184
185The driver will automatically map the "wwan0.3" network device to MBIM
186IP session 3.
187
188
189Device Service Streams (DSS)
190----------------------------
191MBIM also allows up to 256 non-IP data streams to be multiplexed over
192the same shared USB data channel. The cdc_mbim driver models these
193sessions as another set of 802.1q VLAN subdevices of the master wwanY
194device, mapping MBIM DSS session A to VLAN ID (256 + A) for all values
195of A.
196
197The device maximum A is given in the MBIM_DEVICE_SERVICES_INFO
198structure described in section 10.5.29 of [1].
199
200The DSS VLAN subdevices are used as a practical interface between the
201shared MBIM data channel and a MBIM DSS aware userspace application.
202It is not intended to be presented as-is to an end user. The
203assumption is that an userspace application initiating a DSS session
204also takes care of the necessary framing of the DSS data, presenting
205the stream to the end user in an appropriate way for the stream type.
206
207The network device ABI requires a dummy ethernet header for every DSS
208data frame being transported. The contents of this header is
209arbitrary, with the following exceptions:
210 - TX frames using an IP protocol (0x0800 or 0x86dd) will be dropped
211 - RX frames will have the protocol field set to ETH_P_802_3 (but will
212 not be properly formatted 802.3 frames)
213 - RX frames will have the destination address set to the hardware
214 address of the master device
215
216The DSS supporting userspace management application is responsible for
217adding the dummy ethernet header on TX and stripping it on RX.
218
219This is a simple example using tools commonly available, exporting
220DssSessionId 5 as a pty character device pointed to by a /dev/nmea
221symlink:
222
223 ip link add link wwan0 name wwan0.dss5 type vlan id 261
224 ip link set dev wwan0.dss5 up
225 socat INTERFACE:wwan0.dss5,type=2 PTY:,echo=0,link=/dev/nmea
226
227This is only an example, most suitable for testing out a DSS
228service. Userspace applications supporting specific MBIM DSS services
229are expected to use the tools and programming interfaces required by
230that service.
231
232Note that adding VLAN links for DSS sessions is entirely optional. A
233management application may instead choose to bind a packet socket
234directly to the master network device, using the received VLAN tags to
235map frames to the correct DSS session and adding 18 byte VLAN ethernet
236headers with the appropriate tag on TX. In this case using a socket
237filter is recommended, matching only the DSS VLAN subset. This avoid
238unnecessary copying of unrelated IP session data to userspace. For
239example:
240
241 static struct sock_filter dssfilter[] = {
242 /* use special negative offsets to get VLAN tag */
243 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT),
244 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 1, 0, 6), /* true */
245
246 /* verify DSS VLAN range */
247 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, SKF_AD_OFF + SKF_AD_VLAN_TAG),
248 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 256, 0, 4), /* 256 is first DSS VLAN */
249 BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 512, 3, 0), /* 511 is last DSS VLAN */
250
251 /* verify ethertype */
252 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 2 * ETH_ALEN),
253 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ETH_P_802_3, 0, 1),
254
255 BPF_STMT(BPF_RET|BPF_K, (u_int)-1), /* accept */
256 BPF_STMT(BPF_RET|BPF_K, 0), /* ignore */
257 };
258
259
260
261Tagged IP session 0 VLAN
262------------------------
263As described above, MBIM IP session 0 is treated as special by the
264driver. It is initially mapped to untagged frames on the wwanY
265network device.
266
267This mapping implies a few restrictions on multiplexed IPS and DSS
268sessions, which may not always be practical:
269 - no IPS or DSS session can use a frame size greater than the MTU on
270 IP session 0
271 - no IPS or DSS session can be in the up state unless the network
272 device representing IP session 0 also is up
273
274These problems can be avoided by optionally making the driver map IP
275session 0 to a VLAN subdevice, similar to all other IP sessions. This
276behaviour is triggered by adding a VLAN link for the magic VLAN ID
2774094. The driver will then immediately start mapping MBIM IP session
2780 to this VLAN, and will drop untagged frames on the master wwanY
279device.
280
281Tip: It might be less confusing to the end user to name this VLAN
282subdevice after the MBIM SessionID instead of the VLAN ID. For
283example:
284
285 ip link add link wwan0 name wwan0.0 type vlan id 4094
286
287
288VLAN mapping
289------------
290
291Summarizing the cdc_mbim driver mapping described above, we have this
292relationship between VLAN tags on the wwanY network device and MBIM
293sessions on the shared USB data channel:
294
295 VLAN ID MBIM type MBIM SessionID Notes
296 ---------------------------------------------------------
297 untagged IPS 0 a)
298 1 - 255 IPS 1 - 255 <VLANID>
299 256 - 511 DSS 0 - 255 <VLANID - 256>
300 512 - 4093 b)
301 4094 IPS 0 c)
302
303 a) if no VLAN ID 4094 link exists, else dropped
304 b) unsupported VLAN range, unconditionally dropped
305 c) if a VLAN ID 4094 link exists, else dropped
306
307
308
309
310References
311==========
312
313[1] USB Implementers Forum, Inc. - "Universal Serial Bus
314 Communications Class Subclass Specification for Mobile Broadband
315 Interface Model", Revision 1.0 (Errata 1), May 1, 2013
316 - http://www.usb.org/developers/docs/devclass_docs/
317
318[2] USB Implementers Forum, Inc. - "Universal Serial Bus
319 Communications Class Subclass Specifications for Network Control
320 Model Devices", Revision 1.0 (Errata 1), November 24, 2010
321 - http://www.usb.org/developers/docs/devclass_docs/
322
323[3] libmbim - "a glib-based library for talking to WWAN modems and
324 devices which speak the Mobile Interface Broadband Model (MBIM)
325 protocol"
326 - http://www.freedesktop.org/wiki/Software/libmbim/
327
328[4] ModemManager - "a DBus-activated daemon which controls mobile
329 broadband (2G/3G/4G) devices and connections"
330 - http://www.freedesktop.org/wiki/Software/ModemManager/
331
332[5] "MBIM (Mobile Broadband Interface Model) Registry"
333 - http://compliance.usb.org/mbim/
334
335[6] "/proc/bus/usb filesystem output"
336 - Documentation/usb/proc_usb_info.txt
337
338[7] "/sys/bus/usb/devices/.../descriptors"
339 - Documentation/ABI/stable/sysfs-bus-usb
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index 0ab79fca822c..bc23273d0455 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -24,13 +24,21 @@
24#include <net/ipv6.h> 24#include <net/ipv6.h>
25#include <net/addrconf.h> 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/* driver specific data - must match cdc_ncm usage */ 30/* driver specific data - must match cdc_ncm usage */
28struct cdc_mbim_state { 31struct cdc_mbim_state {
29 struct cdc_ncm_ctx *ctx; 32 struct cdc_ncm_ctx *ctx;
30 atomic_t pmcount; 33 atomic_t pmcount;
31 struct usb_driver *subdriver; 34 struct usb_driver *subdriver;
32 struct usb_interface *control; 35 unsigned long _unused;
33 struct usb_interface *data; 36 unsigned long flags;
37};
38
39/* flags for the cdc_mbim_state.flags field */
40enum cdc_mbim_flags {
41 FLAG_IPS0_VLAN = 1 << 0, /* IP session 0 is tagged */
34}; 42};
35 43
36/* using a counter to merge subdriver requests with our own into a combined state */ 44/* 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 return cdc_mbim_manage_power(dev, status); 70 return cdc_mbim_manage_power(dev, status);
63} 71}
64 72
73static int cdc_mbim_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
74{
75 struct usbnet *dev = netdev_priv(netdev);
76 struct cdc_mbim_state *info = (void *)&dev->data;
77
78 /* creation of this VLAN is a request to tag IP session 0 */
79 if (vid == MBIM_IPS0_VID)
80 info->flags |= FLAG_IPS0_VLAN;
81 else
82 if (vid >= 512) /* we don't map these to MBIM session */
83 return -EINVAL;
84 return 0;
85}
86
87static int cdc_mbim_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
88{
89 struct usbnet *dev = netdev_priv(netdev);
90 struct cdc_mbim_state *info = (void *)&dev->data;
91
92 /* this is a request for an untagged IP session 0 */
93 if (vid == MBIM_IPS0_VID)
94 info->flags &= ~FLAG_IPS0_VLAN;
95 return 0;
96}
97
98static const struct net_device_ops cdc_mbim_netdev_ops = {
99 .ndo_open = usbnet_open,
100 .ndo_stop = usbnet_stop,
101 .ndo_start_xmit = usbnet_start_xmit,
102 .ndo_tx_timeout = usbnet_tx_timeout,
103 .ndo_change_mtu = usbnet_change_mtu,
104 .ndo_set_mac_address = eth_mac_addr,
105 .ndo_validate_addr = eth_validate_addr,
106 .ndo_vlan_rx_add_vid = cdc_mbim_rx_add_vid,
107 .ndo_vlan_rx_kill_vid = cdc_mbim_rx_kill_vid,
108};
109
110/* Change the control interface altsetting and update the .driver_info
111 * pointer if the matching entry after changing class codes points to
112 * a different struct
113 */
114static int cdc_mbim_set_ctrlalt(struct usbnet *dev, struct usb_interface *intf, u8 alt)
115{
116 struct usb_driver *driver = to_usb_driver(intf->dev.driver);
117 const struct usb_device_id *id;
118 struct driver_info *info;
119 int ret;
120
121 ret = usb_set_interface(dev->udev,
122 intf->cur_altsetting->desc.bInterfaceNumber,
123 alt);
124 if (ret)
125 return ret;
126
127 id = usb_match_id(intf, driver->id_table);
128 if (!id)
129 return -ENODEV;
130
131 info = (struct driver_info *)id->driver_info;
132 if (info != dev->driver_info) {
133 dev_dbg(&intf->dev, "driver_info updated to '%s'\n",
134 info->description);
135 dev->driver_info = info;
136 }
137 return 0;
138}
65 139
66static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf) 140static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
67{ 141{
68 struct cdc_ncm_ctx *ctx; 142 struct cdc_ncm_ctx *ctx;
69 struct usb_driver *subdriver = ERR_PTR(-ENODEV); 143 struct usb_driver *subdriver = ERR_PTR(-ENODEV);
70 int ret = -ENODEV; 144 int ret = -ENODEV;
71 u8 data_altsetting = cdc_ncm_select_altsetting(dev, intf); 145 u8 data_altsetting = 1;
72 struct cdc_mbim_state *info = (void *)&dev->data; 146 struct cdc_mbim_state *info = (void *)&dev->data;
73 147
74 /* Probably NCM, defer for cdc_ncm_bind */ 148 /* should we change control altsetting on a NCM/MBIM function? */
149 if (cdc_ncm_select_altsetting(intf) == CDC_NCM_COMM_ALTSETTING_MBIM) {
150 data_altsetting = CDC_NCM_DATA_ALTSETTING_MBIM;
151 ret = cdc_mbim_set_ctrlalt(dev, intf, CDC_NCM_COMM_ALTSETTING_MBIM);
152 if (ret)
153 goto err;
154 ret = -ENODEV;
155 }
156
157 /* we will hit this for NCM/MBIM functions if prefer_mbim is false */
75 if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) 158 if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
76 goto err; 159 goto err;
77 160
@@ -101,7 +184,10 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
101 dev->net->flags |= IFF_NOARP; 184 dev->net->flags |= IFF_NOARP;
102 185
103 /* no need to put the VLAN tci in the packet headers */ 186 /* no need to put the VLAN tci in the packet headers */
104 dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX; 187 dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER;
188
189 /* monitor VLAN additions and removals */
190 dev->net->netdev_ops = &cdc_mbim_netdev_ops;
105err: 191err:
106 return ret; 192 return ret;
107} 193}
@@ -164,12 +250,24 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
164 skb_pull(skb, ETH_HLEN); 250 skb_pull(skb, ETH_HLEN);
165 } 251 }
166 252
253 /* Is IP session <0> tagged too? */
254 if (info->flags & FLAG_IPS0_VLAN) {
255 /* drop all untagged packets */
256 if (!tci)
257 goto error;
258 /* map MBIM_IPS0_VID to IPS<0> */
259 if (tci == MBIM_IPS0_VID)
260 tci = 0;
261 }
262
167 /* mapping VLANs to MBIM sessions: 263 /* mapping VLANs to MBIM sessions:
168 * no tag => IPS session <0> 264 * no tag => IPS session <0> if !FLAG_IPS0_VLAN
169 * 1 - 255 => IPS session <vlanid> 265 * 1 - 255 => IPS session <vlanid>
170 * 256 - 511 => DSS session <vlanid - 256> 266 * 256 - 511 => DSS session <vlanid - 256>
171 * 512 - 4095 => unsupported, drop 267 * 512 - 4093 => unsupported, drop
268 * 4094 => IPS session <0> if FLAG_IPS0_VLAN
172 */ 269 */
270
173 switch (tci & 0x0f00) { 271 switch (tci & 0x0f00) {
174 case 0x0000: /* VLAN ID 0 - 255 */ 272 case 0x0000: /* VLAN ID 0 - 255 */
175 if (!is_ip) 273 if (!is_ip)
@@ -178,6 +276,8 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
178 c[3] = tci; 276 c[3] = tci;
179 break; 277 break;
180 case 0x0100: /* VLAN ID 256 - 511 */ 278 case 0x0100: /* VLAN ID 256 - 511 */
279 if (is_ip)
280 goto error;
181 sign = cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN); 281 sign = cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN);
182 c = (u8 *)&sign; 282 c = (u8 *)&sign;
183 c[3] = tci; 283 c[3] = tci;
@@ -268,7 +368,7 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_
268 __be16 proto = htons(ETH_P_802_3); 368 __be16 proto = htons(ETH_P_802_3);
269 struct sk_buff *skb = NULL; 369 struct sk_buff *skb = NULL;
270 370
271 if (tci < 256) { /* IPS session? */ 371 if (tci < 256 || tci == MBIM_IPS0_VID) { /* IPS session? */
272 if (len < sizeof(struct iphdr)) 372 if (len < sizeof(struct iphdr))
273 goto err; 373 goto err;
274 374
@@ -338,6 +438,9 @@ next_ndp:
338 case cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN): 438 case cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN):
339 c = (u8 *)&ndp16->dwSignature; 439 c = (u8 *)&ndp16->dwSignature;
340 tci = c[3]; 440 tci = c[3];
441 /* tag IPS<0> packets too if MBIM_IPS0_VID exists */
442 if (!tci && info->flags & FLAG_IPS0_VLAN)
443 tci = MBIM_IPS0_VID;
341 break; 444 break;
342 case cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN): 445 case cpu_to_le32(USB_CDC_MBIM_NDP16_DSS_SIGN):
343 c = (u8 *)&ndp16->dwSignature; 446 c = (u8 *)&ndp16->dwSignature;
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 9a2bd11943eb..d23bca57a23f 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -541,10 +541,10 @@ void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
541} 541}
542EXPORT_SYMBOL_GPL(cdc_ncm_unbind); 542EXPORT_SYMBOL_GPL(cdc_ncm_unbind);
543 543
544/* Select the MBIM altsetting iff it is preferred and available, 544/* Return the number of the MBIM control interface altsetting iff it
545 * returning the number of the corresponding data interface altsetting 545 * is preferred and available,
546 */ 546 */
547u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf) 547u8 cdc_ncm_select_altsetting(struct usb_interface *intf)
548{ 548{
549 struct usb_host_interface *alt; 549 struct usb_host_interface *alt;
550 550
@@ -563,15 +563,15 @@ u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf)
563 * the rules given in section 6 (USB Device Model) of this 563 * the rules given in section 6 (USB Device Model) of this
564 * specification." 564 * specification."
565 */ 565 */
566 if (prefer_mbim && intf->num_altsetting == 2) { 566 if (intf->num_altsetting < 2)
567 return intf->cur_altsetting->desc.bAlternateSetting;
568
569 if (prefer_mbim) {
567 alt = usb_altnum_to_altsetting(intf, CDC_NCM_COMM_ALTSETTING_MBIM); 570 alt = usb_altnum_to_altsetting(intf, CDC_NCM_COMM_ALTSETTING_MBIM);
568 if (alt && cdc_ncm_comm_intf_is_mbim(alt) && 571 if (alt && cdc_ncm_comm_intf_is_mbim(alt))
569 !usb_set_interface(dev->udev, 572 return CDC_NCM_COMM_ALTSETTING_MBIM;
570 intf->cur_altsetting->desc.bInterfaceNumber,
571 CDC_NCM_COMM_ALTSETTING_MBIM))
572 return CDC_NCM_DATA_ALTSETTING_MBIM;
573 } 573 }
574 return CDC_NCM_DATA_ALTSETTING_NCM; 574 return CDC_NCM_COMM_ALTSETTING_NCM;
575} 575}
576EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting); 576EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting);
577 577
@@ -580,12 +580,11 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
580 int ret; 580 int ret;
581 581
582 /* MBIM backwards compatible function? */ 582 /* MBIM backwards compatible function? */
583 cdc_ncm_select_altsetting(dev, intf); 583 if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
584 if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
585 return -ENODEV; 584 return -ENODEV;
586 585
587 /* NCM data altsetting is always 1 */ 586 /* The NCM data altsetting is fixed */
588 ret = cdc_ncm_bind_common(dev, intf, 1); 587 ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM);
589 588
590 /* 589 /*
591 * We should get an event when network connection is "connected" or 590 * We should get an event when network connection is "connected" or
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index 44b38b92236a..55b6feead93b 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -121,7 +121,7 @@ struct cdc_ncm_ctx {
121 u16 connected; 121 u16 connected;
122}; 122};
123 123
124u8 cdc_ncm_select_altsetting(struct usbnet *dev, struct usb_interface *intf); 124u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
125int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting); 125int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting);
126void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf); 126void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
127struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign); 127struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign);