firewire net, ipv6: IPv6 over Firewire (RFC3146) support.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
6752c8db8e
commit
cb6bf35502
@ -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.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* 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 @@
|
|||||||
|
|
||||||
#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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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[] = {
|
|||||||
.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 = {
|
|||||||
.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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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 @@
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
(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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user