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

Merge branch 's390-net-next'

Julian Wiedmann says:

====================
s390/net: updates 2017-12-20

Please apply the following patch series for 4.16.
Nothing too exciting, mostly just beating the qeth L3 code into shape.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a943e8bc 556fd271
...@@ -91,9 +91,6 @@ config QETH_L3 ...@@ -91,9 +91,6 @@ config QETH_L3
To compile as a module choose M. The module name is qeth_l3. To compile as a module choose M. The module name is qeth_l3.
If unsure, choose Y. If unsure, choose Y.
config QETH_IPV6
def_bool y if (QETH_L3 = IPV6) || (QETH_L3 && IPV6 = 'y')
config CCWGROUP config CCWGROUP
tristate tristate
default (LCS || CTCM || QETH) default (LCS || CTCM || QETH)
......
...@@ -756,18 +756,14 @@ lcs_get_lancmd(struct lcs_card *card, int count) ...@@ -756,18 +756,14 @@ lcs_get_lancmd(struct lcs_card *card, int count)
static void static void
lcs_get_reply(struct lcs_reply *reply) lcs_get_reply(struct lcs_reply *reply)
{ {
WARN_ON(atomic_read(&reply->refcnt) <= 0); refcount_inc(&reply->refcnt);
atomic_inc(&reply->refcnt);
} }
static void static void
lcs_put_reply(struct lcs_reply *reply) lcs_put_reply(struct lcs_reply *reply)
{ {
WARN_ON(atomic_read(&reply->refcnt) <= 0); if (refcount_dec_and_test(&reply->refcnt))
if (atomic_dec_and_test(&reply->refcnt)) {
kfree(reply); kfree(reply);
}
} }
static struct lcs_reply * static struct lcs_reply *
...@@ -780,7 +776,7 @@ lcs_alloc_reply(struct lcs_cmd *cmd) ...@@ -780,7 +776,7 @@ lcs_alloc_reply(struct lcs_cmd *cmd)
reply = kzalloc(sizeof(struct lcs_reply), GFP_ATOMIC); reply = kzalloc(sizeof(struct lcs_reply), GFP_ATOMIC);
if (!reply) if (!reply)
return NULL; return NULL;
atomic_set(&reply->refcnt,1); refcount_set(&reply->refcnt, 1);
reply->sequence_no = cmd->sequence_no; reply->sequence_no = cmd->sequence_no;
reply->received = 0; reply->received = 0;
reply->rc = 0; reply->rc = 0;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/refcount.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#define LCS_DBF_TEXT(level, name, text) \ #define LCS_DBF_TEXT(level, name, text) \
...@@ -271,7 +272,7 @@ struct lcs_buffer { ...@@ -271,7 +272,7 @@ struct lcs_buffer {
struct lcs_reply { struct lcs_reply {
struct list_head list; struct list_head list;
__u16 sequence_no; __u16 sequence_no;
atomic_t refcnt; refcount_t refcnt;
/* Callback for completion notification. */ /* Callback for completion notification. */
void (*callback)(struct lcs_card *, struct lcs_cmd *); void (*callback)(struct lcs_card *, struct lcs_cmd *);
wait_queue_head_t wait_q; wait_queue_head_t wait_q;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/refcount.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/if_inet6.h> #include <net/if_inet6.h>
...@@ -296,8 +297,23 @@ struct qeth_hdr_layer3 { ...@@ -296,8 +297,23 @@ struct qeth_hdr_layer3 {
__u8 ext_flags; __u8 ext_flags;
__u16 vlan_id; __u16 vlan_id;
__u16 frame_offset; __u16 frame_offset;
__u8 dest_addr[16]; union {
} __attribute__ ((packed)); /* TX: */
u8 ipv6_addr[16];
struct ipv4 {
u8 res[12];
u32 addr;
} ipv4;
/* RX: */
struct rx {
u8 res1[2];
u8 src_mac[6];
u8 res2[4];
u16 vlan_id;
u8 res3[2];
} rx;
} next_hop;
};
struct qeth_hdr_layer2 { struct qeth_hdr_layer2 {
__u8 id; __u8 id;
...@@ -504,12 +520,6 @@ struct qeth_qdio_info { ...@@ -504,12 +520,6 @@ struct qeth_qdio_info {
int default_out_queue; int default_out_queue;
}; };
#define QETH_ETH_MAC_V4 0x0100 /* like v4 */
#define QETH_ETH_MAC_V6 0x3333 /* like v6 */
/* tr mc mac is longer, but that will be enough to detect mc frames */
#define QETH_TR_MAC_NC 0xc000 /* non-canonical */
#define QETH_TR_MAC_C 0x0300 /* canonical */
/** /**
* buffer stuff for read channel * buffer stuff for read channel
*/ */
...@@ -632,7 +642,7 @@ struct qeth_reply { ...@@ -632,7 +642,7 @@ struct qeth_reply {
int rc; int rc;
void *param; void *param;
struct qeth_card *card; struct qeth_card *card;
atomic_t refcnt; refcount_t refcnt;
}; };
struct qeth_card_blkt { struct qeth_card_blkt {
...@@ -846,14 +856,16 @@ static inline int qeth_get_micros(void) ...@@ -846,14 +856,16 @@ static inline int qeth_get_micros(void)
static inline int qeth_get_ip_version(struct sk_buff *skb) static inline int qeth_get_ip_version(struct sk_buff *skb)
{ {
__be16 *p = &((struct ethhdr *)skb->data)->h_proto; struct vlan_ethhdr *veth = vlan_eth_hdr(skb);
__be16 prot = veth->h_vlan_proto;
if (prot == htons(ETH_P_8021Q))
prot = veth->h_vlan_encapsulated_proto;
if (be16_to_cpu(*p) == ETH_P_8021Q) switch (prot) {
p += 2; case htons(ETH_P_IPV6):
switch (be16_to_cpu(*p)) {
case ETH_P_IPV6:
return 6; return 6;
case ETH_P_IP: case htons(ETH_P_IP):
return 4; return 4;
default: default:
return 0; return 0;
......
...@@ -564,7 +564,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) ...@@ -564,7 +564,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC); reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC);
if (reply) { if (reply) {
atomic_set(&reply->refcnt, 1); refcount_set(&reply->refcnt, 1);
atomic_set(&reply->received, 0); atomic_set(&reply->received, 0);
reply->card = card; reply->card = card;
} }
...@@ -573,14 +573,12 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) ...@@ -573,14 +573,12 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
static void qeth_get_reply(struct qeth_reply *reply) static void qeth_get_reply(struct qeth_reply *reply)
{ {
WARN_ON(atomic_read(&reply->refcnt) <= 0); refcount_inc(&reply->refcnt);
atomic_inc(&reply->refcnt);
} }
static void qeth_put_reply(struct qeth_reply *reply) static void qeth_put_reply(struct qeth_reply *reply)
{ {
WARN_ON(atomic_read(&reply->refcnt) <= 0); if (refcount_dec_and_test(&reply->refcnt))
if (atomic_dec_and_test(&reply->refcnt))
kfree(reply); kfree(reply);
} }
...@@ -4218,9 +4216,8 @@ static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card, ...@@ -4218,9 +4216,8 @@ static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data; cmd = (struct qeth_ipa_cmd *) data;
if (!card->options.layer2 || if (!card->options.layer2 ||
!(card->info.mac_bits & QETH_LAYER2_MAC_READ)) { !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
memcpy(card->dev->dev_addr, ether_addr_copy(card->dev->dev_addr,
&cmd->data.setadapterparms.data.change_addr.addr, cmd->data.setadapterparms.data.change_addr.addr);
OSA_ADDR_LEN);
card->info.mac_bits |= QETH_LAYER2_MAC_READ; card->info.mac_bits |= QETH_LAYER2_MAC_READ;
} }
qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd); qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
...@@ -4242,9 +4239,9 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card) ...@@ -4242,9 +4239,9 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card)
return -ENOMEM; return -ENOMEM;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setadapterparms.data.change_addr.cmd = CHANGE_ADDR_READ_MAC; cmd->data.setadapterparms.data.change_addr.cmd = CHANGE_ADDR_READ_MAC;
cmd->data.setadapterparms.data.change_addr.addr_size = OSA_ADDR_LEN; cmd->data.setadapterparms.data.change_addr.addr_size = ETH_ALEN;
memcpy(&cmd->data.setadapterparms.data.change_addr.addr, ether_addr_copy(cmd->data.setadapterparms.data.change_addr.addr,
card->dev->dev_addr, OSA_ADDR_LEN); card->dev->dev_addr);
rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_change_macaddr_cb, rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_change_macaddr_cb,
NULL); NULL);
return rc; return rc;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#define __QETH_CORE_MPC_H__ #define __QETH_CORE_MPC_H__
#include <asm/qeth.h> #include <asm/qeth.h>
#include <uapi/linux/if_ether.h>
#define IPA_PDU_HEADER_SIZE 0x40 #define IPA_PDU_HEADER_SIZE 0x40
#define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer + 0x0e) #define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer + 0x0e)
...@@ -25,7 +26,6 @@ extern unsigned char IPA_PDU_HEADER[]; ...@@ -25,7 +26,6 @@ extern unsigned char IPA_PDU_HEADER[];
#define QETH_SEQ_NO_LENGTH 4 #define QETH_SEQ_NO_LENGTH 4
#define QETH_MPC_TOKEN_LENGTH 4 #define QETH_MPC_TOKEN_LENGTH 4
#define QETH_MCL_LENGTH 4 #define QETH_MCL_LENGTH 4
#define OSA_ADDR_LEN 6
#define QETH_TIMEOUT (10 * HZ) #define QETH_TIMEOUT (10 * HZ)
#define QETH_IPA_TIMEOUT (45 * HZ) #define QETH_IPA_TIMEOUT (45 * HZ)
...@@ -416,12 +416,11 @@ struct qeth_query_cmds_supp { ...@@ -416,12 +416,11 @@ struct qeth_query_cmds_supp {
} __attribute__ ((packed)); } __attribute__ ((packed));
struct qeth_change_addr { struct qeth_change_addr {
__u32 cmd; u32 cmd;
__u32 addr_size; u32 addr_size;
__u32 no_macs; u32 no_macs;
__u8 addr[OSA_ADDR_LEN]; u8 addr[ETH_ALEN];
} __attribute__ ((packed)); };
struct qeth_snmp_cmd { struct qeth_snmp_cmd {
__u8 token[16]; __u8 token[16];
......
...@@ -22,8 +22,7 @@ int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout); ...@@ -22,8 +22,7 @@ int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout);
bool qeth_l2_vnicc_is_in_use(struct qeth_card *card); bool qeth_l2_vnicc_is_in_use(struct qeth_card *card);
struct qeth_mac { struct qeth_mac {
u8 mac_addr[OSA_ADDR_LEN]; u8 mac_addr[ETH_ALEN];
u8 is_uc:1;
u8 disp_flag:2; u8 disp_flag:2;
struct hlist_node hnode; struct hlist_node hnode;
}; };
......
...@@ -109,8 +109,8 @@ static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac, ...@@ -109,8 +109,8 @@ static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
if (!iob) if (!iob)
return -ENOMEM; return -ENOMEM;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setdelmac.mac_length = OSA_ADDR_LEN; cmd->data.setdelmac.mac_length = ETH_ALEN;
memcpy(&cmd->data.setdelmac.mac, mac, OSA_ADDR_LEN); ether_addr_copy(cmd->data.setdelmac.mac, mac);
return qeth_setdelmac_makerc(card, qeth_send_ipa_cmd(card, iob, return qeth_setdelmac_makerc(card, qeth_send_ipa_cmd(card, iob,
NULL, NULL)); NULL, NULL));
} }
...@@ -123,7 +123,7 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac) ...@@ -123,7 +123,7 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC); rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC);
if (rc == 0) { if (rc == 0) {
card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
memcpy(card->dev->dev_addr, mac, OSA_ADDR_LEN); ether_addr_copy(card->dev->dev_addr, mac);
dev_info(&card->gdev->dev, dev_info(&card->gdev->dev,
"MAC address %pM successfully registered on device %s\n", "MAC address %pM successfully registered on device %s\n",
card->dev->dev_addr, card->dev->name); card->dev->dev_addr, card->dev->name);
...@@ -156,54 +156,37 @@ static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac) ...@@ -156,54 +156,37 @@ static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
return rc; return rc;
} }
static int qeth_l2_send_setgroupmac(struct qeth_card *card, __u8 *mac) static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
{ {
enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ?
IPA_CMD_SETGMAC : IPA_CMD_SETVMAC;
int rc; int rc;
QETH_CARD_TEXT(card, 2, "L2Sgmac"); QETH_CARD_TEXT(card, 2, "L2Wmac");
rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETGMAC); rc = qeth_l2_send_setdelmac(card, mac, cmd);
if (rc == -EEXIST) if (rc == -EEXIST)
QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s\n", QETH_DBF_MESSAGE(2, "MAC %pM already registered on %s\n",
mac, QETH_CARD_IFNAME(card)); mac, QETH_CARD_IFNAME(card));
else if (rc) else if (rc)
QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %d\n", QETH_DBF_MESSAGE(2, "Failed to register MAC %pM on %s: %d\n",
mac, QETH_CARD_IFNAME(card), rc); mac, QETH_CARD_IFNAME(card), rc);
return rc; return rc;
} }
static int qeth_l2_send_delgroupmac(struct qeth_card *card, __u8 *mac) static int qeth_l2_remove_mac(struct qeth_card *card, u8 *mac)
{ {
enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ?
IPA_CMD_DELGMAC : IPA_CMD_DELVMAC;
int rc; int rc;
QETH_CARD_TEXT(card, 2, "L2Dgmac"); QETH_CARD_TEXT(card, 2, "L2Rmac");
rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELGMAC); rc = qeth_l2_send_setdelmac(card, mac, cmd);
if (rc) if (rc)
QETH_DBF_MESSAGE(2, QETH_DBF_MESSAGE(2, "Failed to delete MAC %pM on %s: %d\n",
"Could not delete group MAC %pM on %s: %d\n", mac, QETH_CARD_IFNAME(card), rc);
mac, QETH_CARD_IFNAME(card), rc);
return rc; return rc;
} }
static int qeth_l2_write_mac(struct qeth_card *card, struct qeth_mac *mac)
{
if (mac->is_uc) {
return qeth_l2_send_setdelmac(card, mac->mac_addr,
IPA_CMD_SETVMAC);
} else {
return qeth_l2_send_setgroupmac(card, mac->mac_addr);
}
}
static int qeth_l2_remove_mac(struct qeth_card *card, struct qeth_mac *mac)
{
if (mac->is_uc) {
return qeth_l2_send_setdelmac(card, mac->mac_addr,
IPA_CMD_DELVMAC);
} else {
return qeth_l2_send_delgroupmac(card, mac->mac_addr);
}
}
static void qeth_l2_del_all_macs(struct qeth_card *card) static void qeth_l2_del_all_macs(struct qeth_card *card)
{ {
struct qeth_mac *mac; struct qeth_mac *mac;
...@@ -549,7 +532,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) ...@@ -549,7 +532,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
QETH_CARD_TEXT(card, 3, "setmcTYP"); QETH_CARD_TEXT(card, 3, "setmcTYP");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
QETH_CARD_HEX(card, 3, addr->sa_data, OSA_ADDR_LEN); QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN);
if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) { if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
QETH_CARD_TEXT(card, 3, "setmcREC"); QETH_CARD_TEXT(card, 3, "setmcREC");
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -597,27 +580,23 @@ static void qeth_promisc_to_bridge(struct qeth_card *card) ...@@ -597,27 +580,23 @@ static void qeth_promisc_to_bridge(struct qeth_card *card)
* only if there is not in the hash table storage already * only if there is not in the hash table storage already
* *
*/ */
static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha)
u8 is_uc)
{ {
u32 mac_hash = get_unaligned((u32 *)(&ha->addr[2])); u32 mac_hash = get_unaligned((u32 *)(&ha->addr[2]));
struct qeth_mac *mac; struct qeth_mac *mac;
hash_for_each_possible(card->mac_htable, mac, hnode, mac_hash) { hash_for_each_possible(card->mac_htable, mac, hnode, mac_hash) {
if (is_uc == mac->is_uc && if (ether_addr_equal_64bits(ha->addr, mac->mac_addr)) {
!memcmp(ha->addr, mac->mac_addr, OSA_ADDR_LEN)) {
mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING; mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
return; return;
} }
} }
mac = kzalloc(sizeof(struct qeth_mac), GFP_ATOMIC); mac = kzalloc(sizeof(struct qeth_mac), GFP_ATOMIC);
if (!mac) if (!mac)
return; return;
memcpy(mac->mac_addr, ha->addr, OSA_ADDR_LEN); ether_addr_copy(mac->mac_addr, ha->addr);
mac->is_uc = is_uc;
mac->disp_flag = QETH_DISP_ADDR_ADD; mac->disp_flag = QETH_DISP_ADDR_ADD;
hash_add(card->mac_htable, &mac->hnode, mac_hash); hash_add(card->mac_htable, &mac->hnode, mac_hash);
...@@ -643,26 +622,29 @@ static void qeth_l2_set_rx_mode(struct net_device *dev) ...@@ -643,26 +622,29 @@ static void qeth_l2_set_rx_mode(struct net_device *dev)
spin_lock_bh(&card->mclock); spin_lock_bh(&card->mclock);
netdev_for_each_mc_addr(ha, dev) netdev_for_each_mc_addr(ha, dev)
qeth_l2_add_mac(card, ha, 0); qeth_l2_add_mac(card, ha);
netdev_for_each_uc_addr(ha, dev) netdev_for_each_uc_addr(ha, dev)
qeth_l2_add_mac(card, ha, 1); qeth_l2_add_mac(card, ha);
hash_for_each_safe(card->mac_htable, i, tmp, mac, hnode) { hash_for_each_safe(card->mac_htable, i, tmp, mac, hnode) {
if (mac->disp_flag == QETH_DISP_ADDR_DELETE) { switch (mac->disp_flag) {
qeth_l2_remove_mac(card, mac); case QETH_DISP_ADDR_DELETE:
qeth_l2_remove_mac(card, mac->mac_addr);
hash_del(&mac->hnode); hash_del(&mac->hnode);
kfree(mac); kfree(mac);
break;
} else if (mac->disp_flag == QETH_DISP_ADDR_ADD) { case QETH_DISP_ADDR_ADD:
rc = qeth_l2_write_mac(card, mac); rc = qeth_l2_write_mac(card, mac->mac_addr);
if (rc) { if (rc) {
hash_del(&mac->hnode); hash_del(&mac->hnode);
kfree(mac); kfree(mac);
} else break;
mac->disp_flag = QETH_DISP_ADDR_DELETE; }
} else /* fall through */
default:
/* for next call to set_rx_mode(): */
mac->disp_flag = QETH_DISP_ADDR_DELETE; mac->disp_flag = QETH_DISP_ADDR_DELETE;
}
} }
spin_unlock_bh(&card->mclock); spin_unlock_bh(&card->mclock);
......
...@@ -29,7 +29,7 @@ struct qeth_ipaddr { ...@@ -29,7 +29,7 @@ struct qeth_ipaddr {
*/ */
int ref_counter; int ref_counter;
enum qeth_prot_versions proto; enum qeth_prot_versions proto;
unsigned char mac[OSA_ADDR_LEN]; unsigned char mac[ETH_ALEN];
union { union {
struct { struct {
unsigned int addr; unsigned int addr;
...@@ -69,7 +69,6 @@ struct qeth_ipato_entry { ...@@ -69,7 +69,6 @@ struct qeth_ipato_entry {
extern const struct attribute_group *qeth_l3_attr_groups[]; extern const struct attribute_group *qeth_l3_attr_groups[];
void qeth_l3_ipaddr_to_string(enum qeth_prot_versions, const __u8 *, char *); void qeth_l3_ipaddr_to_string(enum qeth_prot_versions, const __u8 *, char *);
int qeth_l3_string_to_ipaddr(const char *, enum qeth_prot_versions, __u8 *);
int qeth_l3_create_device_attributes(struct device *); int qeth_l3_create_device_attributes(struct device *);
void qeth_l3_remove_device_attributes(struct device *); void qeth_l3_remove_device_attributes(struct device *);
int qeth_l3_setrouting_v4(struct qeth_card *); int qeth_l3_setrouting_v4(struct qeth_card *);
......
...@@ -18,15 +18,20 @@ ...@@ -18,15 +18,20 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/in.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include <linux/igmp.h> #include <linux/igmp.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/skbuff.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/arp.h> #include <net/arp.h>
#include <net/route.h> #include <net/route.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/ip6_fib.h> #include <net/ip6_fib.h>
#include <net/ip6_checksum.h> #include <net/ip6_checksum.h>
#include <net/iucv/af_iucv.h> #include <net/iucv/af_iucv.h>
...@@ -37,99 +42,22 @@ ...@@ -37,99 +42,22 @@
static int qeth_l3_set_offline(struct ccwgroup_device *); static int qeth_l3_set_offline(struct ccwgroup_device *);
static int qeth_l3_stop(struct net_device *); static int qeth_l3_stop(struct net_device *);
static void qeth_l3_set_multicast_list(struct net_device *); static void qeth_l3_set_rx_mode(struct net_device *dev);
static int qeth_l3_register_addr_entry(struct qeth_card *, static int qeth_l3_register_addr_entry(struct qeth_card *,
struct qeth_ipaddr *); struct qeth_ipaddr *);
static int qeth_l3_deregister_addr_entry(struct qeth_card *, static int qeth_l3_deregister_addr_entry(struct qeth_card *,
struct qeth_ipaddr *); struct qeth_ipaddr *);
static int qeth_l3_isxdigit(char *buf)
{
while (*buf) {
if (!isxdigit(*buf++))
return 0;
}
return 1;
}
static void qeth_l3_ipaddr4_to_string(const __u8 *addr, char *buf) static void qeth_l3_ipaddr4_to_string(const __u8 *addr, char *buf)
{ {
sprintf(buf, "%pI4", addr); sprintf(buf, "%pI4", addr);
} }
static int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr)
{
int count = 0, rc = 0;
unsigned int in[4];
char c;
rc = sscanf(buf, "%u.%u.%u.%u%c",
&in[0], &in[1], &in[2], &in[3], &c);
if (rc != 4 && (rc != 5 || c != '\n'))
return -EINVAL;
for (count = 0; count < 4; count++) {
if (in[count] > 255)
return -EINVAL;
addr[count] = in[count];
}
return 0;
}
static void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf) static void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf)
{ {
sprintf(buf, "%pI6", addr); sprintf(buf, "%pI6", addr);
} }
static int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr)
{
const char *end, *end_tmp, *start;
__u16 *in;
char num[5];
int num2, cnt, out, found, save_cnt;
unsigned short in_tmp[8] = {0, };
cnt = out = found = save_cnt = num2 = 0;
end = start = buf;
in = (__u16 *) addr;
memset(in, 0, 16);
while (*end) {
end = strchr(start, ':');
if (end == NULL) {
end = buf + strlen(buf);
end_tmp = strchr(start, '\n');
if (end_tmp != NULL)
end = end_tmp;
out = 1;
}
if ((end - start)) {
memset(num, 0, 5);
if ((end - start) > 4)
return -EINVAL;
memcpy(num, start, end - start);
if (!qeth_l3_isxdigit(num))
return -EINVAL;
sscanf(start, "%x", &num2);
if (found)
in_tmp[save_cnt++] = num2;
else
in[cnt++] = num2;
if (out)
break;
} else {
if (found)
return -EINVAL;
found = 1;
}
start = ++end;
}
if (cnt + save_cnt > 8)
return -EINVAL;
cnt = 7;
while (save_cnt)
in[cnt--] = in_tmp[--save_cnt];
return 0;
}
void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
char *buf) char *buf)
{ {
...@@ -139,17 +67,6 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, ...@@ -139,17 +67,6 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
qeth_l3_ipaddr6_to_string(addr, buf); qeth_l3_ipaddr6_to_string(addr, buf);
} }
int qeth_l3_string_to_ipaddr(const char *buf, enum qeth_prot_versions proto,
__u8 *addr)
{
if (proto == QETH_PROT_IPV4)
return qeth_l3_string_to_ipaddr4(buf, addr);
else if (proto == QETH_PROT_IPV6)
return qeth_l3_string_to_ipaddr6(buf, addr);
else
return -EINVAL;
}
static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len) static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
{ {
int i, j; int i, j;
...@@ -207,8 +124,8 @@ inline int ...@@ -207,8 +124,8 @@ inline int
qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2) qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2)
{ {
return addr1->proto == addr2->proto && return addr1->proto == addr2->proto &&
!memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) && !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) &&
!memcmp(&addr1->mac, &addr2->mac, sizeof(addr1->mac)); ether_addr_equal_64bits(addr1->mac, addr2->mac);
} }
static struct qeth_ipaddr * static struct qeth_ipaddr *
...@@ -446,7 +363,7 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card, ...@@ -446,7 +363,7 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card,
if (!iob) if (!iob)
return -ENOMEM; return -ENOMEM;
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
memcpy(&cmd->data.setdelipm.mac, addr->mac, OSA_ADDR_LEN); ether_addr_copy(cmd->data.setdelipm.mac, addr->mac);
if (addr->proto == QETH_PROT_IPV6) if (addr->proto == QETH_PROT_IPV6)
memcpy(cmd->data.setdelipm.ip6, &addr->u.a6.addr, memcpy(cmd->data.setdelipm.ip6, &addr->u.a6.addr,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
...@@ -582,7 +499,6 @@ int qeth_l3_setrouting_v6(struct qeth_card *card) ...@@ -582,7 +499,6 @@ int qeth_l3_setrouting_v6(struct qeth_card *card)
int rc = 0; int rc = 0;
QETH_CARD_TEXT(card, 3, "setrtg6"); QETH_CARD_TEXT(card, 3, "setrtg6");
#ifdef CONFIG_QETH_IPV6
if (!qeth_is_supported(card, IPA_IPV6)) if (!qeth_is_supported(card, IPA_IPV6))
return 0; return 0;
...@@ -599,7 +515,6 @@ int qeth_l3_setrouting_v6(struct qeth_card *card) ...@@ -599,7 +515,6 @@ int qeth_l3_setrouting_v6(struct qeth_card *card)
" on %s. Type set to 'no router'.\n", rc, " on %s. Type set to 'no router'.\n", rc,
QETH_CARD_IFNAME(card)); QETH_CARD_IFNAME(card));
} }
#endif
return rc; return rc;
} }
...@@ -896,27 +811,6 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card, ...@@ -896,27 +811,6 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
return rc; return rc;
} }
static u8 qeth_l3_get_qeth_hdr_flags4(int cast_type)
{
if (cast_type == RTN_MULTICAST)
return QETH_CAST_MULTICAST;
if (cast_type == RTN_BROADCAST)
return QETH_CAST_BROADCAST;
return QETH_CAST_UNICAST;
}
static u8 qeth_l3_get_qeth_hdr_flags6(int cast_type)
{
u8 ct = QETH_HDR_PASSTHRU | QETH_HDR_IPV6;
if (cast_type == RTN_MULTICAST)
return ct | QETH_CAST_MULTICAST;
if (cast_type == RTN_ANYCAST)
return ct | QETH_CAST_ANYCAST;
if (cast_type == RTN_BROADCAST)
return ct | QETH_CAST_BROADCAST;
return ct | QETH_CAST_UNICAST;
}
static int qeth_l3_setadapter_parms(struct qeth_card *card) static int qeth_l3_setadapter_parms(struct qeth_card *card)
{ {
int rc = 0; int rc = 0;
...@@ -933,7 +827,6 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card) ...@@ -933,7 +827,6 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card)
return rc; return rc;
} }
#ifdef CONFIG_QETH_IPV6
static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card, static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card,
enum qeth_ipa_funcs ipa_func, __u16 cmd_code) enum qeth_ipa_funcs ipa_func, __u16 cmd_code)
{ {
...@@ -949,7 +842,6 @@ static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card, ...@@ -949,7 +842,6 @@ static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card,
qeth_setassparms_cb, NULL); qeth_setassparms_cb, NULL);
return rc; return rc;
} }
#endif
static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card) static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card)
{ {
...@@ -1045,7 +937,6 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card) ...@@ -1045,7 +937,6 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card)
return rc; return rc;
} }
#ifdef CONFIG_QETH_IPV6
static int qeth_l3_softsetup_ipv6(struct qeth_card *card) static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
{ {
int rc; int rc;
...@@ -1091,12 +982,9 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) ...@@ -1091,12 +982,9 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
dev_info(&card->gdev->dev, "IPV6 enabled\n"); dev_info(&card->gdev->dev, "IPV6 enabled\n");
return 0; return 0;
} }
#endif
static int qeth_l3_start_ipa_ipv6(struct qeth_card *card) static int qeth_l3_start_ipa_ipv6(struct qeth_card *card)
{ {
int rc = 0;
QETH_CARD_TEXT(card, 3, "strtipv6"); QETH_CARD_TEXT(card, 3, "strtipv6");
if (!qeth_is_supported(card, IPA_IPV6)) { if (!qeth_is_supported(card, IPA_IPV6)) {
...@@ -1104,10 +992,7 @@ static int qeth_l3_start_ipa_ipv6(struct qeth_card *card) ...@@ -1104,10 +992,7 @@ static int qeth_l3_start_ipa_ipv6(struct qeth_card *card)
"IPv6 not supported on %s\n", QETH_CARD_IFNAME(card)); "IPv6 not supported on %s\n", QETH_CARD_IFNAME(card));
return 0; return 0;
} }
#ifdef CONFIG_QETH_IPV6 return qeth_l3_softsetup_ipv6(card);
rc = qeth_l3_softsetup_ipv6(card);
#endif
return rc ;
} }
static int qeth_l3_start_ipa_broadcast(struct qeth_card *card) static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
...@@ -1179,8 +1064,8 @@ static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card, ...@@ -1179,8 +1064,8 @@ static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data; cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code == 0) if (cmd->hdr.return_code == 0)
memcpy(card->dev->dev_addr, ether_addr_copy(card->dev->dev_addr,
cmd->data.create_destroy_addr.unique_id, ETH_ALEN); cmd->data.create_destroy_addr.unique_id);
else else
eth_random_addr(card->dev->dev_addr); eth_random_addr(card->dev->dev_addr);
...@@ -1328,81 +1213,22 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) ...@@ -1328,81 +1213,22 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL); return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL);
} }
static void qeth_l3_get_mac_for_ipm(__be32 ipm, char *mac)
{
ip_eth_mc_map(ipm, mac);
}
static void qeth_l3_mark_all_mc_to_be_deleted(struct qeth_card *card)
{
struct qeth_ipaddr *addr;
int i;
hash_for_each(card->ip_mc_htable, i, addr, hnode)
addr->disp_flag = QETH_DISP_ADDR_DELETE;
}
static void qeth_l3_add_all_new_mc(struct qeth_card *card)
{
struct qeth_ipaddr *addr;
struct hlist_node *tmp;
int i;
int rc;
hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) {
if (addr->disp_flag == QETH_DISP_ADDR_ADD) {
rc = qeth_l3_register_addr_entry(card, addr);
if (!rc || (rc == IPA_RC_LAN_OFFLINE))
addr->ref_counter = 1;
else {
hash_del(&addr->hnode);
kfree(addr);
}
}
}
}
static void qeth_l3_delete_nonused_mc(struct qeth_card *card)
{
struct qeth_ipaddr *addr;
struct hlist_node *tmp;
int i;
int rc;
hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) {
if (addr->disp_flag == QETH_DISP_ADDR_DELETE) {
rc = qeth_l3_deregister_addr_entry(card, addr);
if (!rc || (rc == IPA_RC_MC_ADDR_NOT_FOUND)) {
hash_del(&addr->hnode);
kfree(addr);
}
}
}
}
static void static void
qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev)
{ {
struct ip_mc_list *im4; struct ip_mc_list *im4;
struct qeth_ipaddr *tmp, *ipm; struct qeth_ipaddr *tmp, *ipm;
char buf[MAX_ADDR_LEN];
QETH_CARD_TEXT(card, 4, "addmc"); QETH_CARD_TEXT(card, 4, "addmc");
tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
if (!tmp) if (!tmp)
return; return;
for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL; for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL;
im4 = rcu_dereference(im4->next_rcu)) { im4 = rcu_dereference(im4->next_rcu)) {
qeth_l3_get_mac_for_ipm(im4->multiaddr, buf); ip_eth_mc_map(im4->multiaddr, tmp->mac);
tmp->u.a4.addr = be32_to_cpu(im4->multiaddr); tmp->u.a4.addr = be32_to_cpu(im4->multiaddr);
memcpy(tmp->mac, buf, sizeof(tmp->mac));
tmp->is_multicast = 1; tmp->is_multicast = 1;
ipm = qeth_l3_ip_from_hash(card, tmp); ipm = qeth_l3_ip_from_hash(card, tmp);
...@@ -1412,7 +1238,7 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) ...@@ -1412,7 +1238,7 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev)
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
if (!ipm) if (!ipm)
continue; continue;
memcpy(ipm->mac, buf, sizeof(tmp->mac)); ether_addr_copy(ipm->mac, tmp->mac);
ipm->u.a4.addr = be32_to_cpu(im4->multiaddr); ipm->u.a4.addr = be32_to_cpu(im4->multiaddr);
ipm->is_multicast = 1; ipm->is_multicast = 1;
ipm->disp_flag = QETH_DISP_ADDR_ADD; ipm->disp_flag = QETH_DISP_ADDR_ADD;
...@@ -1466,25 +1292,21 @@ static void qeth_l3_add_multicast_ipv4(struct qeth_card *card) ...@@ -1466,25 +1292,21 @@ static void qeth_l3_add_multicast_ipv4(struct qeth_card *card)
rcu_read_unlock(); rcu_read_unlock();
} }
#ifdef CONFIG_QETH_IPV6 static void qeth_l3_add_mc6_to_hash(struct qeth_card *card,
static void struct inet6_dev *in6_dev)
qeth_l3_add_mc6_to_hash(struct qeth_card *card, struct inet6_dev *in6_dev)
{ {
struct qeth_ipaddr *ipm; struct qeth_ipaddr *ipm;
struct ifmcaddr6 *im6; struct ifmcaddr6 *im6;
struct qeth_ipaddr *tmp; struct qeth_ipaddr *tmp;
char buf[MAX_ADDR_LEN];
QETH_CARD_TEXT(card, 4, "addmc6"); QETH_CARD_TEXT(card, 4, "addmc6");
tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
if (!tmp) if (!tmp)
return; return;
for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) { for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
ndisc_mc_map(&im6->mca_addr, buf, in6_dev->dev, 0); ipv6_eth_mc_map(&im6->mca_addr, tmp->mac);
memcpy(tmp->mac, buf, sizeof(tmp->mac));
memcpy(&tmp->u.a6.addr, &im6->mca_addr.s6_addr, memcpy(&tmp->u.a6.addr, &im6->mca_addr.s6_addr,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
tmp->is_multicast = 1; tmp->is_multicast = 1;
...@@ -1499,7 +1321,7 @@ qeth_l3_add_mc6_to_hash(struct qeth_card *card, struct inet6_dev *in6_dev) ...@@ -1499,7 +1321,7 @@ qeth_l3_add_mc6_to_hash(struct qeth_card *card, struct inet6_dev *in6_dev)
if (!ipm) if (!ipm)
continue; continue;
memcpy(ipm->mac, buf, OSA_ADDR_LEN); ether_addr_copy(ipm->mac, tmp->mac);
memcpy(&ipm->u.a6.addr, &im6->mca_addr.s6_addr, memcpy(&ipm->u.a6.addr, &im6->mca_addr.s6_addr,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
ipm->is_multicast = 1; ipm->is_multicast = 1;
...@@ -1560,7 +1382,6 @@ static void qeth_l3_add_multicast_ipv6(struct qeth_card *card) ...@@ -1560,7 +1382,6 @@ static void qeth_l3_add_multicast_ipv6(struct qeth_card *card)
rcu_read_unlock(); rcu_read_unlock();
in6_dev_put(in6_dev); in6_dev_put(in6_dev);
} }
#endif /* CONFIG_QETH_IPV6 */
static void qeth_l3_free_vlan_addresses4(struct qeth_card *card, static void qeth_l3_free_vlan_addresses4(struct qeth_card *card,
unsigned short vid) unsigned short vid)
...@@ -1600,9 +1421,8 @@ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card, ...@@ -1600,9 +1421,8 @@ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card,
} }
static void qeth_l3_free_vlan_addresses6(struct qeth_card *card, static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
unsigned short vid) unsigned short vid)
{ {
#ifdef CONFIG_QETH_IPV6
struct inet6_dev *in6_dev; struct inet6_dev *in6_dev;
struct inet6_ifaddr *ifa; struct inet6_ifaddr *ifa;
struct qeth_ipaddr *addr; struct qeth_ipaddr *addr;
...@@ -1637,7 +1457,6 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card, ...@@ -1637,7 +1457,6 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
kfree(addr); kfree(addr);
out: out:
in6_dev_put(in6_dev); in6_dev_put(in6_dev);
#endif /* CONFIG_QETH_IPV6 */
} }
static void qeth_l3_free_vlan_addresses(struct qeth_card *card, static void qeth_l3_free_vlan_addresses(struct qeth_card *card,
...@@ -1672,44 +1491,31 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev, ...@@ -1672,44 +1491,31 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
/* unregister IP addresses of vlan device */ /* unregister IP addresses of vlan device */
qeth_l3_free_vlan_addresses(card, vid); qeth_l3_free_vlan_addresses(card, vid);
clear_bit(vid, card->active_vlans); clear_bit(vid, card->active_vlans);
qeth_l3_set_multicast_list(card->dev); qeth_l3_set_rx_mode(dev);
return 0; return 0;
} }
static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr) struct qeth_hdr *hdr)
{ {
__u16 prot;
struct iphdr *ip_hdr;
unsigned char tg_addr[MAX_ADDR_LEN];
if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) { if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) {
prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 : u16 prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 :
ETH_P_IP; ETH_P_IP;
unsigned char tg_addr[ETH_ALEN];
skb_reset_network_header(skb);
switch (hdr->hdr.l3.flags & QETH_HDR_CAST_MASK) { switch (hdr->hdr.l3.flags & QETH_HDR_CAST_MASK) {
case QETH_CAST_MULTICAST: case QETH_CAST_MULTICAST:
switch (prot) { if (prot == ETH_P_IP)
#ifdef CONFIG_QETH_IPV6 ip_eth_mc_map(ip_hdr(skb)->daddr, tg_addr);
case ETH_P_IPV6: else
ndisc_mc_map((struct in6_addr *) ipv6_eth_mc_map(&ipv6_hdr(skb)->daddr, tg_addr);
skb->data + 24,
tg_addr, card->dev, 0);
break;
#endif
case ETH_P_IP:
ip_hdr = (struct iphdr *)skb->data;
ip_eth_mc_map(ip_hdr->daddr, tg_addr);
break;
default:
memcpy(tg_addr, card->dev->broadcast,
card->dev->addr_len);
}
card->stats.multicast++; card->stats.multicast++;
skb->pkt_type = PACKET_MULTICAST; skb->pkt_type = PACKET_MULTICAST;
break; break;
case QETH_CAST_BROADCAST: case QETH_CAST_BROADCAST:
memcpy(tg_addr, card->dev->broadcast, ether_addr_copy(tg_addr, card->dev->broadcast);
card->dev->addr_len);
card->stats.multicast++; card->stats.multicast++;
skb->pkt_type = PACKET_BROADCAST; skb->pkt_type = PACKET_BROADCAST;
break; break;
...@@ -1721,12 +1527,11 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, ...@@ -1721,12 +1527,11 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
skb->pkt_type = PACKET_OTHERHOST; skb->pkt_type = PACKET_OTHERHOST;
else else
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
memcpy(tg_addr, card->dev->dev_addr, ether_addr_copy(tg_addr, card->dev->dev_addr);
card->dev->addr_len);
} }
if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR) if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
card->dev->header_ops->create(skb, card->dev, prot, card->dev->header_ops->create(skb, card->dev, prot,
tg_addr, &hdr->hdr.l3.dest_addr[2], tg_addr, &hdr->hdr.l3.next_hop.rx.src_mac,
card->dev->addr_len); card->dev->addr_len);
else else
card->dev->header_ops->create(skb, card->dev, prot, card->dev->header_ops->create(skb, card->dev, prot,
...@@ -1741,7 +1546,7 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, ...@@ -1741,7 +1546,7 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
QETH_HDR_EXT_INCLUDE_VLAN_TAG))) { QETH_HDR_EXT_INCLUDE_VLAN_TAG))) {
u16 tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ? u16 tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ?
hdr->hdr.l3.vlan_id : hdr->hdr.l3.vlan_id :
*((u16 *)&hdr->hdr.l3.dest_addr[12]); hdr->hdr.l3.next_hop.rx.vlan_id;
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag); __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag);
} }
...@@ -1949,26 +1754,46 @@ qeth_l3_handle_promisc_mode(struct qeth_card *card) ...@@ -1949,26 +1754,46 @@ qeth_l3_handle_promisc_mode(struct qeth_card *card)
} }
} }
static void qeth_l3_set_multicast_list(struct net_device *dev) static void qeth_l3_set_rx_mode(struct net_device *dev)
{ {
struct qeth_card *card = dev->ml_priv; struct qeth_card *card = dev->ml_priv;
struct qeth_ipaddr *addr;
struct hlist_node *tmp;
int i, rc;
QETH_CARD_TEXT(card, 3, "setmulti"); QETH_CARD_TEXT(card, 3, "setmulti");
if (qeth_threads_running(card, QETH_RECOVER_THREAD) && if (qeth_threads_running(card, QETH_RECOVER_THREAD) &&
(card->state != CARD_STATE_UP)) (card->state != CARD_STATE_UP))
return; return;
if (!card->options.sniffer) { if (!card->options.sniffer) {
spin_lock_bh(&card->mclock); spin_lock_bh(&card->mclock);
qeth_l3_mark_all_mc_to_be_deleted(card);
qeth_l3_add_multicast_ipv4(card); qeth_l3_add_multicast_ipv4(card);
#ifdef CONFIG_QETH_IPV6
qeth_l3_add_multicast_ipv6(card); qeth_l3_add_multicast_ipv6(card);
#endif
qeth_l3_delete_nonused_mc(card); hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) {
qeth_l3_add_all_new_mc(card); switch (addr->disp_flag) {
case QETH_DISP_ADDR_DELETE:
rc = qeth_l3_deregister_addr_entry(card, addr);
if (!rc || rc == IPA_RC_MC_ADDR_NOT_FOUND) {
hash_del(&addr->hnode);
kfree(addr);
}
break;
case QETH_DISP_ADDR_ADD:
rc = qeth_l3_register_addr_entry(card, addr);
if (rc && rc != IPA_RC_LAN_OFFLINE) {
hash_del(&addr->hnode);
kfree(addr);
break;
}
addr->ref_counter = 1;
/* fall through */
default:
/* for next call to set_rx_mode(): */
addr->disp_flag = QETH_DISP_ADDR_DELETE;
}
}
spin_unlock_bh(&card->mclock); spin_unlock_bh(&card->mclock);
...@@ -2237,12 +2062,10 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) ...@@ -2237,12 +2062,10 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
rc = -EFAULT; rc = -EFAULT;
goto free_and_out; goto free_and_out;
} }
#ifdef CONFIG_QETH_IPV6
if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) { if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) {
/* fails in case of GuestLAN QDIO mode */ /* fails in case of GuestLAN QDIO mode */
qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6, &qinfo); qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6, &qinfo);
} }
#endif
if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) { if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) {
QETH_CARD_TEXT(card, 4, "qactf"); QETH_CARD_TEXT(card, 4, "qactf");
rc = -EFAULT; rc = -EFAULT;
...@@ -2422,9 +2245,8 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -2422,9 +2245,8 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return rc; return rc;
} }
static int qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) static int qeth_l3_get_cast_type(struct sk_buff *skb)
{ {
int cast_type = RTN_UNSPEC;
struct neighbour *n = NULL; struct neighbour *n = NULL;
struct dst_entry *dst; struct dst_entry *dst;
...@@ -2433,48 +2255,34 @@ static int qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) ...@@ -2433,48 +2255,34 @@ static int qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
if (dst) if (dst)
n = dst_neigh_lookup_skb(dst, skb); n = dst_neigh_lookup_skb(dst, skb);
if (n) { if (n) {
cast_type = n->type; int cast_type = n->type;
rcu_read_unlock(); rcu_read_unlock();
neigh_release(n); neigh_release(n);
if ((cast_type == RTN_BROADCAST) || if ((cast_type == RTN_BROADCAST) ||
(cast_type == RTN_MULTICAST) || (cast_type == RTN_MULTICAST) ||
(cast_type == RTN_ANYCAST)) (cast_type == RTN_ANYCAST))
return cast_type; return cast_type;
else return RTN_UNSPEC;
return RTN_UNSPEC;
} }
rcu_read_unlock(); rcu_read_unlock();
/* try something else */ /* no neighbour (eg AF_PACKET), fall back to target's IP address ... */
if (be16_to_cpu(skb->protocol) == ETH_P_IPV6) if (be16_to_cpu(skb->protocol) == ETH_P_IPV6)
return (skb_network_header(skb)[24] == 0xff) ? return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ?
RTN_MULTICAST : 0; RTN_MULTICAST : RTN_UNSPEC;
else if (be16_to_cpu(skb->protocol) == ETH_P_IP) else if (be16_to_cpu(skb->protocol) == ETH_P_IP)
return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ? return ipv4_is_multicast(ip_hdr(skb)->daddr) ?
RTN_MULTICAST : 0; RTN_MULTICAST : RTN_UNSPEC;
/* ... */
if (!memcmp(skb->data, skb->dev->broadcast, 6)) /* ... and MAC address */
if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, skb->dev->broadcast))
return RTN_BROADCAST; return RTN_BROADCAST;
else { if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
u16 hdr_mac; return RTN_MULTICAST;
hdr_mac = *((u16 *)skb->data); /* default to unicast */
/* tr multicast? */ return RTN_UNSPEC;
switch (card->info.link_type) {
case QETH_LINK_TYPE_HSTR:
case QETH_LINK_TYPE_LANE_TR:
if ((hdr_mac == QETH_TR_MAC_NC) ||
(hdr_mac == QETH_TR_MAC_C))
return RTN_MULTICAST;
break;
/* eth or so multicast? */
default:
if ((hdr_mac == QETH_ETH_MAC_V4) ||
(hdr_mac == QETH_ETH_MAC_V6))
return RTN_MULTICAST;
}
}
return cast_type;
} }
static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card, static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card,
...@@ -2494,17 +2302,27 @@ static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card, ...@@ -2494,17 +2302,27 @@ static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card,
daddr[0] = 0xfe; daddr[0] = 0xfe;
daddr[1] = 0x80; daddr[1] = 0x80;
memcpy(&daddr[8], iucv_hdr->destUserID, 8); memcpy(&daddr[8], iucv_hdr->destUserID, 8);
memcpy(hdr->hdr.l3.dest_addr, daddr, 16); memcpy(hdr->hdr.l3.next_hop.ipv6_addr, daddr, 16);
} }
static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, static u8 qeth_l3_cast_type_to_flag(int cast_type)
struct sk_buff *skb, int ipv, int cast_type)
{ {
struct dst_entry *dst; if (cast_type == RTN_MULTICAST)
return QETH_CAST_MULTICAST;
if (cast_type == RTN_ANYCAST)
return QETH_CAST_ANYCAST;
if (cast_type == RTN_BROADCAST)
return QETH_CAST_BROADCAST;
return QETH_CAST_UNICAST;
}
static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type,
unsigned int data_len)
{
memset(hdr, 0, sizeof(struct qeth_hdr)); memset(hdr, 0, sizeof(struct qeth_hdr));
hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
hdr->hdr.l3.ext_flags = 0; hdr->hdr.l3.length = data_len;
/* /*
* before we're going to overwrite this location with next hop ip. * before we're going to overwrite this location with next hop ip.
...@@ -2518,44 +2336,40 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, ...@@ -2518,44 +2336,40 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb); hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb);
} }
hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr); /* OSA only: */
if (!ipv) {
hdr->hdr.l3.flags = QETH_HDR_PASSTHRU;
if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest,
skb->dev->broadcast))
hdr->hdr.l3.flags |= QETH_CAST_BROADCAST;
else
hdr->hdr.l3.flags |= (cast_type == RTN_MULTICAST) ?
QETH_CAST_MULTICAST : QETH_CAST_UNICAST;
return;
}
hdr->hdr.l3.flags = qeth_l3_cast_type_to_flag(cast_type);
rcu_read_lock(); rcu_read_lock();
dst = skb_dst(skb);
if (ipv == 4) { if (ipv == 4) {
struct rtable *rt = (struct rtable *) dst; struct rtable *rt = skb_rtable(skb);
__be32 *pkey = &ip_hdr(skb)->daddr;
if (rt && rt->rt_gateway) *((__be32 *) &hdr->hdr.l3.next_hop.ipv4.addr) = (rt) ?
pkey = &rt->rt_gateway; rt_nexthop(rt, ip_hdr(skb)->daddr) :
ip_hdr(skb)->daddr;
/* IPv4 */ } else {
hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); /* IPv6 */
memset(hdr->hdr.l3.dest_addr, 0, 12); const struct rt6_info *rt = skb_rt6_info(skb);
*((__be32 *) (&hdr->hdr.l3.dest_addr[12])) = *pkey; const struct in6_addr *next_hop;
} else if (ipv == 6) {
struct rt6_info *rt = (struct rt6_info *) dst;
struct in6_addr *pkey = &ipv6_hdr(skb)->daddr;
if (rt && !ipv6_addr_any(&rt->rt6i_gateway)) if (rt && !ipv6_addr_any(&rt->rt6i_gateway))
pkey = &rt->rt6i_gateway; next_hop = &rt->rt6i_gateway;
else
next_hop = &ipv6_hdr(skb)->daddr;
memcpy(hdr->hdr.l3.next_hop.ipv6_addr, next_hop, 16);
/* IPv6 */ hdr->hdr.l3.flags |= QETH_HDR_IPV6;
hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); if (card->info.type != QETH_CARD_TYPE_IQD)
if (card->info.type == QETH_CARD_TYPE_IQD) hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU;
hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU;
memcpy(hdr->hdr.l3.dest_addr, pkey, 16);
} else {
if (!memcmp(skb->data + sizeof(struct qeth_hdr),
skb->dev->broadcast, 6)) {
/* broadcast? */
hdr->hdr.l3.flags = QETH_CAST_BROADCAST |
QETH_HDR_PASSTHRU;
} else {
hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ?
QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU :
QETH_CAST_UNICAST | QETH_HDR_PASSTHRU;
}
} }
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -2587,7 +2401,6 @@ static void qeth_tso_fill_header(struct qeth_card *card, ...@@ -2587,7 +2401,6 @@ static void qeth_tso_fill_header(struct qeth_card *card,
/*fix header to TSO values ...*/ /*fix header to TSO values ...*/
hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO; hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO;
hdr->hdr.hdr.l3.length = skb->len - sizeof(struct qeth_hdr_tso);
/*set values which are fix for the first approach ...*/ /*set values which are fix for the first approach ...*/
hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso); hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso);
hdr->ext.imb_hdr_no = 1; hdr->ext.imb_hdr_no = 1;
...@@ -2655,7 +2468,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, ...@@ -2655,7 +2468,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
struct qeth_card *card = dev->ml_priv; struct qeth_card *card = dev->ml_priv;
struct sk_buff *new_skb = NULL; struct sk_buff *new_skb = NULL;
int ipv = qeth_get_ip_version(skb); int ipv = qeth_get_ip_version(skb);
int cast_type = qeth_l3_get_cast_type(card, skb); int cast_type = qeth_l3_get_cast_type(skb);
struct qeth_qdio_out_q *queue = struct qeth_qdio_out_q *queue =
card->qdio.out_qs[card->qdio.do_prio_queueing card->qdio.out_qs[card->qdio.do_prio_queueing
|| (cast_type && card->info.is_multicast_different) ? || (cast_type && card->info.is_multicast_different) ?
...@@ -2748,21 +2561,23 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, ...@@ -2748,21 +2561,23 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb,
if (use_tso) { if (use_tso) {
hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso)); hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso));
memset(hdr, 0, sizeof(struct qeth_hdr_tso)); memset(hdr, 0, sizeof(struct qeth_hdr_tso));
qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type,
new_skb->len - sizeof(struct qeth_hdr_tso));
qeth_tso_fill_header(card, hdr, new_skb); qeth_tso_fill_header(card, hdr, new_skb);
hdr_elements++; hdr_elements++;
} else { } else {
if (data_offset < 0) { if (data_offset < 0) {
hdr = skb_push(new_skb, sizeof(struct qeth_hdr)); hdr = skb_push(new_skb, sizeof(struct qeth_hdr));
qeth_l3_fill_header(card, hdr, new_skb, ipv, qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type,
cast_type); new_skb->len -
sizeof(struct qeth_hdr));
} else { } else {
if (be16_to_cpu(new_skb->protocol) == ETH_P_AF_IUCV) if (be16_to_cpu(new_skb->protocol) == ETH_P_AF_IUCV)
qeth_l3_fill_af_iucv_hdr(card, hdr, new_skb); qeth_l3_fill_af_iucv_hdr(card, hdr, new_skb);
else { else {
qeth_l3_fill_header(card, hdr, new_skb, ipv, qeth_l3_fill_header(card, hdr, new_skb, ipv,
cast_type); cast_type,
hdr->hdr.l3.length = new_skb->len - data_offset; new_skb->len - data_offset);
} }
} }
...@@ -2930,7 +2745,7 @@ static const struct net_device_ops qeth_l3_netdev_ops = { ...@@ -2930,7 +2745,7 @@ static const struct net_device_ops qeth_l3_netdev_ops = {
.ndo_get_stats = qeth_get_stats, .ndo_get_stats = qeth_get_stats,
.ndo_start_xmit = qeth_l3_hard_start_xmit, .ndo_start_xmit = qeth_l3_hard_start_xmit,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_set_rx_mode = qeth_l3_set_multicast_list, .ndo_set_rx_mode = qeth_l3_set_rx_mode,
.ndo_do_ioctl = qeth_do_ioctl, .ndo_do_ioctl = qeth_do_ioctl,
.ndo_change_mtu = qeth_change_mtu, .ndo_change_mtu = qeth_change_mtu,
.ndo_fix_features = qeth_fix_features, .ndo_fix_features = qeth_fix_features,
...@@ -2947,7 +2762,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { ...@@ -2947,7 +2762,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
.ndo_start_xmit = qeth_l3_hard_start_xmit, .ndo_start_xmit = qeth_l3_hard_start_xmit,
.ndo_features_check = qeth_features_check, .ndo_features_check = qeth_features_check,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_set_rx_mode = qeth_l3_set_multicast_list, .ndo_set_rx_mode = qeth_l3_set_rx_mode,
.ndo_do_ioctl = qeth_do_ioctl, .ndo_do_ioctl = qeth_do_ioctl,
.ndo_change_mtu = qeth_change_mtu, .ndo_change_mtu = qeth_change_mtu,
.ndo_fix_features = qeth_fix_features, .ndo_fix_features = qeth_fix_features,
...@@ -3145,7 +2960,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) ...@@ -3145,7 +2960,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
__qeth_l3_open(card->dev); __qeth_l3_open(card->dev);
else else
dev_open(card->dev); dev_open(card->dev);
qeth_l3_set_multicast_list(card->dev); qeth_l3_set_rx_mode(card->dev);
qeth_recover_features(card->dev); qeth_recover_features(card->dev);
rtnl_unlock(); rtnl_unlock();
} }
...@@ -3371,10 +3186,6 @@ static struct notifier_block qeth_l3_ip_notifier = { ...@@ -3371,10 +3186,6 @@ static struct notifier_block qeth_l3_ip_notifier = {
NULL, NULL,
}; };
#ifdef CONFIG_QETH_IPV6
/**
* IPv6 event handler
*/
static int qeth_l3_ip6_event(struct notifier_block *this, static int qeth_l3_ip6_event(struct notifier_block *this,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
...@@ -3419,7 +3230,6 @@ static struct notifier_block qeth_l3_ip6_notifier = { ...@@ -3419,7 +3230,6 @@ static struct notifier_block qeth_l3_ip6_notifier = {
qeth_l3_ip6_event, qeth_l3_ip6_event,
NULL, NULL,
}; };
#endif
static int qeth_l3_register_notifiers(void) static int qeth_l3_register_notifiers(void)
{ {
...@@ -3429,35 +3239,25 @@ static int qeth_l3_register_notifiers(void) ...@@ -3429,35 +3239,25 @@ static int qeth_l3_register_notifiers(void)
rc = register_inetaddr_notifier(&qeth_l3_ip_notifier); rc = register_inetaddr_notifier(&qeth_l3_ip_notifier);
if (rc) if (rc)
return rc; return rc;
#ifdef CONFIG_QETH_IPV6
rc = register_inet6addr_notifier(&qeth_l3_ip6_notifier); rc = register_inet6addr_notifier(&qeth_l3_ip6_notifier);
if (rc) { if (rc) {
unregister_inetaddr_notifier(&qeth_l3_ip_notifier); unregister_inetaddr_notifier(&qeth_l3_ip_notifier);
return rc; return rc;
} }
#else
pr_warn("There is no IPv6 support for the layer 3 discipline\n");
#endif
return 0; return 0;
} }
static void qeth_l3_unregister_notifiers(void) static void qeth_l3_unregister_notifiers(void)
{ {
QETH_DBF_TEXT(SETUP, 5, "unregnot"); QETH_DBF_TEXT(SETUP, 5, "unregnot");
WARN_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier)); WARN_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier));
#ifdef CONFIG_QETH_IPV6
WARN_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier)); WARN_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier));
#endif /* QETH_IPV6 */
} }
static int __init qeth_l3_init(void) static int __init qeth_l3_init(void)
{ {
int rc = 0;
pr_info("register layer 3 discipline\n"); pr_info("register layer 3 discipline\n");
rc = qeth_l3_register_notifiers(); return qeth_l3_register_notifiers();
return rc;
} }
static void __exit qeth_l3_exit(void) static void __exit qeth_l3_exit(void)
......
...@@ -10,11 +10,23 @@ ...@@ -10,11 +10,23 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/inet.h>
#include "qeth_l3.h" #include "qeth_l3.h"
#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store) struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
static int qeth_l3_string_to_ipaddr(const char *buf,
enum qeth_prot_versions proto, u8 *addr)
{
const char *end;
if ((proto == QETH_PROT_IPV4 && !in4_pton(buf, -1, addr, -1, &end)) ||
(proto == QETH_PROT_IPV6 && !in6_pton(buf, -1, addr, -1, &end)))
return -EINVAL;
return 0;
}
static ssize_t qeth_l3_dev_route_show(struct qeth_card *card, static ssize_t qeth_l3_dev_route_show(struct qeth_card *card,
struct qeth_routing_info *route, char *buf) struct qeth_routing_info *route, char *buf)
{ {
......
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