xref: /OK3568_Linux_fs/kernel/drivers/net/usb/lg-vl600.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Ethernet interface part of the LG VL600 LTE modem (4G dongle)
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2011 Intel Corporation
6*4882a593Smuzhiyun  * Author: Andrzej Zaborowski <balrogg@gmail.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun #include <linux/etherdevice.h>
9*4882a593Smuzhiyun #include <linux/ethtool.h>
10*4882a593Smuzhiyun #include <linux/mii.h>
11*4882a593Smuzhiyun #include <linux/usb.h>
12*4882a593Smuzhiyun #include <linux/usb/cdc.h>
13*4882a593Smuzhiyun #include <linux/usb/usbnet.h>
14*4882a593Smuzhiyun #include <linux/if_ether.h>
15*4882a593Smuzhiyun #include <linux/if_arp.h>
16*4882a593Smuzhiyun #include <linux/inetdevice.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /*
20*4882a593Smuzhiyun  * The device has a CDC ACM port for modem control (it claims to be
21*4882a593Smuzhiyun  * CDC ACM anyway) and a CDC Ethernet port for actual network data.
22*4882a593Smuzhiyun  * It will however ignore data on both ports that is not encapsulated
23*4882a593Smuzhiyun  * in a specific way, any data returned is also encapsulated the same
24*4882a593Smuzhiyun  * way.  The headers don't seem to follow any popular standard.
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  * This driver adds and strips these headers from the ethernet frames
27*4882a593Smuzhiyun  * sent/received from the CDC Ethernet port.  The proprietary header
28*4882a593Smuzhiyun  * replaces the standard ethernet header in a packet so only actual
29*4882a593Smuzhiyun  * ethernet frames are allowed.  The headers allow some form of
30*4882a593Smuzhiyun  * multiplexing by using non standard values of the .h_proto field.
31*4882a593Smuzhiyun  * Windows/Mac drivers do send a couple of such frames to the device
32*4882a593Smuzhiyun  * during initialisation, with protocol set to 0x0906 or 0x0b06 and (what
33*4882a593Smuzhiyun  * seems to be) a flag in the .dummy_flags.  This doesn't seem necessary
34*4882a593Smuzhiyun  * for modem operation but can possibly be used for GPS or other funcitons.
35*4882a593Smuzhiyun  */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun struct vl600_frame_hdr {
38*4882a593Smuzhiyun 	__le32 len;
39*4882a593Smuzhiyun 	__le32 serial;
40*4882a593Smuzhiyun 	__le32 pkt_cnt;
41*4882a593Smuzhiyun 	__le32 dummy_flags;
42*4882a593Smuzhiyun 	__le32 dummy;
43*4882a593Smuzhiyun 	__le32 magic;
44*4882a593Smuzhiyun } __attribute__((packed));
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun struct vl600_pkt_hdr {
47*4882a593Smuzhiyun 	__le32 dummy[2];
48*4882a593Smuzhiyun 	__le32 len;
49*4882a593Smuzhiyun 	__be16 h_proto;
50*4882a593Smuzhiyun } __attribute__((packed));
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun struct vl600_state {
53*4882a593Smuzhiyun 	struct sk_buff *current_rx_buf;
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
vl600_bind(struct usbnet * dev,struct usb_interface * intf)56*4882a593Smuzhiyun static int vl600_bind(struct usbnet *dev, struct usb_interface *intf)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	int ret;
59*4882a593Smuzhiyun 	struct vl600_state *s = kzalloc(sizeof(struct vl600_state), GFP_KERNEL);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	if (!s)
62*4882a593Smuzhiyun 		return -ENOMEM;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	ret = usbnet_cdc_bind(dev, intf);
65*4882a593Smuzhiyun 	if (ret) {
66*4882a593Smuzhiyun 		kfree(s);
67*4882a593Smuzhiyun 		return ret;
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	dev->driver_priv = s;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	/* ARP packets don't go through, but they're also of no use.  The
73*4882a593Smuzhiyun 	 * subnet has only two hosts anyway: us and the gateway / DHCP
74*4882a593Smuzhiyun 	 * server (probably simulated by modem firmware or network operator)
75*4882a593Smuzhiyun 	 * whose address changes everytime we connect to the intarwebz and
76*4882a593Smuzhiyun 	 * who doesn't bother answering ARP requests either.  So hardware
77*4882a593Smuzhiyun 	 * addresses have no meaning, the destination and the source of every
78*4882a593Smuzhiyun 	 * packet depend only on whether it is on the IN or OUT endpoint.  */
79*4882a593Smuzhiyun 	dev->net->flags |= IFF_NOARP;
80*4882a593Smuzhiyun 	/* IPv6 NDP relies on multicast.  Enable it by default. */
81*4882a593Smuzhiyun 	dev->net->flags |= IFF_MULTICAST;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	return ret;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
vl600_unbind(struct usbnet * dev,struct usb_interface * intf)86*4882a593Smuzhiyun static void vl600_unbind(struct usbnet *dev, struct usb_interface *intf)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	struct vl600_state *s = dev->driver_priv;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	dev_kfree_skb(s->current_rx_buf);
91*4882a593Smuzhiyun 	kfree(s);
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	return usbnet_cdc_unbind(dev, intf);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
vl600_rx_fixup(struct usbnet * dev,struct sk_buff * skb)96*4882a593Smuzhiyun static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	struct vl600_frame_hdr *frame;
99*4882a593Smuzhiyun 	struct vl600_pkt_hdr *packet;
100*4882a593Smuzhiyun 	struct ethhdr *ethhdr;
101*4882a593Smuzhiyun 	int packet_len, count;
102*4882a593Smuzhiyun 	struct sk_buff *buf = skb;
103*4882a593Smuzhiyun 	struct sk_buff *clone;
104*4882a593Smuzhiyun 	struct vl600_state *s = dev->driver_priv;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	/* Frame lengths are generally 4B multiplies but every couple of
107*4882a593Smuzhiyun 	 * hours there's an odd number of bytes sized yet correct frame,
108*4882a593Smuzhiyun 	 * so don't require this.  */
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	/* Allow a packet (or multiple packets batched together) to be
111*4882a593Smuzhiyun 	 * split across many frames.  We don't allow a new batch to
112*4882a593Smuzhiyun 	 * begin in the same frame another one is ending however, and no
113*4882a593Smuzhiyun 	 * leading or trailing pad bytes.  */
114*4882a593Smuzhiyun 	if (s->current_rx_buf) {
115*4882a593Smuzhiyun 		frame = (struct vl600_frame_hdr *) s->current_rx_buf->data;
116*4882a593Smuzhiyun 		if (skb->len + s->current_rx_buf->len >
117*4882a593Smuzhiyun 				le32_to_cpup(&frame->len)) {
118*4882a593Smuzhiyun 			netif_err(dev, ifup, dev->net, "Fragment too long\n");
119*4882a593Smuzhiyun 			dev->net->stats.rx_length_errors++;
120*4882a593Smuzhiyun 			goto error;
121*4882a593Smuzhiyun 		}
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 		buf = s->current_rx_buf;
124*4882a593Smuzhiyun 		skb_put_data(buf, skb->data, skb->len);
125*4882a593Smuzhiyun 	} else if (skb->len < 4) {
126*4882a593Smuzhiyun 		netif_err(dev, ifup, dev->net, "Frame too short\n");
127*4882a593Smuzhiyun 		dev->net->stats.rx_length_errors++;
128*4882a593Smuzhiyun 		goto error;
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	frame = (struct vl600_frame_hdr *) buf->data;
132*4882a593Smuzhiyun 	/* Yes, check that frame->magic == 0x53544448 (or 0x44544d48),
133*4882a593Smuzhiyun 	 * otherwise we may run out of memory w/a bad packet */
134*4882a593Smuzhiyun 	if (ntohl(frame->magic) != 0x53544448 &&
135*4882a593Smuzhiyun 			ntohl(frame->magic) != 0x44544d48)
136*4882a593Smuzhiyun 		goto error;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	if (buf->len < sizeof(*frame) ||
139*4882a593Smuzhiyun 			buf->len != le32_to_cpup(&frame->len)) {
140*4882a593Smuzhiyun 		/* Save this fragment for later assembly */
141*4882a593Smuzhiyun 		if (s->current_rx_buf)
142*4882a593Smuzhiyun 			return 0;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 		s->current_rx_buf = skb_copy_expand(skb, 0,
145*4882a593Smuzhiyun 				le32_to_cpup(&frame->len), GFP_ATOMIC);
146*4882a593Smuzhiyun 		if (!s->current_rx_buf)
147*4882a593Smuzhiyun 			dev->net->stats.rx_errors++;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 		return 0;
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	count = le32_to_cpup(&frame->pkt_cnt);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	skb_pull(buf, sizeof(*frame));
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	while (count--) {
157*4882a593Smuzhiyun 		if (buf->len < sizeof(*packet)) {
158*4882a593Smuzhiyun 			netif_err(dev, ifup, dev->net, "Packet too short\n");
159*4882a593Smuzhiyun 			goto error;
160*4882a593Smuzhiyun 		}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 		packet = (struct vl600_pkt_hdr *) buf->data;
163*4882a593Smuzhiyun 		packet_len = sizeof(*packet) + le32_to_cpup(&packet->len);
164*4882a593Smuzhiyun 		if (packet_len > buf->len) {
165*4882a593Smuzhiyun 			netif_err(dev, ifup, dev->net,
166*4882a593Smuzhiyun 					"Bad packet length stored in header\n");
167*4882a593Smuzhiyun 			goto error;
168*4882a593Smuzhiyun 		}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 		/* Packet header is same size as the ethernet header
171*4882a593Smuzhiyun 		 * (sizeof(*packet) == sizeof(*ethhdr)), additionally
172*4882a593Smuzhiyun 		 * the h_proto field is in the same place so we just leave it
173*4882a593Smuzhiyun 		 * alone and fill in the remaining fields.
174*4882a593Smuzhiyun 		 */
175*4882a593Smuzhiyun 		ethhdr = (struct ethhdr *) skb->data;
176*4882a593Smuzhiyun 		if (be16_to_cpup(&ethhdr->h_proto) == ETH_P_ARP &&
177*4882a593Smuzhiyun 				buf->len > 0x26) {
178*4882a593Smuzhiyun 			/* Copy the addresses from packet contents */
179*4882a593Smuzhiyun 			memcpy(ethhdr->h_source,
180*4882a593Smuzhiyun 					&buf->data[sizeof(*ethhdr) + 0x8],
181*4882a593Smuzhiyun 					ETH_ALEN);
182*4882a593Smuzhiyun 			memcpy(ethhdr->h_dest,
183*4882a593Smuzhiyun 					&buf->data[sizeof(*ethhdr) + 0x12],
184*4882a593Smuzhiyun 					ETH_ALEN);
185*4882a593Smuzhiyun 		} else {
186*4882a593Smuzhiyun 			eth_zero_addr(ethhdr->h_source);
187*4882a593Smuzhiyun 			memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 			/* Inbound IPv6 packets have an IPv4 ethertype (0x800)
190*4882a593Smuzhiyun 			 * for some reason.  Peek at the L3 header to check
191*4882a593Smuzhiyun 			 * for IPv6 packets, and set the ethertype to IPv6
192*4882a593Smuzhiyun 			 * (0x86dd) so Linux can understand it.
193*4882a593Smuzhiyun 			 */
194*4882a593Smuzhiyun 			if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60)
195*4882a593Smuzhiyun 				ethhdr->h_proto = htons(ETH_P_IPV6);
196*4882a593Smuzhiyun 		}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 		if (count) {
199*4882a593Smuzhiyun 			/* Not the last packet in this batch */
200*4882a593Smuzhiyun 			clone = skb_clone(buf, GFP_ATOMIC);
201*4882a593Smuzhiyun 			if (!clone)
202*4882a593Smuzhiyun 				goto error;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 			skb_trim(clone, packet_len);
205*4882a593Smuzhiyun 			usbnet_skb_return(dev, clone);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 			skb_pull(buf, (packet_len + 3) & ~3);
208*4882a593Smuzhiyun 		} else {
209*4882a593Smuzhiyun 			skb_trim(buf, packet_len);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 			if (s->current_rx_buf) {
212*4882a593Smuzhiyun 				usbnet_skb_return(dev, buf);
213*4882a593Smuzhiyun 				s->current_rx_buf = NULL;
214*4882a593Smuzhiyun 				return 0;
215*4882a593Smuzhiyun 			}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 			return 1;
218*4882a593Smuzhiyun 		}
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun error:
222*4882a593Smuzhiyun 	if (s->current_rx_buf) {
223*4882a593Smuzhiyun 		dev_kfree_skb_any(s->current_rx_buf);
224*4882a593Smuzhiyun 		s->current_rx_buf = NULL;
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun 	dev->net->stats.rx_errors++;
227*4882a593Smuzhiyun 	return 0;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
vl600_tx_fixup(struct usbnet * dev,struct sk_buff * skb,gfp_t flags)230*4882a593Smuzhiyun static struct sk_buff *vl600_tx_fixup(struct usbnet *dev,
231*4882a593Smuzhiyun 		struct sk_buff *skb, gfp_t flags)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct sk_buff *ret;
234*4882a593Smuzhiyun 	struct vl600_frame_hdr *frame;
235*4882a593Smuzhiyun 	struct vl600_pkt_hdr *packet;
236*4882a593Smuzhiyun 	static uint32_t serial = 1;
237*4882a593Smuzhiyun 	int orig_len = skb->len - sizeof(struct ethhdr);
238*4882a593Smuzhiyun 	int full_len = (skb->len + sizeof(struct vl600_frame_hdr) + 3) & ~3;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	frame = (struct vl600_frame_hdr *) skb->data;
241*4882a593Smuzhiyun 	if (skb->len > sizeof(*frame) && skb->len == le32_to_cpup(&frame->len))
242*4882a593Smuzhiyun 		return skb; /* Already encapsulated? */
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (skb->len < sizeof(struct ethhdr))
245*4882a593Smuzhiyun 		/* Drop, device can only deal with ethernet packets */
246*4882a593Smuzhiyun 		return NULL;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	if (!skb_cloned(skb)) {
249*4882a593Smuzhiyun 		int headroom = skb_headroom(skb);
250*4882a593Smuzhiyun 		int tailroom = skb_tailroom(skb);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 		if (tailroom >= full_len - skb->len - sizeof(*frame) &&
253*4882a593Smuzhiyun 				headroom >= sizeof(*frame))
254*4882a593Smuzhiyun 			/* There's enough head and tail room */
255*4882a593Smuzhiyun 			goto encapsulate;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		if (headroom + tailroom + skb->len >= full_len) {
258*4882a593Smuzhiyun 			/* There's enough total room, just readjust */
259*4882a593Smuzhiyun 			skb->data = memmove(skb->head + sizeof(*frame),
260*4882a593Smuzhiyun 					skb->data, skb->len);
261*4882a593Smuzhiyun 			skb_set_tail_pointer(skb, skb->len);
262*4882a593Smuzhiyun 			goto encapsulate;
263*4882a593Smuzhiyun 		}
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	/* Alloc a new skb with the required size */
267*4882a593Smuzhiyun 	ret = skb_copy_expand(skb, sizeof(struct vl600_frame_hdr), full_len -
268*4882a593Smuzhiyun 			skb->len - sizeof(struct vl600_frame_hdr), flags);
269*4882a593Smuzhiyun 	dev_kfree_skb_any(skb);
270*4882a593Smuzhiyun 	if (!ret)
271*4882a593Smuzhiyun 		return ret;
272*4882a593Smuzhiyun 	skb = ret;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun encapsulate:
275*4882a593Smuzhiyun 	/* Packet header is same size as ethernet packet header
276*4882a593Smuzhiyun 	 * (sizeof(*packet) == sizeof(struct ethhdr)), additionally the
277*4882a593Smuzhiyun 	 * h_proto field is in the same place so we just leave it alone and
278*4882a593Smuzhiyun 	 * overwrite the remaining fields.
279*4882a593Smuzhiyun 	 */
280*4882a593Smuzhiyun 	packet = (struct vl600_pkt_hdr *) skb->data;
281*4882a593Smuzhiyun 	/* The VL600 wants IPv6 packets to have an IPv4 ethertype
282*4882a593Smuzhiyun 	 * Since this modem only supports IPv4 and IPv6, just set all
283*4882a593Smuzhiyun 	 * frames to 0x0800 (ETH_P_IP)
284*4882a593Smuzhiyun 	 */
285*4882a593Smuzhiyun 	packet->h_proto = htons(ETH_P_IP);
286*4882a593Smuzhiyun 	memset(&packet->dummy, 0, sizeof(packet->dummy));
287*4882a593Smuzhiyun 	packet->len = cpu_to_le32(orig_len);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	frame = skb_push(skb, sizeof(*frame));
290*4882a593Smuzhiyun 	memset(frame, 0, sizeof(*frame));
291*4882a593Smuzhiyun 	frame->len = cpu_to_le32(full_len);
292*4882a593Smuzhiyun 	frame->serial = cpu_to_le32(serial++);
293*4882a593Smuzhiyun 	frame->pkt_cnt = cpu_to_le32(1);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (skb->len < full_len) /* Pad */
296*4882a593Smuzhiyun 		skb_put(skb, full_len - skb->len);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	return skb;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun static const struct driver_info	vl600_info = {
302*4882a593Smuzhiyun 	.description	= "LG VL600 modem",
303*4882a593Smuzhiyun 	.flags		= FLAG_RX_ASSEMBLE | FLAG_WWAN,
304*4882a593Smuzhiyun 	.bind		= vl600_bind,
305*4882a593Smuzhiyun 	.unbind		= vl600_unbind,
306*4882a593Smuzhiyun 	.status		= usbnet_cdc_status,
307*4882a593Smuzhiyun 	.rx_fixup	= vl600_rx_fixup,
308*4882a593Smuzhiyun 	.tx_fixup	= vl600_tx_fixup,
309*4882a593Smuzhiyun };
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun static const struct usb_device_id products[] = {
312*4882a593Smuzhiyun 	{
313*4882a593Smuzhiyun 		USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM,
314*4882a593Smuzhiyun 				USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
315*4882a593Smuzhiyun 		.driver_info	= (unsigned long) &vl600_info,
316*4882a593Smuzhiyun 	},
317*4882a593Smuzhiyun 	{},	/* End */
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, products);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun static struct usb_driver lg_vl600_driver = {
322*4882a593Smuzhiyun 	.name		= "lg-vl600",
323*4882a593Smuzhiyun 	.id_table	= products,
324*4882a593Smuzhiyun 	.probe		= usbnet_probe,
325*4882a593Smuzhiyun 	.disconnect	= usbnet_disconnect,
326*4882a593Smuzhiyun 	.suspend	= usbnet_suspend,
327*4882a593Smuzhiyun 	.resume		= usbnet_resume,
328*4882a593Smuzhiyun 	.disable_hub_initiated_lpm = 1,
329*4882a593Smuzhiyun };
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun module_usb_driver(lg_vl600_driver);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun MODULE_AUTHOR("Anrzej Zaborowski");
334*4882a593Smuzhiyun MODULE_DESCRIPTION("LG-VL600 modem's ethernet link");
335*4882a593Smuzhiyun MODULE_LICENSE("GPL");
336