From 18406d7e42a67d7b3a3b3ed17be6626a51d8c715 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 25 Mar 2013 08:25:38 +0000 Subject: firewire net: Accept IPv4 and ARP only. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- drivers/firewire/net.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/firewire/net.c') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index c1898adeb900..d438c5be8c21 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -517,6 +517,14 @@ static int fwnet_finish_incoming_packet(struct net_device *net, int status; __be64 guid; + switch (ether_type) { + case ETH_P_ARP: + case ETH_P_IP: + break; + default: + goto err; + } + dev = netdev_priv(net); /* Write metadata, and then pass to the receive level */ skb->dev = net; @@ -653,6 +661,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, return 0; no_peer: + err: net->stats.rx_errors++; net->stats.rx_dropped++; @@ -1340,9 +1349,17 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) * We might need to rebuild the header on tx failure. */ memcpy(&hdr_buf, skb->data, sizeof(hdr_buf)); - skb_pull(skb, sizeof(hdr_buf)); - proto = hdr_buf.h_proto; + + switch (proto) { + case htons(ETH_P_ARP): + case htons(ETH_P_IP): + break; + default: + goto fail; + } + + skb_pull(skb, sizeof(hdr_buf)); dg_size = skb->len; /* -- cgit From 021b97e469714b31b9e808c91b49543a8766c342 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 25 Mar 2013 08:25:48 +0000 Subject: firewire net: Send L2 multicast via GASP. Send L2 multicast packet via GASP (Global asynchronous stream packet) by seeing the multicast bit in the L2 hardware address, not by seeing upper- layer protocol address. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- drivers/firewire/net.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/firewire/net.c') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index d438c5be8c21..7c2e16a1db4f 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -84,6 +84,11 @@ struct fwnet_header { __be16 h_proto; /* packet type ID field */ } __packed; +static bool fwnet_hwaddr_is_multicast(u8 *ha) +{ + return !!(*ha & 1); +} + /* IPv4 and IPv6 encapsulation header */ struct rfc2734_header { u32 w0; @@ -626,7 +631,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, skb_reset_mac_header(skb); skb_pull(skb, sizeof(*eth)); eth = (struct fwnet_header *)skb_mac_header(skb); - if (*eth->h_dest & 1) { + if (fwnet_hwaddr_is_multicast(eth->h_dest)) { if (memcmp(eth->h_dest, net->broadcast, net->addr_len) == 0) skb->pkt_type = PACKET_BROADCAST; @@ -1366,10 +1371,7 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) * Set the transmission type for the packet. ARP packets and IP * broadcast packets are sent via GASP. */ - if (memcmp(hdr_buf.h_dest, net->broadcast, FWNET_ALEN) == 0 - || proto == htons(ETH_P_ARP) - || (proto == htons(ETH_P_IP) - && IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) { + if (fwnet_hwaddr_is_multicast(hdr_buf.h_dest)) { max_payload = dev->broadcast_xmt_max_payload; datagram_label_ptr = &dev->broadcast_xmt_datagramlabel; -- cgit From 382c4b4090b7394d079c199ba053a378c6cd45b8 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 25 Mar 2013 08:25:57 +0000 Subject: firewire net: Allocate address handler before registering net_device. Allocate FIFO address before registering net_device. This is preparation to change the pseudo hardware address format for firewire devices to include the offset of the FIFO for receipt of unicast datagrams, instead of mangling ARP/NDP messages in the driver layer. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- drivers/firewire/net.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers/firewire/net.c') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 7c2e16a1db4f..72536e7fe95c 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1286,13 +1286,9 @@ static int fwnet_open(struct net_device *net) struct fwnet_device *dev = netdev_priv(net); int ret; - ret = fwnet_fifo_start(dev); - if (ret) - return ret; - ret = fwnet_broadcast_start(dev); if (ret) - goto out; + return ret; netif_start_queue(net); @@ -1301,9 +1297,6 @@ static int fwnet_open(struct net_device *net) spin_unlock_irq(&dev->lock); return 0; -out: - fwnet_fifo_stop(dev); - return ret; } /* ifdown */ @@ -1312,9 +1305,7 @@ static int fwnet_stop(struct net_device *net) struct fwnet_device *dev = netdev_priv(net); netif_stop_queue(net); - fwnet_broadcast_stop(dev); - fwnet_fifo_stop(dev); return 0; } @@ -1593,6 +1584,11 @@ static int fwnet_probe(struct device *_dev) dev->card = card; dev->netdev = net; + ret = fwnet_fifo_start(dev); + if (ret < 0) + goto out; + dev->local_fifo = dev->handler.offset; + /* * Use the RFC 2734 default 1500 octets or the maximum payload * as initial MTU @@ -1616,10 +1612,10 @@ static int fwnet_probe(struct device *_dev) if (ret && allocated_netdev) { unregister_netdev(net); list_del(&dev->dev_link); - } out: - if (ret && allocated_netdev) + fwnet_fifo_stop(dev); free_netdev(net); + } mutex_unlock(&fwnet_device_mutex); @@ -1660,6 +1656,8 @@ static int fwnet_remove(struct device *_dev) if (list_empty(&dev->peer_list)) { unregister_netdev(net); + fwnet_fifo_stop(dev); + for (i = 0; dev->queued_datagrams && i < 5; i++) ssleep(1); WARN_ON(dev->queued_datagrams); -- cgit From 61a7839a19c157d11930fe69697a4c90884bf7c4 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 25 Mar 2013 08:26:08 +0000 Subject: firewire net: Ignore spd and max_payload advertised by ARP. Stefan Richter says: | As far as I can tell, it would be best to ignore max_rec and sspd from ARP | and NDP but keep using the respective information from firewire-core | instead (handed over by fwnet_probe()). | | Why? As I noted earlier, RFC 2734:1999 and RFC 3146:2001 were apparently | written with a too simplistic notion of IEEE 1394 bus topology, resulting | in max_rec and sspd in ARP-1394 and NDP-1394 to be useless, IMO. | | Consider a bus like this: | | A ---- B ==== C | | A, B, C are all IP-over-1394 capable nodes. ---- is an S400 cable hop, | and ==== is an S800 cable hop. | | In case of unicasts or multicasts in which node A is involved as | transmitter or receiver, as well as in case of broadcasts, the speeds | S100, S200, S400 work and speed S400 is optimal. | | In case of anything else, IOW in case of unicasts or multicasts in which | only nodes B and C are involved, the speeds S100, S200, S400, S800 work | and speed S800 is optimal. | | Clearly, node A should indicate sspd = S400 in its ARP or NDP packets. | But which sspd should nodes B and C set there? Maybe they set S400, which | would work but would waste half of the available bandwidth in the second | case. Or maybe they set S800, which is OK in the second case but would | prohibit any communication with node A if blindly taken for correct. | | On the other hand, firewire-core *always* gives us the correct and optimum | peer-to-peer speed and asynchronous packet payload, no matter how simple | or complex the bus topology is and no matter in which temporal order nodes | join the bus and are discovered. CC: Stefan Richter Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- drivers/firewire/net.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers/firewire/net.c') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 72536e7fe95c..cb8aa865ff88 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -552,8 +552,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, unsigned char *arp_ptr; u64 fifo_addr; u64 peer_guid; - unsigned sspd; - u16 max_payload; struct fwnet_peer *peer; unsigned long flags; @@ -564,24 +562,10 @@ static int fwnet_finish_incoming_packet(struct net_device *net, fifo_addr = (u64)get_unaligned_be16(&arp1394->fifo_hi) << 32 | get_unaligned_be32(&arp1394->fifo_lo); - sspd = arp1394->sspd; - /* Sanity check. OS X 10.3 PPC reportedly sends 131. */ - if (sspd > SCODE_3200) { - dev_notice(&net->dev, "sspd %x out of range\n", sspd); - sspd = SCODE_3200; - } - max_payload = fwnet_max_payload(arp1394->max_rec, sspd); - spin_lock_irqsave(&dev->lock, flags); peer = fwnet_peer_find_by_guid(dev, peer_guid); if (peer) { peer->fifo = fifo_addr; - - if (peer->speed > sspd) - peer->speed = sspd; - if (peer->max_payload > max_payload) - peer->max_payload = max_payload; - peer->ip = arp1394->sip; } spin_unlock_irqrestore(&dev->lock, flags); -- cgit From 6752c8db8e0cfedb44ba62806dd15b383ed64000 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 25 Mar 2013 08:26:16 +0000 Subject: firewire net, ipv4 arp: Extend hardware address and remove driver-level packet inspection. Inspection of upper layer protocol is considered harmful, especially if it is about ARP or other stateful upper layer protocol; driver cannot (and should not) have full state of them. IPv4 over Firewire module used to inspect ARP (both in sending path and in receiving path), and record peer's GUID, max packet size, max speed and fifo address. This patch removes such inspection by extending our "hardware address" definition to include other information as well: max packet size, max speed and fifo. By doing this, The neighbour module in networking subsystem can cache them. Note: As we have started ignoring sspd and max_rec in ARP/NDP, those information will not be used in the driver when sending. When a packet is being sent, the IP layer fills our pseudo header with the extended "hardware address", including GUID and fifo. The driver can look-up node-id (the real but rather volatile low-level address) by GUID, and then the module can send the packet to the wire using parameters provided in the extendedn hardware address. This approach is realistic because IP over IEEE1394 (RFC2734) and IPv6 over IEEE1394 (RFC3146) share same "hardware address" format in their address resolution protocols. Here, extended "hardware address" is defined as follows: union fwnet_hwaddr { u8 u[16]; struct { __be64 uniq_id; /* EUI-64 */ u8 max_rec; /* max packet size */ u8 sspd; /* max speed */ __be16 fifo_hi; /* hi 16bits of FIFO addr */ __be32 fifo_lo; /* lo 32bits of FIFO addr */ } __packed uc; }; Note that Hardware address is declared as union, so that we can map full IP address into this, when implementing MCAP (Multicast Cannel Allocation Protocol) for IPv6, but IP and ARP subsystem do not need to know this format in detail. One difference between original ARP (RFC826) and 1394 ARP (RFC2734) is that 1394 ARP Request/Reply do not contain the target hardware address field (aka ar$tha). This difference is handled in the ARP subsystem. CC: Stephan Gatzka Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- drivers/firewire/net.c | 153 +++++++++---------------------------------------- 1 file changed, 26 insertions(+), 127 deletions(-) (limited to 'drivers/firewire/net.c') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index cb8aa865ff88..790017eb5051 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -28,6 +28,7 @@ #include #include +#include /* rx limits */ #define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */ @@ -57,33 +58,6 @@ #define RFC2374_HDR_LASTFRAG 2 /* last fragment */ #define RFC2374_HDR_INTFRAG 3 /* interior fragment */ -#define RFC2734_HW_ADDR_LEN 16 - -struct rfc2734_arp { - __be16 hw_type; /* 0x0018 */ - __be16 proto_type; /* 0x0806 */ - u8 hw_addr_len; /* 16 */ - u8 ip_addr_len; /* 4 */ - __be16 opcode; /* ARP Opcode */ - /* Above is exactly the same format as struct arphdr */ - - __be64 s_uniq_id; /* Sender's 64bit EUI */ - u8 max_rec; /* Sender's max packet size */ - u8 sspd; /* Sender's max speed */ - __be16 fifo_hi; /* hi 16bits of sender's FIFO addr */ - __be32 fifo_lo; /* lo 32bits of sender's FIFO addr */ - __be32 sip; /* Sender's IP Address */ - __be32 tip; /* IP Address of requested hw addr */ -} __packed; - -/* This header format is specific to this driver implementation. */ -#define FWNET_ALEN 8 -#define FWNET_HLEN 10 -struct fwnet_header { - u8 h_dest[FWNET_ALEN]; /* destination address */ - __be16 h_proto; /* packet type ID field */ -} __packed; - static bool fwnet_hwaddr_is_multicast(u8 *ha) { return !!(*ha & 1); @@ -196,8 +170,6 @@ struct fwnet_peer { struct list_head peer_link; struct fwnet_device *dev; u64 guid; - u64 fifo; - __be32 ip; /* guarded by dev->lock */ struct list_head pd_list; /* received partial datagrams */ @@ -226,6 +198,15 @@ struct fwnet_packet_task { u8 enqueued; }; +/* + * Get fifo address embedded in hwaddr + */ +static __u64 fwnet_hwaddr_fifo(union fwnet_hwaddr *ha) +{ + return (u64)get_unaligned_be16(&ha->uc.fifo_hi) << 32 + | get_unaligned_be32(&ha->uc.fifo_lo); +} + /* * saddr == NULL means use device source address. * daddr == NULL means leave destination address (eg unresolved arp). @@ -518,7 +499,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, bool is_broadcast, u16 ether_type) { struct fwnet_device *dev; - static const __be64 broadcast_hw = cpu_to_be64(~0ULL); int status; __be64 guid; @@ -537,76 +517,11 @@ static int fwnet_finish_incoming_packet(struct net_device *net, /* * Parse the encapsulation header. This actually does the job of - * converting to an ethernet frame header, as well as arp - * conversion if needed. ARP conversion is easier in this - * direction, since we are using ethernet as our backend. - */ - /* - * If this is an ARP packet, convert it. First, we want to make - * use of some of the fields, since they tell us a little bit - * about the sending machine. + * converting to an ethernet-like pseudo frame header. */ - if (ether_type == ETH_P_ARP) { - struct rfc2734_arp *arp1394; - struct arphdr *arp; - unsigned char *arp_ptr; - u64 fifo_addr; - u64 peer_guid; - struct fwnet_peer *peer; - unsigned long flags; - - arp1394 = (struct rfc2734_arp *)skb->data; - arp = (struct arphdr *)skb->data; - arp_ptr = (unsigned char *)(arp + 1); - peer_guid = get_unaligned_be64(&arp1394->s_uniq_id); - fifo_addr = (u64)get_unaligned_be16(&arp1394->fifo_hi) << 32 - | get_unaligned_be32(&arp1394->fifo_lo); - - spin_lock_irqsave(&dev->lock, flags); - peer = fwnet_peer_find_by_guid(dev, peer_guid); - if (peer) { - peer->fifo = fifo_addr; - peer->ip = arp1394->sip; - } - spin_unlock_irqrestore(&dev->lock, flags); - - if (!peer) { - dev_notice(&net->dev, - "no peer for ARP packet from %016llx\n", - (unsigned long long)peer_guid); - goto no_peer; - } - - /* - * Now that we're done with the 1394 specific stuff, we'll - * need to alter some of the data. Believe it or not, all - * that needs to be done is sender_IP_address needs to be - * moved, the destination hardware address get stuffed - * in and the hardware address length set to 8. - * - * IMPORTANT: The code below overwrites 1394 specific data - * needed above so keep the munging of the data for the - * higher level IP stack last. - */ - - arp->ar_hln = 8; - /* skip over sender unique id */ - arp_ptr += arp->ar_hln; - /* move sender IP addr */ - put_unaligned(arp1394->sip, (u32 *)arp_ptr); - /* skip over sender IP addr */ - arp_ptr += arp->ar_pln; - - if (arp->ar_op == htons(ARPOP_REQUEST)) - memset(arp_ptr, 0, sizeof(u64)); - else - memcpy(arp_ptr, net->dev_addr, sizeof(u64)); - } - - /* Now add the ethernet header. */ guid = cpu_to_be64(dev->card->guid); if (dev_hard_header(skb, net, ether_type, - is_broadcast ? &broadcast_hw : &guid, + is_broadcast ? net->broadcast : net->dev_addr, NULL, skb->len) >= 0) { struct fwnet_header *eth; u16 *rawp; @@ -649,7 +564,6 @@ static int fwnet_finish_incoming_packet(struct net_device *net, return 0; - no_peer: err: net->stats.rx_errors++; net->stats.rx_dropped++; @@ -1355,11 +1269,12 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ptask->dest_node = IEEE1394_ALL_NODES; ptask->speed = SCODE_100; } else { - __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest); + union fwnet_hwaddr *ha = (union fwnet_hwaddr *)hdr_buf.h_dest; + __be64 guid = get_unaligned(&ha->uc.uniq_id); u8 generation; peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); - if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) + if (!peer) goto fail; generation = peer->generation; @@ -1367,32 +1282,12 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) max_payload = peer->max_payload; datagram_label_ptr = &peer->datagram_label; - ptask->fifo_addr = peer->fifo; + ptask->fifo_addr = fwnet_hwaddr_fifo(ha); ptask->generation = generation; ptask->dest_node = dest_node; ptask->speed = peer->speed; } - /* If this is an ARP packet, convert it */ - if (proto == htons(ETH_P_ARP)) { - struct arphdr *arp = (struct arphdr *)skb->data; - unsigned char *arp_ptr = (unsigned char *)(arp + 1); - struct rfc2734_arp *arp1394 = (struct rfc2734_arp *)skb->data; - __be32 ipaddr; - - ipaddr = get_unaligned((__be32 *)(arp_ptr + FWNET_ALEN)); - - arp1394->hw_addr_len = RFC2734_HW_ADDR_LEN; - arp1394->max_rec = dev->card->max_receive; - arp1394->sspd = dev->card->link_speed; - - put_unaligned_be16(dev->local_fifo >> 32, - &arp1394->fifo_hi); - put_unaligned_be32(dev->local_fifo & 0xffffffff, - &arp1394->fifo_lo); - put_unaligned(ipaddr, &arp1394->sip); - } - ptask->hdr.w0 = 0; ptask->hdr.w1 = 0; ptask->skb = skb; @@ -1507,8 +1402,6 @@ static int fwnet_add_peer(struct fwnet_device *dev, peer->dev = dev; peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; - peer->fifo = FWNET_NO_FIFO_ADDR; - peer->ip = 0; INIT_LIST_HEAD(&peer->pd_list); peer->pdg_size = 0; peer->datagram_label = 0; @@ -1538,6 +1431,7 @@ static int fwnet_probe(struct device *_dev) struct fwnet_device *dev; unsigned max_mtu; int ret; + union fwnet_hwaddr *ha; mutex_lock(&fwnet_device_mutex); @@ -1582,8 +1476,15 @@ static int fwnet_probe(struct device *_dev) net->mtu = min(1500U, max_mtu); /* Set our hardware address while we're at it */ - put_unaligned_be64(card->guid, net->dev_addr); - put_unaligned_be64(~0ULL, net->broadcast); + ha = (union fwnet_hwaddr *)net->dev_addr; + put_unaligned_be64(card->guid, &ha->uc.uniq_id); + ha->uc.max_rec = dev->card->max_receive; + ha->uc.sspd = dev->card->link_speed; + put_unaligned_be16(dev->local_fifo >> 32, &ha->uc.fifo_hi); + put_unaligned_be32(dev->local_fifo & 0xffffffff, &ha->uc.fifo_lo); + + memset(net->broadcast, -1, net->addr_len); + ret = register_netdev(net); if (ret) goto out; @@ -1632,8 +1533,6 @@ static int fwnet_remove(struct device *_dev) mutex_lock(&fwnet_device_mutex); net = dev->netdev; - if (net && peer->ip) - arp_invalidate(net, peer->ip); fwnet_remove_peer(peer, dev); -- cgit From cb6bf35502d53364d15737295bc64f804c4587ce Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki / 吉藤英明 Date: Mon, 25 Mar 2013 08:26:24 +0000 Subject: firewire net, ipv6: IPv6 over Firewire (RFC3146) support. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- drivers/firewire/net.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 5 deletions(-) (limited to 'drivers/firewire/net.c') diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 790017eb5051..56796330a162 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -1,5 +1,6 @@ /* * IPv4 over IEEE 1394, per RFC 2734 + * IPv6 over IEEE 1394, per RFC 3146 * * Copyright (C) 2009 Jay Fenlason * @@ -46,6 +47,7 @@ #define IANA_SPECIFIER_ID 0x00005eU #define RFC2734_SW_VERSION 0x000001U +#define RFC3146_SW_VERSION 0x000002U #define IEEE1394_GASP_HDR_SIZE 8 @@ -505,6 +507,9 @@ static int fwnet_finish_incoming_packet(struct net_device *net, switch (ether_type) { case ETH_P_ARP: case ETH_P_IP: +#if IS_ENABLED(CONFIG_IPV6) + case ETH_P_IPV6: +#endif break; default: goto err; @@ -768,7 +773,12 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, ver = be32_to_cpu(buf_ptr[1]) & 0xffffff; source_node_id = be32_to_cpu(buf_ptr[0]) >> 16; - if (specifier_id == IANA_SPECIFIER_ID && ver == RFC2734_SW_VERSION) { + if (specifier_id == IANA_SPECIFIER_ID && + (ver == RFC2734_SW_VERSION +#if IS_ENABLED(CONFIG_IPV6) + || ver == RFC3146_SW_VERSION +#endif + )) { buf_ptr += 2; length -= IEEE1394_GASP_HDR_SIZE; fwnet_incoming_packet(dev, buf_ptr, length, source_node_id, @@ -971,16 +981,27 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) u8 *p; int generation; int node_id; + unsigned int sw_version; /* ptask->generation may not have been set yet */ generation = dev->card->generation; smp_rmb(); node_id = dev->card->node_id; + switch (ptask->skb->protocol) { + default: + sw_version = RFC2734_SW_VERSION; + break; +#if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): + sw_version = RFC3146_SW_VERSION; +#endif + } + p = skb_push(ptask->skb, IEEE1394_GASP_HDR_SIZE); put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p); put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24 - | RFC2734_SW_VERSION, &p[4]); + | sw_version, &p[4]); /* We should not transmit if broadcast_channel.valid == 0. */ fw_send_request(dev->card, &ptask->transaction, @@ -1248,6 +1269,9 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) switch (proto) { case htons(ETH_P_ARP): case htons(ETH_P_IP): +#if IS_ENABLED(CONFIG_IPV6) + case htons(ETH_P_IPV6): +#endif break; default: goto fail; @@ -1490,7 +1514,7 @@ static int fwnet_probe(struct device *_dev) goto out; list_add_tail(&dev->dev_link, &fwnet_device_list); - dev_notice(&net->dev, "IPv4 over IEEE 1394 on card %s\n", + dev_notice(&net->dev, "IP over IEEE 1394 on card %s\n", dev_name(card->device)); have_dev: ret = fwnet_add_peer(dev, unit, device); @@ -1579,6 +1603,14 @@ static const struct ieee1394_device_id fwnet_id_table[] = { .specifier_id = IANA_SPECIFIER_ID, .version = RFC2734_SW_VERSION, }, +#if IS_ENABLED(CONFIG_IPV6) + { + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .specifier_id = IANA_SPECIFIER_ID, + .version = RFC3146_SW_VERSION, + }, +#endif { } }; @@ -1616,6 +1648,30 @@ static struct fw_descriptor rfc2374_unit_directory = { .data = rfc2374_unit_directory_data }; +#if IS_ENABLED(CONFIG_IPV6) +static const u32 rfc3146_unit_directory_data[] = { + 0x00040000, /* directory_length */ + 0x1200005e, /* unit_specifier_id: IANA */ + 0x81000003, /* textual descriptor offset */ + 0x13000002, /* unit_sw_version: RFC 3146 */ + 0x81000005, /* textual descriptor offset */ + 0x00030000, /* descriptor_length */ + 0x00000000, /* text */ + 0x00000000, /* minimal ASCII, en */ + 0x49414e41, /* I A N A */ + 0x00030000, /* descriptor_length */ + 0x00000000, /* text */ + 0x00000000, /* minimal ASCII, en */ + 0x49507636, /* I P v 6 */ +}; + +static struct fw_descriptor rfc3146_unit_directory = { + .length = ARRAY_SIZE(rfc3146_unit_directory_data), + .key = (CSR_DIRECTORY | CSR_UNIT) << 24, + .data = rfc3146_unit_directory_data +}; +#endif + static int __init fwnet_init(void) { int err; @@ -1624,11 +1680,17 @@ static int __init fwnet_init(void) if (err) return err; +#if IS_ENABLED(CONFIG_IPV6) + err = fw_core_add_descriptor(&rfc3146_unit_directory); + if (err) + goto out; +#endif + fwnet_packet_task_cache = kmem_cache_create("packet_task", sizeof(struct fwnet_packet_task), 0, 0, NULL); if (!fwnet_packet_task_cache) { err = -ENOMEM; - goto out; + goto out2; } err = driver_register(&fwnet_driver.driver); @@ -1636,7 +1698,11 @@ static int __init fwnet_init(void) return 0; kmem_cache_destroy(fwnet_packet_task_cache); +out2: +#if IS_ENABLED(CONFIG_IPV6) + fw_core_remove_descriptor(&rfc3146_unit_directory); out: +#endif fw_core_remove_descriptor(&rfc2374_unit_directory); return err; @@ -1647,11 +1713,14 @@ static void __exit fwnet_cleanup(void) { driver_unregister(&fwnet_driver.driver); kmem_cache_destroy(fwnet_packet_task_cache); +#if IS_ENABLED(CONFIG_IPV6) + fw_core_remove_descriptor(&rfc3146_unit_directory); +#endif fw_core_remove_descriptor(&rfc2374_unit_directory); } module_exit(fwnet_cleanup); MODULE_AUTHOR("Jay Fenlason "); -MODULE_DESCRIPTION("IPv4 over IEEE1394 as per RFC 2734"); +MODULE_DESCRIPTION("IP over IEEE1394 as per RFC 2734/3146"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(ieee1394, fwnet_id_table); -- cgit