Commit 8dc57da2 authored by David S. Miller's avatar David S. Miller

Merge branch 'ipv6-firewire'

YOSHIFUJI Hideaki says:

====================
This is take 4 of supporting IPv6 over Firewire (IEEE 1394) based on
RFC3146.

Take 3->4:
- Fix receiving 1394 ARP, which comes without arp$tha.
- Remove rfc3146 unit directory on module exit.
- other minor clean-ups - minimize diffs.

====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b8092861 cb6bf355
...@@ -47,9 +47,9 @@ config FIREWIRE_NET ...@@ -47,9 +47,9 @@ config FIREWIRE_NET
tristate "IP networking over 1394" tristate "IP networking over 1394"
depends on FIREWIRE && INET depends on FIREWIRE && INET
help help
This enables IPv4 over IEEE 1394, providing IP connectivity with This enables IPv4/IPv6 over IEEE 1394, providing IP connectivity
other implementations of RFC 2734 as found on several operating with other implementations of RFC 2734/3146 as found on several
systems. Multicast support is currently limited. operating systems. Multicast support is currently limited.
To compile this driver as a module, say M here: The module will be To compile this driver as a module, say M here: The module will be
called firewire-net. called firewire-net.
......
/* /*
* IPv4 over IEEE 1394, per RFC 2734 * IPv4 over IEEE 1394, per RFC 2734
* IPv6 over IEEE 1394, per RFC 3146
* *
* Copyright (C) 2009 Jay Fenlason <fenlason@redhat.com> * Copyright (C) 2009 Jay Fenlason <fenlason@redhat.com>
* *
...@@ -28,6 +29,7 @@ ...@@ -28,6 +29,7 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <net/arp.h> #include <net/arp.h>
#include <net/firewire.h>
/* rx limits */ /* rx limits */
#define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */ #define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */
...@@ -45,6 +47,7 @@ ...@@ -45,6 +47,7 @@
#define IANA_SPECIFIER_ID 0x00005eU #define IANA_SPECIFIER_ID 0x00005eU
#define RFC2734_SW_VERSION 0x000001U #define RFC2734_SW_VERSION 0x000001U
#define RFC3146_SW_VERSION 0x000002U
#define IEEE1394_GASP_HDR_SIZE 8 #define IEEE1394_GASP_HDR_SIZE 8
...@@ -57,32 +60,10 @@ ...@@ -57,32 +60,10 @@
#define RFC2374_HDR_LASTFRAG 2 /* last fragment */ #define RFC2374_HDR_LASTFRAG 2 /* last fragment */
#define RFC2374_HDR_INTFRAG 3 /* interior fragment */ #define RFC2374_HDR_INTFRAG 3 /* interior fragment */
#define RFC2734_HW_ADDR_LEN 16 static bool fwnet_hwaddr_is_multicast(u8 *ha)
{
struct rfc2734_arp { return !!(*ha & 1);
__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;
/* IPv4 and IPv6 encapsulation header */ /* IPv4 and IPv6 encapsulation header */
struct rfc2734_header { struct rfc2734_header {
...@@ -191,8 +172,6 @@ struct fwnet_peer { ...@@ -191,8 +172,6 @@ struct fwnet_peer {
struct list_head peer_link; struct list_head peer_link;
struct fwnet_device *dev; struct fwnet_device *dev;
u64 guid; u64 guid;
u64 fifo;
__be32 ip;
/* guarded by dev->lock */ /* guarded by dev->lock */
struct list_head pd_list; /* received partial datagrams */ struct list_head pd_list; /* received partial datagrams */
...@@ -221,6 +200,15 @@ struct fwnet_packet_task { ...@@ -221,6 +200,15 @@ struct fwnet_packet_task {
u8 enqueued; 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. * saddr == NULL means use device source address.
* daddr == NULL means leave destination address (eg unresolved arp). * daddr == NULL means leave destination address (eg unresolved arp).
...@@ -513,10 +501,20 @@ static int fwnet_finish_incoming_packet(struct net_device *net, ...@@ -513,10 +501,20 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
bool is_broadcast, u16 ether_type) bool is_broadcast, u16 ether_type)
{ {
struct fwnet_device *dev; struct fwnet_device *dev;
static const __be64 broadcast_hw = cpu_to_be64(~0ULL);
int status; int status;
__be64 guid; __be64 guid;
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;
}
dev = netdev_priv(net); dev = netdev_priv(net);
/* Write metadata, and then pass to the receive level */ /* Write metadata, and then pass to the receive level */
skb->dev = net; skb->dev = net;
...@@ -524,92 +522,11 @@ static int fwnet_finish_incoming_packet(struct net_device *net, ...@@ -524,92 +522,11 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
/* /*
* Parse the encapsulation header. This actually does the job of * Parse the encapsulation header. This actually does the job of
* converting to an ethernet frame header, as well as arp * converting to an ethernet-like pseudo frame header.
* 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.
*/
if (ether_type == ETH_P_ARP) {
struct rfc2734_arp *arp1394;
struct arphdr *arp;
unsigned char *arp_ptr;
u64 fifo_addr;
u64 peer_guid;
unsigned sspd;
u16 max_payload;
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);
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);
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); guid = cpu_to_be64(dev->card->guid);
if (dev_hard_header(skb, net, ether_type, if (dev_hard_header(skb, net, ether_type,
is_broadcast ? &broadcast_hw : &guid, is_broadcast ? net->broadcast : net->dev_addr,
NULL, skb->len) >= 0) { NULL, skb->len) >= 0) {
struct fwnet_header *eth; struct fwnet_header *eth;
u16 *rawp; u16 *rawp;
...@@ -618,7 +535,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, ...@@ -618,7 +535,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb_pull(skb, sizeof(*eth)); skb_pull(skb, sizeof(*eth));
eth = (struct fwnet_header *)skb_mac_header(skb); 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, if (memcmp(eth->h_dest, net->broadcast,
net->addr_len) == 0) net->addr_len) == 0)
skb->pkt_type = PACKET_BROADCAST; skb->pkt_type = PACKET_BROADCAST;
...@@ -652,7 +569,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net, ...@@ -652,7 +569,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
return 0; return 0;
no_peer: err:
net->stats.rx_errors++; net->stats.rx_errors++;
net->stats.rx_dropped++; net->stats.rx_dropped++;
...@@ -856,7 +773,12 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, ...@@ -856,7 +773,12 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
ver = be32_to_cpu(buf_ptr[1]) & 0xffffff; ver = be32_to_cpu(buf_ptr[1]) & 0xffffff;
source_node_id = be32_to_cpu(buf_ptr[0]) >> 16; 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; buf_ptr += 2;
length -= IEEE1394_GASP_HDR_SIZE; length -= IEEE1394_GASP_HDR_SIZE;
fwnet_incoming_packet(dev, buf_ptr, length, source_node_id, fwnet_incoming_packet(dev, buf_ptr, length, source_node_id,
...@@ -1059,16 +981,27 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) ...@@ -1059,16 +981,27 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
u8 *p; u8 *p;
int generation; int generation;
int node_id; int node_id;
unsigned int sw_version;
/* ptask->generation may not have been set yet */ /* ptask->generation may not have been set yet */
generation = dev->card->generation; generation = dev->card->generation;
smp_rmb(); smp_rmb();
node_id = dev->card->node_id; 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); p = skb_push(ptask->skb, IEEE1394_GASP_HDR_SIZE);
put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p); put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p);
put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24 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. */ /* We should not transmit if broadcast_channel.valid == 0. */
fw_send_request(dev->card, &ptask->transaction, fw_send_request(dev->card, &ptask->transaction,
...@@ -1272,13 +1205,9 @@ static int fwnet_open(struct net_device *net) ...@@ -1272,13 +1205,9 @@ static int fwnet_open(struct net_device *net)
struct fwnet_device *dev = netdev_priv(net); struct fwnet_device *dev = netdev_priv(net);
int ret; int ret;
ret = fwnet_fifo_start(dev);
if (ret)
return ret;
ret = fwnet_broadcast_start(dev); ret = fwnet_broadcast_start(dev);
if (ret) if (ret)
goto out; return ret;
netif_start_queue(net); netif_start_queue(net);
...@@ -1287,9 +1216,6 @@ static int fwnet_open(struct net_device *net) ...@@ -1287,9 +1216,6 @@ static int fwnet_open(struct net_device *net)
spin_unlock_irq(&dev->lock); spin_unlock_irq(&dev->lock);
return 0; return 0;
out:
fwnet_fifo_stop(dev);
return ret;
} }
/* ifdown */ /* ifdown */
...@@ -1298,9 +1224,7 @@ static int fwnet_stop(struct net_device *net) ...@@ -1298,9 +1224,7 @@ static int fwnet_stop(struct net_device *net)
struct fwnet_device *dev = netdev_priv(net); struct fwnet_device *dev = netdev_priv(net);
netif_stop_queue(net); netif_stop_queue(net);
fwnet_broadcast_stop(dev); fwnet_broadcast_stop(dev);
fwnet_fifo_stop(dev);
return 0; return 0;
} }
...@@ -1340,19 +1264,27 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ...@@ -1340,19 +1264,27 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
* We might need to rebuild the header on tx failure. * We might need to rebuild the header on tx failure.
*/ */
memcpy(&hdr_buf, skb->data, sizeof(hdr_buf)); memcpy(&hdr_buf, skb->data, sizeof(hdr_buf));
skb_pull(skb, sizeof(hdr_buf));
proto = hdr_buf.h_proto; proto = hdr_buf.h_proto;
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;
}
skb_pull(skb, sizeof(hdr_buf));
dg_size = skb->len; dg_size = skb->len;
/* /*
* Set the transmission type for the packet. ARP packets and IP * Set the transmission type for the packet. ARP packets and IP
* broadcast packets are sent via GASP. * broadcast packets are sent via GASP.
*/ */
if (memcmp(hdr_buf.h_dest, net->broadcast, FWNET_ALEN) == 0 if (fwnet_hwaddr_is_multicast(hdr_buf.h_dest)) {
|| proto == htons(ETH_P_ARP)
|| (proto == htons(ETH_P_IP)
&& IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) {
max_payload = dev->broadcast_xmt_max_payload; max_payload = dev->broadcast_xmt_max_payload;
datagram_label_ptr = &dev->broadcast_xmt_datagramlabel; datagram_label_ptr = &dev->broadcast_xmt_datagramlabel;
...@@ -1361,11 +1293,12 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ...@@ -1361,11 +1293,12 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
ptask->dest_node = IEEE1394_ALL_NODES; ptask->dest_node = IEEE1394_ALL_NODES;
ptask->speed = SCODE_100; ptask->speed = SCODE_100;
} else { } 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; u8 generation;
peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid)); peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR) if (!peer)
goto fail; goto fail;
generation = peer->generation; generation = peer->generation;
...@@ -1373,32 +1306,12 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ...@@ -1373,32 +1306,12 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
max_payload = peer->max_payload; max_payload = peer->max_payload;
datagram_label_ptr = &peer->datagram_label; datagram_label_ptr = &peer->datagram_label;
ptask->fifo_addr = peer->fifo; ptask->fifo_addr = fwnet_hwaddr_fifo(ha);
ptask->generation = generation; ptask->generation = generation;
ptask->dest_node = dest_node; ptask->dest_node = dest_node;
ptask->speed = peer->speed; 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.w0 = 0;
ptask->hdr.w1 = 0; ptask->hdr.w1 = 0;
ptask->skb = skb; ptask->skb = skb;
...@@ -1513,8 +1426,6 @@ static int fwnet_add_peer(struct fwnet_device *dev, ...@@ -1513,8 +1426,6 @@ static int fwnet_add_peer(struct fwnet_device *dev,
peer->dev = dev; peer->dev = dev;
peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; 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); INIT_LIST_HEAD(&peer->pd_list);
peer->pdg_size = 0; peer->pdg_size = 0;
peer->datagram_label = 0; peer->datagram_label = 0;
...@@ -1544,6 +1455,7 @@ static int fwnet_probe(struct device *_dev) ...@@ -1544,6 +1455,7 @@ static int fwnet_probe(struct device *_dev)
struct fwnet_device *dev; struct fwnet_device *dev;
unsigned max_mtu; unsigned max_mtu;
int ret; int ret;
union fwnet_hwaddr *ha;
mutex_lock(&fwnet_device_mutex); mutex_lock(&fwnet_device_mutex);
...@@ -1574,6 +1486,11 @@ static int fwnet_probe(struct device *_dev) ...@@ -1574,6 +1486,11 @@ static int fwnet_probe(struct device *_dev)
dev->card = card; dev->card = card;
dev->netdev = net; 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 * Use the RFC 2734 default 1500 octets or the maximum payload
* as initial MTU * as initial MTU
...@@ -1583,24 +1500,31 @@ static int fwnet_probe(struct device *_dev) ...@@ -1583,24 +1500,31 @@ static int fwnet_probe(struct device *_dev)
net->mtu = min(1500U, max_mtu); net->mtu = min(1500U, max_mtu);
/* Set our hardware address while we're at it */ /* Set our hardware address while we're at it */
put_unaligned_be64(card->guid, net->dev_addr); ha = (union fwnet_hwaddr *)net->dev_addr;
put_unaligned_be64(~0ULL, net->broadcast); 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); ret = register_netdev(net);
if (ret) if (ret)
goto out; goto out;
list_add_tail(&dev->dev_link, &fwnet_device_list); 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)); dev_name(card->device));
have_dev: have_dev:
ret = fwnet_add_peer(dev, unit, device); ret = fwnet_add_peer(dev, unit, device);
if (ret && allocated_netdev) { if (ret && allocated_netdev) {
unregister_netdev(net); unregister_netdev(net);
list_del(&dev->dev_link); list_del(&dev->dev_link);
}
out: out:
if (ret && allocated_netdev) fwnet_fifo_stop(dev);
free_netdev(net); free_netdev(net);
}
mutex_unlock(&fwnet_device_mutex); mutex_unlock(&fwnet_device_mutex);
...@@ -1633,14 +1557,14 @@ static int fwnet_remove(struct device *_dev) ...@@ -1633,14 +1557,14 @@ static int fwnet_remove(struct device *_dev)
mutex_lock(&fwnet_device_mutex); mutex_lock(&fwnet_device_mutex);
net = dev->netdev; net = dev->netdev;
if (net && peer->ip)
arp_invalidate(net, peer->ip);
fwnet_remove_peer(peer, dev); fwnet_remove_peer(peer, dev);
if (list_empty(&dev->peer_list)) { if (list_empty(&dev->peer_list)) {
unregister_netdev(net); unregister_netdev(net);
fwnet_fifo_stop(dev);
for (i = 0; dev->queued_datagrams && i < 5; i++) for (i = 0; dev->queued_datagrams && i < 5; i++)
ssleep(1); ssleep(1);
WARN_ON(dev->queued_datagrams); WARN_ON(dev->queued_datagrams);
...@@ -1679,6 +1603,14 @@ static const struct ieee1394_device_id fwnet_id_table[] = { ...@@ -1679,6 +1603,14 @@ static const struct ieee1394_device_id fwnet_id_table[] = {
.specifier_id = IANA_SPECIFIER_ID, .specifier_id = IANA_SPECIFIER_ID,
.version = RFC2734_SW_VERSION, .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
{ } { }
}; };
...@@ -1716,6 +1648,30 @@ static struct fw_descriptor rfc2374_unit_directory = { ...@@ -1716,6 +1648,30 @@ static struct fw_descriptor rfc2374_unit_directory = {
.data = rfc2374_unit_directory_data .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) static int __init fwnet_init(void)
{ {
int err; int err;
...@@ -1724,11 +1680,17 @@ static int __init fwnet_init(void) ...@@ -1724,11 +1680,17 @@ static int __init fwnet_init(void)
if (err) if (err)
return 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", fwnet_packet_task_cache = kmem_cache_create("packet_task",
sizeof(struct fwnet_packet_task), 0, 0, NULL); sizeof(struct fwnet_packet_task), 0, 0, NULL);
if (!fwnet_packet_task_cache) { if (!fwnet_packet_task_cache) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out2;
} }
err = driver_register(&fwnet_driver.driver); err = driver_register(&fwnet_driver.driver);
...@@ -1736,7 +1698,11 @@ static int __init fwnet_init(void) ...@@ -1736,7 +1698,11 @@ static int __init fwnet_init(void)
return 0; return 0;
kmem_cache_destroy(fwnet_packet_task_cache); kmem_cache_destroy(fwnet_packet_task_cache);
out2:
#if IS_ENABLED(CONFIG_IPV6)
fw_core_remove_descriptor(&rfc3146_unit_directory);
out: out:
#endif
fw_core_remove_descriptor(&rfc2374_unit_directory); fw_core_remove_descriptor(&rfc2374_unit_directory);
return err; return err;
...@@ -1747,11 +1713,14 @@ static void __exit fwnet_cleanup(void) ...@@ -1747,11 +1713,14 @@ static void __exit fwnet_cleanup(void)
{ {
driver_unregister(&fwnet_driver.driver); driver_unregister(&fwnet_driver.driver);
kmem_cache_destroy(fwnet_packet_task_cache); 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); fw_core_remove_descriptor(&rfc2374_unit_directory);
} }
module_exit(fwnet_cleanup); module_exit(fwnet_cleanup);
MODULE_AUTHOR("Jay Fenlason <fenlason@redhat.com>"); MODULE_AUTHOR("Jay Fenlason <fenlason@redhat.com>");
MODULE_DESCRIPTION("IPv4 over IEEE1394 as per RFC 2734"); MODULE_DESCRIPTION("IP over IEEE1394 as per RFC 2734/3146");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(ieee1394, fwnet_id_table); MODULE_DEVICE_TABLE(ieee1394, fwnet_id_table);
...@@ -33,7 +33,15 @@ static inline struct arphdr *arp_hdr(const struct sk_buff *skb) ...@@ -33,7 +33,15 @@ static inline struct arphdr *arp_hdr(const struct sk_buff *skb)
static inline int arp_hdr_len(struct net_device *dev) static inline int arp_hdr_len(struct net_device *dev)
{ {
switch (dev->type) {
#if IS_ENABLED(CONFIG_FIREWIRE_NET)
case ARPHRD_IEEE1394:
/* ARP header, device address and 2 IP addresses */
return sizeof(struct arphdr) + dev->addr_len + sizeof(u32) * 2;
#endif
default:
/* ARP header, plus 2 device addresses, plus 2 IP addresses. */ /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) * 2; return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) * 2;
}
} }
#endif /* _LINUX_IF_ARP_H */ #endif /* _LINUX_IF_ARP_H */
#ifndef _NET_FIREWIRE_H
#define _NET_FIREWIRE_H
/* Pseudo L2 address */
#define FWNET_ALEN 16
union fwnet_hwaddr {
u8 u[FWNET_ALEN];
/* "Hardware address" defined in RFC2734/RF3146 */
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;
};
/* Pseudo L2 Header */
#define FWNET_HLEN 18
struct fwnet_header {
u8 h_dest[FWNET_ALEN]; /* destination address */
__be16 h_proto; /* packet type ID field */
} __packed;
#endif
...@@ -654,11 +654,19 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, ...@@ -654,11 +654,19 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
arp_ptr += dev->addr_len; arp_ptr += dev->addr_len;
memcpy(arp_ptr, &src_ip, 4); memcpy(arp_ptr, &src_ip, 4);
arp_ptr += 4; arp_ptr += 4;
switch (dev->type) {
#if IS_ENABLED(CONFIG_FIREWIRE_NET)
case ARPHRD_IEEE1394:
break;
#endif
default:
if (target_hw != NULL) if (target_hw != NULL)
memcpy(arp_ptr, target_hw, dev->addr_len); memcpy(arp_ptr, target_hw, dev->addr_len);
else else
memset(arp_ptr, 0, dev->addr_len); memset(arp_ptr, 0, dev->addr_len);
arp_ptr += dev->addr_len; arp_ptr += dev->addr_len;
}
memcpy(arp_ptr, &dest_ip, 4); memcpy(arp_ptr, &dest_ip, 4);
return skb; return skb;
...@@ -781,7 +789,14 @@ static int arp_process(struct sk_buff *skb) ...@@ -781,7 +789,14 @@ static int arp_process(struct sk_buff *skb)
arp_ptr += dev->addr_len; arp_ptr += dev->addr_len;
memcpy(&sip, arp_ptr, 4); memcpy(&sip, arp_ptr, 4);
arp_ptr += 4; arp_ptr += 4;
switch (dev_type) {
#if IS_ENABLED(CONFIG_FIREWIRE_NET)
case ARPHRD_IEEE1394:
break;
#endif
default:
arp_ptr += dev->addr_len; arp_ptr += dev->addr_len;
}
memcpy(&tip, arp_ptr, 4); memcpy(&tip, arp_ptr, 4);
/* /*
* Check for bad requests for 127.x.x.x and requests for multicast * Check for bad requests for 127.x.x.x and requests for multicast
......
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
#include <net/snmp.h> #include <net/snmp.h>
#include <net/af_ieee802154.h> #include <net/af_ieee802154.h>
#include <net/firewire.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/protocol.h> #include <net/protocol.h>
#include <net/ndisc.h> #include <net/ndisc.h>
...@@ -1738,6 +1739,20 @@ static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev) ...@@ -1738,6 +1739,20 @@ static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev)
return 0; return 0;
} }
static int addrconf_ifid_ieee1394(u8 *eui, struct net_device *dev)
{
union fwnet_hwaddr *ha;
if (dev->addr_len != FWNET_ALEN)
return -1;
ha = (union fwnet_hwaddr *)dev->dev_addr;
memcpy(eui, &ha->uc.uniq_id, sizeof(ha->uc.uniq_id));
eui[0] ^= 2;
return 0;
}
static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev) static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev)
{ {
/* XXX: inherit EUI-64 from other interface -- yoshfuji */ /* XXX: inherit EUI-64 from other interface -- yoshfuji */
...@@ -1802,6 +1817,8 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) ...@@ -1802,6 +1817,8 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
return addrconf_ifid_gre(eui, dev); return addrconf_ifid_gre(eui, dev);
case ARPHRD_IEEE802154: case ARPHRD_IEEE802154:
return addrconf_ifid_eui64(eui, dev); return addrconf_ifid_eui64(eui, dev);
case ARPHRD_IEEE1394:
return addrconf_ifid_ieee1394(eui, dev);
} }
return -1; return -1;
} }
...@@ -2643,7 +2660,8 @@ static void addrconf_dev_config(struct net_device *dev) ...@@ -2643,7 +2660,8 @@ static void addrconf_dev_config(struct net_device *dev)
(dev->type != ARPHRD_FDDI) && (dev->type != ARPHRD_FDDI) &&
(dev->type != ARPHRD_ARCNET) && (dev->type != ARPHRD_ARCNET) &&
(dev->type != ARPHRD_INFINIBAND) && (dev->type != ARPHRD_INFINIBAND) &&
(dev->type != ARPHRD_IEEE802154)) { (dev->type != ARPHRD_IEEE802154) &&
(dev->type != ARPHRD_IEEE1394)) {
/* Alas, we support only Ethernet autoconfiguration. */ /* Alas, we support only Ethernet autoconfiguration. */
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment