Commit cb6bf355 authored by YOSHIFUJI Hideaki / 吉藤英明's avatar YOSHIFUJI Hideaki / 吉藤英明 Committed by David S. Miller

firewire net, ipv6: IPv6 over Firewire (RFC3146) support.

Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6752c8db
...@@ -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>
* *
...@@ -46,6 +47,7 @@ ...@@ -46,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
...@@ -505,6 +507,9 @@ static int fwnet_finish_incoming_packet(struct net_device *net, ...@@ -505,6 +507,9 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
switch (ether_type) { switch (ether_type) {
case ETH_P_ARP: case ETH_P_ARP:
case ETH_P_IP: case ETH_P_IP:
#if IS_ENABLED(CONFIG_IPV6)
case ETH_P_IPV6:
#endif
break; break;
default: default:
goto err; goto err;
...@@ -768,7 +773,12 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context, ...@@ -768,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,
...@@ -971,16 +981,27 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask) ...@@ -971,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,
...@@ -1248,6 +1269,9 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net) ...@@ -1248,6 +1269,9 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
switch (proto) { switch (proto) {
case htons(ETH_P_ARP): case htons(ETH_P_ARP):
case htons(ETH_P_IP): case htons(ETH_P_IP):
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6):
#endif
break; break;
default: default:
goto fail; goto fail;
...@@ -1490,7 +1514,7 @@ static int fwnet_probe(struct device *_dev) ...@@ -1490,7 +1514,7 @@ static int fwnet_probe(struct device *_dev)
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);
...@@ -1579,6 +1603,14 @@ static const struct ieee1394_device_id fwnet_id_table[] = { ...@@ -1579,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
{ } { }
}; };
...@@ -1616,6 +1648,30 @@ static struct fw_descriptor rfc2374_unit_directory = { ...@@ -1616,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;
...@@ -1624,11 +1680,17 @@ static int __init fwnet_init(void) ...@@ -1624,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);
...@@ -1636,7 +1698,11 @@ static int __init fwnet_init(void) ...@@ -1636,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;
...@@ -1647,11 +1713,14 @@ static void __exit fwnet_cleanup(void) ...@@ -1647,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);
...@@ -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