Skip to content

Commit 8491cd0

Browse files
Xie Hegregkh
Xie He
authored andcommitted
drivers/net/wan/hdlc_fr: Correctly handle special skb->protocol values
[ Upstream commit 8306266 ] The fr_hard_header function is used to prepend the header to skbs before transmission. It is used in 3 situations: 1) When a control packet is generated internally in this driver; 2) When a user sends an skb on an Ethernet-emulating PVC device; 3) When a user sends an skb on a normal PVC device. These 3 situations need to be handled differently by fr_hard_header. Different headers should be prepended to the skb in different situations. Currently fr_hard_header distinguishes these 3 situations using skb->protocol. For situation 1 and 2, a special skb->protocol value will be assigned before calling fr_hard_header, so that it can recognize these 2 situations. All skb->protocol values other than these special ones are treated by fr_hard_header as situation 3. However, it is possible that in situation 3, the user sends an skb with one of the special skb->protocol values. In this case, fr_hard_header would incorrectly treat it as situation 1 or 2. This patch tries to solve this issue by using skb->dev instead of skb->protocol to distinguish between these 3 situations. For situation 1, skb->dev would be NULL; for situation 2, skb->dev->type would be ARPHRD_ETHER; and for situation 3, skb->dev->type would be ARPHRD_DLCI. This way fr_hard_header would be able to distinguish these 3 situations correctly regardless what skb->protocol value the user tries to use in situation 3. Cc: Krzysztof Halasa <[email protected]> Signed-off-by: Xie He <[email protected]> Signed-off-by: David S. Miller <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 56e567f commit 8491cd0

File tree

1 file changed

+51
-47
lines changed

1 file changed

+51
-47
lines changed

drivers/net/wan/hdlc_fr.c

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -273,63 +273,69 @@ static inline struct net_device **get_dev_p(struct pvc_device *pvc,
273273

274274
static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
275275
{
276-
u16 head_len;
277276
struct sk_buff *skb = *skb_p;
278277

279-
switch (skb->protocol) {
280-
case cpu_to_be16(NLPID_CCITT_ANSI_LMI):
281-
head_len = 4;
282-
skb_push(skb, head_len);
283-
skb->data[3] = NLPID_CCITT_ANSI_LMI;
284-
break;
285-
286-
case cpu_to_be16(NLPID_CISCO_LMI):
287-
head_len = 4;
288-
skb_push(skb, head_len);
289-
skb->data[3] = NLPID_CISCO_LMI;
290-
break;
291-
292-
case cpu_to_be16(ETH_P_IP):
293-
head_len = 4;
294-
skb_push(skb, head_len);
295-
skb->data[3] = NLPID_IP;
296-
break;
297-
298-
case cpu_to_be16(ETH_P_IPV6):
299-
head_len = 4;
300-
skb_push(skb, head_len);
301-
skb->data[3] = NLPID_IPV6;
302-
break;
303-
304-
case cpu_to_be16(ETH_P_802_3):
305-
head_len = 10;
306-
if (skb_headroom(skb) < head_len) {
307-
struct sk_buff *skb2 = skb_realloc_headroom(skb,
308-
head_len);
278+
if (!skb->dev) { /* Control packets */
279+
switch (dlci) {
280+
case LMI_CCITT_ANSI_DLCI:
281+
skb_push(skb, 4);
282+
skb->data[3] = NLPID_CCITT_ANSI_LMI;
283+
break;
284+
285+
case LMI_CISCO_DLCI:
286+
skb_push(skb, 4);
287+
skb->data[3] = NLPID_CISCO_LMI;
288+
break;
289+
290+
default:
291+
return -EINVAL;
292+
}
293+
294+
} else if (skb->dev->type == ARPHRD_DLCI) {
295+
switch (skb->protocol) {
296+
case htons(ETH_P_IP):
297+
skb_push(skb, 4);
298+
skb->data[3] = NLPID_IP;
299+
break;
300+
301+
case htons(ETH_P_IPV6):
302+
skb_push(skb, 4);
303+
skb->data[3] = NLPID_IPV6;
304+
break;
305+
306+
default:
307+
skb_push(skb, 10);
308+
skb->data[3] = FR_PAD;
309+
skb->data[4] = NLPID_SNAP;
310+
/* OUI 00-00-00 indicates an Ethertype follows */
311+
skb->data[5] = 0x00;
312+
skb->data[6] = 0x00;
313+
skb->data[7] = 0x00;
314+
/* This should be an Ethertype: */
315+
*(__be16 *)(skb->data + 8) = skb->protocol;
316+
}
317+
318+
} else if (skb->dev->type == ARPHRD_ETHER) {
319+
if (skb_headroom(skb) < 10) {
320+
struct sk_buff *skb2 = skb_realloc_headroom(skb, 10);
309321
if (!skb2)
310322
return -ENOBUFS;
311323
dev_kfree_skb(skb);
312324
skb = *skb_p = skb2;
313325
}
314-
skb_push(skb, head_len);
326+
skb_push(skb, 10);
315327
skb->data[3] = FR_PAD;
316328
skb->data[4] = NLPID_SNAP;
317-
skb->data[5] = FR_PAD;
329+
/* OUI 00-80-C2 stands for the 802.1 organization */
330+
skb->data[5] = 0x00;
318331
skb->data[6] = 0x80;
319332
skb->data[7] = 0xC2;
333+
/* PID 00-07 stands for Ethernet frames without FCS */
320334
skb->data[8] = 0x00;
321-
skb->data[9] = 0x07; /* bridged Ethernet frame w/out FCS */
322-
break;
335+
skb->data[9] = 0x07;
323336

324-
default:
325-
head_len = 10;
326-
skb_push(skb, head_len);
327-
skb->data[3] = FR_PAD;
328-
skb->data[4] = NLPID_SNAP;
329-
skb->data[5] = FR_PAD;
330-
skb->data[6] = FR_PAD;
331-
skb->data[7] = FR_PAD;
332-
*(__be16*)(skb->data + 8) = skb->protocol;
337+
} else {
338+
return -EINVAL;
333339
}
334340

335341
dlci_to_q922(skb->data, dlci);
@@ -425,8 +431,8 @@ static netdev_tx_t pvc_xmit(struct sk_buff *skb, struct net_device *dev)
425431
skb_put(skb, pad);
426432
memset(skb->data + len, 0, pad);
427433
}
428-
skb->protocol = cpu_to_be16(ETH_P_802_3);
429434
}
435+
skb->dev = dev;
430436
if (!fr_hard_header(&skb, pvc->dlci)) {
431437
dev->stats.tx_bytes += skb->len;
432438
dev->stats.tx_packets++;
@@ -494,10 +500,8 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
494500
memset(skb->data, 0, len);
495501
skb_reserve(skb, 4);
496502
if (lmi == LMI_CISCO) {
497-
skb->protocol = cpu_to_be16(NLPID_CISCO_LMI);
498503
fr_hard_header(&skb, LMI_CISCO_DLCI);
499504
} else {
500-
skb->protocol = cpu_to_be16(NLPID_CCITT_ANSI_LMI);
501505
fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI);
502506
}
503507
data = skb_tail_pointer(skb);

0 commit comments

Comments
 (0)