From: Carlos E. Ugarte Date: Mon, 4 Jun 2007 15:49:19 +0000 (-0400) Subject: ieee1394: fix to ether1394_tx in ether1394.c X-Git-Tag: v2.6.22-rc6~69^2~1 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=18b461796b737f94286f73710debc8649467161b;p=linux-2.6 ieee1394: fix to ether1394_tx in ether1394.c This patch fixes a problem that occurs when packets cannot be sent across the ieee1394 bus and we return NETDEV_TX_BUSY in the net driver "hard start xmit" routine ether1394_tx. When we return NETDEV_TX_BUSY the stack will call ether1394_tx again with the same skb. So we need to restore the header to look like it did before we munged it for xmit over ieee1394. [Stefan Richter: changed whitespace, deleted a local variable] Signed-off-by: Stefan Richter --- diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index 5f026b5d78..7c13fb3c16 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -1565,7 +1565,7 @@ static void ether1394_complete_cb(void *__ptask) /* Transmit a packet (called by kernel) */ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) { - struct eth1394hdr *eth; + struct eth1394hdr hdr_buf; struct eth1394_priv *priv = netdev_priv(dev); __be16 proto; unsigned long flags; @@ -1595,16 +1595,17 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) if (!skb) goto fail; - /* Get rid of the fake eth1394 header, but save a pointer */ - eth = (struct eth1394hdr *)skb->data; + /* Get rid of the fake eth1394 header, but first make a copy. + * We might need to rebuild the header on tx failure. */ + memcpy(&hdr_buf, skb->data, sizeof(hdr_buf)); skb_pull(skb, ETH1394_HLEN); - proto = eth->h_proto; + proto = hdr_buf.h_proto; dg_size = skb->len; /* Set the transmission type for the packet. ARP packets and IP * broadcast packets are sent via GASP. */ - if (memcmp(eth->h_dest, dev->broadcast, ETH1394_ALEN) == 0 || + if (memcmp(hdr_buf.h_dest, dev->broadcast, ETH1394_ALEN) == 0 || proto == htons(ETH_P_ARP) || (proto == htons(ETH_P_IP) && IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) { @@ -1616,7 +1617,7 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) priv->bc_dgl++; } else { - __be64 guid = get_unaligned((u64 *)eth->h_dest); + __be64 guid = get_unaligned((u64 *)hdr_buf.h_dest); node = eth1394_find_node_guid(&priv->ip_node_list, be64_to_cpu(guid)); @@ -1673,6 +1674,14 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev) if (dest_node == (LOCAL_BUS | ALL_NODES)) goto fail; + /* At this point we want to restore the packet. When we return + * here with NETDEV_TX_BUSY we will get another entrance in this + * routine with the same skb and we need it to look the same. + * So we pull 4 more bytes, then build the header again. */ + skb_pull(skb, 4); + ether1394_header(skb, dev, ntohs(hdr_buf.h_proto), + hdr_buf.h_dest, NULL, 0); + /* Most failures of ether1394_send_packet are recoverable. */ netif_stop_queue(dev); priv->wake_node = dest_node;