Skip to content

Commit 68cac07

Browse files
StefanBruensgregkh
authored andcommitted
sierra_net: Add support for IPv6 and Dual-Stack Link Sense Indications
[ Upstream commit 5a70348e1187c5bf1cbd0ec51843f36befed1c2d ] If a context is configured as dualstack ("IPv4v6"), the modem indicates the context activation with a slightly different indication message. The dual-stack indication omits the link_type (IPv4/v6) and adds additional address fields. IPv6 LSIs are identical to IPv4 LSIs, but have a different link type. Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de> Reviewed-by: Bjørn Mork <bjorn@mork.no> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <alexander.levin@verizon.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d95ffdd commit 68cac07

1 file changed

Lines changed: 66 additions & 35 deletions

File tree

drivers/net/usb/sierra_net.c

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@ static atomic_t iface_counter = ATOMIC_INIT(0);
7373
/* Private data structure */
7474
struct sierra_net_data {
7575

76-
u8 ethr_hdr_tmpl[ETH_HLEN]; /* ethernet header template for rx'd pkts */
77-
7876
u16 link_up; /* air link up or down */
7977
u8 tx_hdr_template[4]; /* part of HIP hdr for tx'd packets */
8078

@@ -122,24 +120,31 @@ struct param {
122120

123121
/* LSI Protocol types */
124122
#define SIERRA_NET_PROTOCOL_UMTS 0x01
123+
#define SIERRA_NET_PROTOCOL_UMTS_DS 0x04
125124
/* LSI Coverage */
126125
#define SIERRA_NET_COVERAGE_NONE 0x00
127126
#define SIERRA_NET_COVERAGE_NOPACKET 0x01
128127

129128
/* LSI Session */
130129
#define SIERRA_NET_SESSION_IDLE 0x00
131130
/* LSI Link types */
132-
#define SIERRA_NET_AS_LINK_TYPE_IPv4 0x00
131+
#define SIERRA_NET_AS_LINK_TYPE_IPV4 0x00
132+
#define SIERRA_NET_AS_LINK_TYPE_IPV6 0x02
133133

134134
struct lsi_umts {
135135
u8 protocol;
136136
u8 unused1;
137137
__be16 length;
138138
/* eventually use a union for the rest - assume umts for now */
139139
u8 coverage;
140-
u8 unused2[41];
140+
u8 network_len; /* network name len */
141+
u8 network[40]; /* network name (UCS2, bigendian) */
141142
u8 session_state;
142143
u8 unused3[33];
144+
} __packed;
145+
146+
struct lsi_umts_single {
147+
struct lsi_umts lsi;
143148
u8 link_type;
144149
u8 pdp_addr_len; /* NW-supplied PDP address len */
145150
u8 pdp_addr[16]; /* NW-supplied PDP address (bigendian)) */
@@ -158,10 +163,31 @@ struct lsi_umts {
158163
u8 reserved[8];
159164
} __packed;
160165

166+
struct lsi_umts_dual {
167+
struct lsi_umts lsi;
168+
u8 pdp_addr4_len; /* NW-supplied PDP IPv4 address len */
169+
u8 pdp_addr4[4]; /* NW-supplied PDP IPv4 address (bigendian)) */
170+
u8 pdp_addr6_len; /* NW-supplied PDP IPv6 address len */
171+
u8 pdp_addr6[16]; /* NW-supplied PDP IPv6 address (bigendian)) */
172+
u8 unused4[23];
173+
u8 dns1_addr4_len; /* NW-supplied 1st DNS v4 address len (bigendian) */
174+
u8 dns1_addr4[4]; /* NW-supplied 1st DNS v4 address */
175+
u8 dns1_addr6_len; /* NW-supplied 1st DNS v6 address len */
176+
u8 dns1_addr6[16]; /* NW-supplied 1st DNS v6 address (bigendian)*/
177+
u8 dns2_addr4_len; /* NW-supplied 2nd DNS v4 address len (bigendian) */
178+
u8 dns2_addr4[4]; /* NW-supplied 2nd DNS v4 address */
179+
u8 dns2_addr6_len; /* NW-supplied 2nd DNS v6 address len */
180+
u8 dns2_addr6[16]; /* NW-supplied 2nd DNS v6 address (bigendian)*/
181+
u8 unused5[68];
182+
} __packed;
183+
161184
#define SIERRA_NET_LSI_COMMON_LEN 4
162-
#define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts))
185+
#define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts_single))
163186
#define SIERRA_NET_LSI_UMTS_STATUS_LEN \
164187
(SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN)
188+
#define SIERRA_NET_LSI_UMTS_DS_LEN (sizeof(struct lsi_umts_dual))
189+
#define SIERRA_NET_LSI_UMTS_DS_STATUS_LEN \
190+
(SIERRA_NET_LSI_UMTS_DS_LEN - SIERRA_NET_LSI_COMMON_LEN)
165191

166192
/* Forward definitions */
167193
static void sierra_sync_timer(unsigned long syncdata);
@@ -191,10 +217,11 @@ static inline void sierra_net_set_private(struct usbnet *dev,
191217
dev->data[0] = (unsigned long)priv;
192218
}
193219

194-
/* is packet IPv4 */
220+
/* is packet IPv4/IPv6 */
195221
static inline int is_ip(struct sk_buff *skb)
196222
{
197-
return skb->protocol == cpu_to_be16(ETH_P_IP);
223+
return skb->protocol == cpu_to_be16(ETH_P_IP) ||
224+
skb->protocol == cpu_to_be16(ETH_P_IPV6);
198225
}
199226

200227
/*
@@ -350,18 +377,11 @@ static inline int sierra_net_is_valid_addrlen(u8 len)
350377
static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen)
351378
{
352379
struct lsi_umts *lsi = (struct lsi_umts *)data;
380+
u32 expected_length;
353381

354-
if (datalen < sizeof(struct lsi_umts)) {
355-
netdev_err(dev->net, "%s: Data length %d, exp %Zu\n",
356-
__func__, datalen,
357-
sizeof(struct lsi_umts));
358-
return -1;
359-
}
360-
361-
if (lsi->length != cpu_to_be16(SIERRA_NET_LSI_UMTS_STATUS_LEN)) {
362-
netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n",
363-
__func__, be16_to_cpu(lsi->length),
364-
(u32)SIERRA_NET_LSI_UMTS_STATUS_LEN);
382+
if (datalen < sizeof(struct lsi_umts_single)) {
383+
netdev_err(dev->net, "%s: Data length %d, exp >= %Zu\n",
384+
__func__, datalen, sizeof(struct lsi_umts_single));
365385
return -1;
366386
}
367387

@@ -373,22 +393,34 @@ static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen)
373393
}
374394

375395
/* Validate the protocol - only support UMTS for now */
376-
if (lsi->protocol != SIERRA_NET_PROTOCOL_UMTS) {
396+
if (lsi->protocol == SIERRA_NET_PROTOCOL_UMTS) {
397+
struct lsi_umts_single *single = (struct lsi_umts_single *)lsi;
398+
399+
/* Validate the link type */
400+
if (single->link_type != SIERRA_NET_AS_LINK_TYPE_IPV4 &&
401+
single->link_type != SIERRA_NET_AS_LINK_TYPE_IPV6) {
402+
netdev_err(dev->net, "Link type unsupported: 0x%02x\n",
403+
single->link_type);
404+
return -1;
405+
}
406+
expected_length = SIERRA_NET_LSI_UMTS_STATUS_LEN;
407+
} else if (lsi->protocol == SIERRA_NET_PROTOCOL_UMTS_DS) {
408+
expected_length = SIERRA_NET_LSI_UMTS_DS_STATUS_LEN;
409+
} else {
377410
netdev_err(dev->net, "Protocol unsupported, 0x%02x\n",
378-
lsi->protocol);
411+
lsi->protocol);
379412
return -1;
380413
}
381414

382-
/* Validate the link type */
383-
if (lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) {
384-
netdev_err(dev->net, "Link type unsupported: 0x%02x\n",
385-
lsi->link_type);
415+
if (be16_to_cpu(lsi->length) != expected_length) {
416+
netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n",
417+
__func__, be16_to_cpu(lsi->length), expected_length);
386418
return -1;
387419
}
388420

389421
/* Validate the coverage */
390-
if (lsi->coverage == SIERRA_NET_COVERAGE_NONE
391-
|| lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) {
422+
if (lsi->coverage == SIERRA_NET_COVERAGE_NONE ||
423+
lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) {
392424
netdev_err(dev->net, "No coverage, 0x%02x\n", lsi->coverage);
393425
return 0;
394426
}
@@ -662,7 +694,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
662694
u8 numendpoints;
663695
u16 fwattr = 0;
664696
int status;
665-
struct ethhdr *eth;
666697
struct sierra_net_data *priv;
667698
static const u8 sync_tmplate[sizeof(priv->sync_msg)] = {
668699
0x00, 0x00, SIERRA_NET_HIP_MSYNC_ID, 0x00};
@@ -700,11 +731,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
700731
dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter);
701732
dev->net->dev_addr[ETH_ALEN-1] = ifacenum;
702733

703-
/* we will have to manufacture ethernet headers, prepare template */
704-
eth = (struct ethhdr *)priv->ethr_hdr_tmpl;
705-
memcpy(&eth->h_dest, dev->net->dev_addr, ETH_ALEN);
706-
eth->h_proto = cpu_to_be16(ETH_P_IP);
707-
708734
/* prepare shutdown message template */
709735
memcpy(priv->shdwn_msg, shdwn_tmplate, sizeof(priv->shdwn_msg));
710736
/* set context index initially to 0 - prepares tx hdr template */
@@ -833,9 +859,14 @@ static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
833859

834860
skb_pull(skb, hh.hdrlen);
835861

836-
/* We are going to accept this packet, prepare it */
837-
memcpy(skb->data, sierra_net_get_private(dev)->ethr_hdr_tmpl,
838-
ETH_HLEN);
862+
/* We are going to accept this packet, prepare it.
863+
* In case protocol is IPv6, keep it, otherwise force IPv4.
864+
*/
865+
skb_reset_mac_header(skb);
866+
if (eth_hdr(skb)->h_proto != cpu_to_be16(ETH_P_IPV6))
867+
eth_hdr(skb)->h_proto = cpu_to_be16(ETH_P_IP);
868+
eth_zero_addr(eth_hdr(skb)->h_source);
869+
memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
839870

840871
/* Last packet in batch handled by usbnet */
841872
if (hh.payload_len.word == skb->len)

0 commit comments

Comments
 (0)