diff options
Diffstat (limited to 'drivers/ieee1394/eth1394.c')
-rw-r--r-- | drivers/ieee1394/eth1394.c | 21 |
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 5f026b5d7857..7c13fb3c167b 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c | |||
@@ -1565,7 +1565,7 @@ static void ether1394_complete_cb(void *__ptask) | |||
1565 | /* Transmit a packet (called by kernel) */ | 1565 | /* Transmit a packet (called by kernel) */ |
1566 | static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) | 1566 | static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) |
1567 | { | 1567 | { |
1568 | struct eth1394hdr *eth; | 1568 | struct eth1394hdr hdr_buf; |
1569 | struct eth1394_priv *priv = netdev_priv(dev); | 1569 | struct eth1394_priv *priv = netdev_priv(dev); |
1570 | __be16 proto; | 1570 | __be16 proto; |
1571 | unsigned long flags; | 1571 | unsigned long flags; |
@@ -1595,16 +1595,17 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) | |||
1595 | if (!skb) | 1595 | if (!skb) |
1596 | goto fail; | 1596 | goto fail; |
1597 | 1597 | ||
1598 | /* Get rid of the fake eth1394 header, but save a pointer */ | 1598 | /* Get rid of the fake eth1394 header, but first make a copy. |
1599 | eth = (struct eth1394hdr *)skb->data; | 1599 | * We might need to rebuild the header on tx failure. */ |
1600 | memcpy(&hdr_buf, skb->data, sizeof(hdr_buf)); | ||
1600 | skb_pull(skb, ETH1394_HLEN); | 1601 | skb_pull(skb, ETH1394_HLEN); |
1601 | 1602 | ||
1602 | proto = eth->h_proto; | 1603 | proto = hdr_buf.h_proto; |
1603 | dg_size = skb->len; | 1604 | dg_size = skb->len; |
1604 | 1605 | ||
1605 | /* Set the transmission type for the packet. ARP packets and IP | 1606 | /* Set the transmission type for the packet. ARP packets and IP |
1606 | * broadcast packets are sent via GASP. */ | 1607 | * broadcast packets are sent via GASP. */ |
1607 | if (memcmp(eth->h_dest, dev->broadcast, ETH1394_ALEN) == 0 || | 1608 | if (memcmp(hdr_buf.h_dest, dev->broadcast, ETH1394_ALEN) == 0 || |
1608 | proto == htons(ETH_P_ARP) || | 1609 | proto == htons(ETH_P_ARP) || |
1609 | (proto == htons(ETH_P_IP) && | 1610 | (proto == htons(ETH_P_IP) && |
1610 | IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) { | 1611 | IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) { |
@@ -1616,7 +1617,7 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) | |||
1616 | if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) | 1617 | if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) |
1617 | priv->bc_dgl++; | 1618 | priv->bc_dgl++; |
1618 | } else { | 1619 | } else { |
1619 | __be64 guid = get_unaligned((u64 *)eth->h_dest); | 1620 | __be64 guid = get_unaligned((u64 *)hdr_buf.h_dest); |
1620 | 1621 | ||
1621 | node = eth1394_find_node_guid(&priv->ip_node_list, | 1622 | node = eth1394_find_node_guid(&priv->ip_node_list, |
1622 | be64_to_cpu(guid)); | 1623 | be64_to_cpu(guid)); |
@@ -1673,6 +1674,14 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) | |||
1673 | if (dest_node == (LOCAL_BUS | ALL_NODES)) | 1674 | if (dest_node == (LOCAL_BUS | ALL_NODES)) |
1674 | goto fail; | 1675 | goto fail; |
1675 | 1676 | ||
1677 | /* At this point we want to restore the packet. When we return | ||
1678 | * here with NETDEV_TX_BUSY we will get another entrance in this | ||
1679 | * routine with the same skb and we need it to look the same. | ||
1680 | * So we pull 4 more bytes, then build the header again. */ | ||
1681 | skb_pull(skb, 4); | ||
1682 | ether1394_header(skb, dev, ntohs(hdr_buf.h_proto), | ||
1683 | hdr_buf.h_dest, NULL, 0); | ||
1684 | |||
1676 | /* Most failures of ether1394_send_packet are recoverable. */ | 1685 | /* Most failures of ether1394_send_packet are recoverable. */ |
1677 | netif_stop_queue(dev); | 1686 | netif_stop_queue(dev); |
1678 | priv->wake_node = dest_node; | 1687 | priv->wake_node = dest_node; |