/drivers/s390/net/qeth_l3_main.c
https://bitbucket.org/slukk/jb-tsm-kernel-4.2 · C · 3759 lines · 3251 code · 394 blank · 114 comment · 725 complexity · 0ac3595442969ea8ec7f05d360378290 MD5 · raw file
Large files are truncated click here to view the full file
- /*
- * drivers/s390/net/qeth_l3_main.c
- *
- * Copyright IBM Corp. 2007, 2009
- * Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
- * Frank Pavlic <fpavlic@de.ibm.com>,
- * Thomas Spatzier <tspat@de.ibm.com>,
- * Frank Blaschka <frank.blaschka@de.ibm.com>
- */
- #define KMSG_COMPONENT "qeth"
- #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/string.h>
- #include <linux/errno.h>
- #include <linux/kernel.h>
- #include <linux/etherdevice.h>
- #include <linux/mii.h>
- #include <linux/ip.h>
- #include <linux/ipv6.h>
- #include <linux/inetdevice.h>
- #include <linux/igmp.h>
- #include <linux/slab.h>
- #include <net/ip.h>
- #include <net/arp.h>
- #include <net/ip6_checksum.h>
- #include "qeth_l3.h"
- static int qeth_l3_set_offline(struct ccwgroup_device *);
- static int qeth_l3_recover(void *);
- static int qeth_l3_stop(struct net_device *);
- static void qeth_l3_set_multicast_list(struct net_device *);
- static int qeth_l3_neigh_setup(struct net_device *, struct neigh_parms *);
- static int qeth_l3_register_addr_entry(struct qeth_card *,
- struct qeth_ipaddr *);
- static int qeth_l3_deregister_addr_entry(struct qeth_card *,
- struct qeth_ipaddr *);
- static int __qeth_l3_set_online(struct ccwgroup_device *, int);
- static int __qeth_l3_set_offline(struct ccwgroup_device *, int);
- static int qeth_l3_isxdigit(char *buf)
- {
- while (*buf) {
- if (!isxdigit(*buf++))
- return 0;
- }
- return 1;
- }
- void qeth_l3_ipaddr4_to_string(const __u8 *addr, char *buf)
- {
- sprintf(buf, "%i.%i.%i.%i", addr[0], addr[1], addr[2], addr[3]);
- }
- int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr)
- {
- int count = 0, rc = 0;
- 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;
- }
- void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf)
- {
- sprintf(buf, "%pI6", addr);
- }
- 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,
- char *buf)
- {
- if (proto == QETH_PROT_IPV4)
- qeth_l3_ipaddr4_to_string(addr, buf);
- else if (proto == QETH_PROT_IPV6)
- 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)
- {
- int i, j;
- u8 octet;
- for (i = 0; i < len; ++i) {
- octet = addr[i];
- for (j = 7; j >= 0; --j) {
- bits[i*8 + j] = octet & 1;
- octet >>= 1;
- }
- }
- }
- int qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
- struct qeth_ipaddr *addr)
- {
- struct qeth_ipato_entry *ipatoe;
- u8 addr_bits[128] = {0, };
- u8 ipatoe_bits[128] = {0, };
- int rc = 0;
- if (!card->ipato.enabled)
- return 0;
- qeth_l3_convert_addr_to_bits((u8 *) &addr->u, addr_bits,
- (addr->proto == QETH_PROT_IPV4)? 4:16);
- list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
- if (addr->proto != ipatoe->proto)
- continue;
- qeth_l3_convert_addr_to_bits(ipatoe->addr, ipatoe_bits,
- (ipatoe->proto == QETH_PROT_IPV4) ?
- 4 : 16);
- if (addr->proto == QETH_PROT_IPV4)
- rc = !memcmp(addr_bits, ipatoe_bits,
- min(32, ipatoe->mask_bits));
- else
- rc = !memcmp(addr_bits, ipatoe_bits,
- min(128, ipatoe->mask_bits));
- if (rc)
- break;
- }
- /* invert? */
- if ((addr->proto == QETH_PROT_IPV4) && card->ipato.invert4)
- rc = !rc;
- else if ((addr->proto == QETH_PROT_IPV6) && card->ipato.invert6)
- rc = !rc;
- return rc;
- }
- /*
- * Add IP to be added to todo list. If there is already an "add todo"
- * in this list we just incremenent the reference count.
- * Returns 0 if we just incremented reference count.
- */
- static int __qeth_l3_insert_ip_todo(struct qeth_card *card,
- struct qeth_ipaddr *addr, int add)
- {
- struct qeth_ipaddr *tmp, *t;
- int found = 0;
- if (card->options.sniffer)
- return 0;
- list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) {
- if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) &&
- (tmp->type == QETH_IP_TYPE_DEL_ALL_MC))
- return 0;
- if ((tmp->proto == QETH_PROT_IPV4) &&
- (addr->proto == QETH_PROT_IPV4) &&
- (tmp->type == addr->type) &&
- (tmp->is_multicast == addr->is_multicast) &&
- (tmp->u.a4.addr == addr->u.a4.addr) &&
- (tmp->u.a4.mask == addr->u.a4.mask)) {
- found = 1;
- break;
- }
- if ((tmp->proto == QETH_PROT_IPV6) &&
- (addr->proto == QETH_PROT_IPV6) &&
- (tmp->type == addr->type) &&
- (tmp->is_multicast == addr->is_multicast) &&
- (tmp->u.a6.pfxlen == addr->u.a6.pfxlen) &&
- (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr,
- sizeof(struct in6_addr)) == 0)) {
- found = 1;
- break;
- }
- }
- if (found) {
- if (addr->users != 0)
- tmp->users += addr->users;
- else
- tmp->users += add ? 1 : -1;
- if (tmp->users == 0) {
- list_del(&tmp->entry);
- kfree(tmp);
- }
- return 0;
- } else {
- if (addr->type == QETH_IP_TYPE_DEL_ALL_MC)
- list_add(&addr->entry, card->ip_tbd_list);
- else {
- if (addr->users == 0)
- addr->users += add ? 1 : -1;
- if (add && (addr->type == QETH_IP_TYPE_NORMAL) &&
- qeth_l3_is_addr_covered_by_ipato(card, addr)) {
- QETH_CARD_TEXT(card, 2, "tkovaddr");
- addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG;
- }
- list_add_tail(&addr->entry, card->ip_tbd_list);
- }
- return 1;
- }
- }
- static int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
- {
- unsigned long flags;
- int rc = 0;
- QETH_CARD_TEXT(card, 4, "delip");
- if (addr->proto == QETH_PROT_IPV4)
- QETH_CARD_HEX(card, 4, &addr->u.a4.addr, 4);
- else {
- QETH_CARD_HEX(card, 4, &addr->u.a6.addr, 8);
- QETH_CARD_HEX(card, 4, ((char *)&addr->u.a6.addr) + 8, 8);
- }
- spin_lock_irqsave(&card->ip_lock, flags);
- rc = __qeth_l3_insert_ip_todo(card, addr, 0);
- spin_unlock_irqrestore(&card->ip_lock, flags);
- return rc;
- }
- static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
- {
- unsigned long flags;
- int rc = 0;
- QETH_CARD_TEXT(card, 4, "addip");
- if (addr->proto == QETH_PROT_IPV4)
- QETH_CARD_HEX(card, 4, &addr->u.a4.addr, 4);
- else {
- QETH_CARD_HEX(card, 4, &addr->u.a6.addr, 8);
- QETH_CARD_HEX(card, 4, ((char *)&addr->u.a6.addr) + 8, 8);
- }
- spin_lock_irqsave(&card->ip_lock, flags);
- rc = __qeth_l3_insert_ip_todo(card, addr, 1);
- spin_unlock_irqrestore(&card->ip_lock, flags);
- return rc;
- }
- static struct qeth_ipaddr *qeth_l3_get_addr_buffer(
- enum qeth_prot_versions prot)
- {
- struct qeth_ipaddr *addr;
- addr = kzalloc(sizeof(struct qeth_ipaddr), GFP_ATOMIC);
- if (addr == NULL) {
- return NULL;
- }
- addr->type = QETH_IP_TYPE_NORMAL;
- addr->proto = prot;
- return addr;
- }
- static void qeth_l3_delete_mc_addresses(struct qeth_card *card)
- {
- struct qeth_ipaddr *iptodo;
- unsigned long flags;
- QETH_CARD_TEXT(card, 4, "delmc");
- iptodo = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
- if (!iptodo) {
- QETH_CARD_TEXT(card, 2, "dmcnomem");
- return;
- }
- iptodo->type = QETH_IP_TYPE_DEL_ALL_MC;
- spin_lock_irqsave(&card->ip_lock, flags);
- if (!__qeth_l3_insert_ip_todo(card, iptodo, 0))
- kfree(iptodo);
- spin_unlock_irqrestore(&card->ip_lock, flags);
- }
- /*
- * Add/remove address to/from card's ip list, i.e. try to add or remove
- * reference to/from an IP address that is already registered on the card.
- * Returns:
- * 0 address was on card and its reference count has been adjusted,
- * but is still > 0, so nothing has to be done
- * also returns 0 if card was not on card and the todo was to delete
- * the address -> there is also nothing to be done
- * 1 address was not on card and the todo is to add it to the card's ip
- * list
- * -1 address was on card and its reference count has been decremented
- * to <= 0 by the todo -> address must be removed from card
- */
- static int __qeth_l3_ref_ip_on_card(struct qeth_card *card,
- struct qeth_ipaddr *todo, struct qeth_ipaddr **__addr)
- {
- struct qeth_ipaddr *addr;
- int found = 0;
- list_for_each_entry(addr, &card->ip_list, entry) {
- if ((addr->proto == QETH_PROT_IPV4) &&
- (todo->proto == QETH_PROT_IPV4) &&
- (addr->type == todo->type) &&
- (addr->u.a4.addr == todo->u.a4.addr) &&
- (addr->u.a4.mask == todo->u.a4.mask)) {
- found = 1;
- break;
- }
- if ((addr->proto == QETH_PROT_IPV6) &&
- (todo->proto == QETH_PROT_IPV6) &&
- (addr->type == todo->type) &&
- (addr->u.a6.pfxlen == todo->u.a6.pfxlen) &&
- (memcmp(&addr->u.a6.addr, &todo->u.a6.addr,
- sizeof(struct in6_addr)) == 0)) {
- found = 1;
- break;
- }
- }
- if (found) {
- addr->users += todo->users;
- if (addr->users <= 0) {
- *__addr = addr;
- return -1;
- } else {
- /* for VIPA and RXIP limit refcount to 1 */
- if (addr->type != QETH_IP_TYPE_NORMAL)
- addr->users = 1;
- return 0;
- }
- }
- if (todo->users > 0) {
- /* for VIPA and RXIP limit refcount to 1 */
- if (todo->type != QETH_IP_TYPE_NORMAL)
- todo->users = 1;
- return 1;
- } else
- return 0;
- }
- static void __qeth_l3_delete_all_mc(struct qeth_card *card,
- unsigned long *flags)
- {
- struct list_head fail_list;
- struct qeth_ipaddr *addr, *tmp;
- int rc;
- INIT_LIST_HEAD(&fail_list);
- again:
- list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) {
- if (addr->is_multicast) {
- list_del(&addr->entry);
- spin_unlock_irqrestore(&card->ip_lock, *flags);
- rc = qeth_l3_deregister_addr_entry(card, addr);
- spin_lock_irqsave(&card->ip_lock, *flags);
- if (!rc || (rc == IPA_RC_MC_ADDR_NOT_FOUND))
- kfree(addr);
- else
- list_add_tail(&addr->entry, &fail_list);
- goto again;
- }
- }
- list_splice(&fail_list, &card->ip_list);
- }
- static void qeth_l3_set_ip_addr_list(struct qeth_card *card)
- {
- struct list_head *tbd_list;
- struct qeth_ipaddr *todo, *addr;
- unsigned long flags;
- int rc;
- QETH_CARD_TEXT(card, 2, "sdiplist");
- QETH_CARD_HEX(card, 2, &card, sizeof(void *));
- if ((card->state != CARD_STATE_UP &&
- card->state != CARD_STATE_SOFTSETUP) || card->options.sniffer) {
- return;
- }
- spin_lock_irqsave(&card->ip_lock, flags);
- tbd_list = card->ip_tbd_list;
- card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
- if (!card->ip_tbd_list) {
- QETH_CARD_TEXT(card, 0, "silnomem");
- card->ip_tbd_list = tbd_list;
- spin_unlock_irqrestore(&card->ip_lock, flags);
- return;
- } else
- INIT_LIST_HEAD(card->ip_tbd_list);
- while (!list_empty(tbd_list)) {
- todo = list_entry(tbd_list->next, struct qeth_ipaddr, entry);
- list_del(&todo->entry);
- if (todo->type == QETH_IP_TYPE_DEL_ALL_MC) {
- __qeth_l3_delete_all_mc(card, &flags);
- kfree(todo);
- continue;
- }
- rc = __qeth_l3_ref_ip_on_card(card, todo, &addr);
- if (rc == 0) {
- /* nothing to be done; only adjusted refcount */
- kfree(todo);
- } else if (rc == 1) {
- /* new entry to be added to on-card list */
- spin_unlock_irqrestore(&card->ip_lock, flags);
- rc = qeth_l3_register_addr_entry(card, todo);
- spin_lock_irqsave(&card->ip_lock, flags);
- if (!rc || (rc == IPA_RC_LAN_OFFLINE))
- list_add_tail(&todo->entry, &card->ip_list);
- else
- kfree(todo);
- } else if (rc == -1) {
- /* on-card entry to be removed */
- list_del_init(&addr->entry);
- spin_unlock_irqrestore(&card->ip_lock, flags);
- rc = qeth_l3_deregister_addr_entry(card, addr);
- spin_lock_irqsave(&card->ip_lock, flags);
- if (!rc || (rc == IPA_RC_IP_ADDRESS_NOT_DEFINED))
- kfree(addr);
- else
- list_add_tail(&addr->entry, &card->ip_list);
- kfree(todo);
- }
- }
- spin_unlock_irqrestore(&card->ip_lock, flags);
- kfree(tbd_list);
- }
- static void qeth_l3_clear_ip_list(struct qeth_card *card, int recover)
- {
- struct qeth_ipaddr *addr, *tmp;
- unsigned long flags;
- QETH_CARD_TEXT(card, 4, "clearip");
- if (recover && card->options.sniffer)
- return;
- spin_lock_irqsave(&card->ip_lock, flags);
- /* clear todo list */
- list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) {
- list_del(&addr->entry);
- kfree(addr);
- }
- while (!list_empty(&card->ip_list)) {
- addr = list_entry(card->ip_list.next,
- struct qeth_ipaddr, entry);
- list_del_init(&addr->entry);
- if (!recover || addr->is_multicast) {
- kfree(addr);
- continue;
- }
- list_add_tail(&addr->entry, card->ip_tbd_list);
- }
- spin_unlock_irqrestore(&card->ip_lock, flags);
- }
- static int qeth_l3_address_exists_in_list(struct list_head *list,
- struct qeth_ipaddr *addr, int same_type)
- {
- struct qeth_ipaddr *tmp;
- list_for_each_entry(tmp, list, entry) {
- if ((tmp->proto == QETH_PROT_IPV4) &&
- (addr->proto == QETH_PROT_IPV4) &&
- ((same_type && (tmp->type == addr->type)) ||
- (!same_type && (tmp->type != addr->type))) &&
- (tmp->u.a4.addr == addr->u.a4.addr))
- return 1;
- if ((tmp->proto == QETH_PROT_IPV6) &&
- (addr->proto == QETH_PROT_IPV6) &&
- ((same_type && (tmp->type == addr->type)) ||
- (!same_type && (tmp->type != addr->type))) &&
- (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr,
- sizeof(struct in6_addr)) == 0))
- return 1;
- }
- return 0;
- }
- static int qeth_l3_send_setdelmc(struct qeth_card *card,
- struct qeth_ipaddr *addr, int ipacmd)
- {
- int rc;
- struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- QETH_CARD_TEXT(card, 4, "setdelmc");
- iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- memcpy(&cmd->data.setdelipm.mac, addr->mac, OSA_ADDR_LEN);
- if (addr->proto == QETH_PROT_IPV6)
- memcpy(cmd->data.setdelipm.ip6, &addr->u.a6.addr,
- sizeof(struct in6_addr));
- else
- memcpy(&cmd->data.setdelipm.ip4, &addr->u.a4.addr, 4);
- rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
- return rc;
- }
- static void qeth_l3_fill_netmask(u8 *netmask, unsigned int len)
- {
- int i, j;
- for (i = 0; i < 16; i++) {
- j = (len) - (i * 8);
- if (j >= 8)
- netmask[i] = 0xff;
- else if (j > 0)
- netmask[i] = (u8)(0xFF00 >> j);
- else
- netmask[i] = 0;
- }
- }
- static int qeth_l3_send_setdelip(struct qeth_card *card,
- struct qeth_ipaddr *addr, int ipacmd, unsigned int flags)
- {
- int rc;
- struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- __u8 netmask[16];
- QETH_CARD_TEXT(card, 4, "setdelip");
- QETH_CARD_TEXT_(card, 4, "flags%02X", flags);
- iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- if (addr->proto == QETH_PROT_IPV6) {
- memcpy(cmd->data.setdelip6.ip_addr, &addr->u.a6.addr,
- sizeof(struct in6_addr));
- qeth_l3_fill_netmask(netmask, addr->u.a6.pfxlen);
- memcpy(cmd->data.setdelip6.mask, netmask,
- sizeof(struct in6_addr));
- cmd->data.setdelip6.flags = flags;
- } else {
- memcpy(cmd->data.setdelip4.ip_addr, &addr->u.a4.addr, 4);
- memcpy(cmd->data.setdelip4.mask, &addr->u.a4.mask, 4);
- cmd->data.setdelip4.flags = flags;
- }
- rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
- return rc;
- }
- static int qeth_l3_send_setrouting(struct qeth_card *card,
- enum qeth_routing_types type, enum qeth_prot_versions prot)
- {
- int rc;
- struct qeth_ipa_cmd *cmd;
- struct qeth_cmd_buffer *iob;
- QETH_CARD_TEXT(card, 4, "setroutg");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETRTG, prot);
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- cmd->data.setrtg.type = (type);
- rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
- return rc;
- }
- static void qeth_l3_correct_routing_type(struct qeth_card *card,
- enum qeth_routing_types *type, enum qeth_prot_versions prot)
- {
- if (card->info.type == QETH_CARD_TYPE_IQD) {
- switch (*type) {
- case NO_ROUTER:
- case PRIMARY_CONNECTOR:
- case SECONDARY_CONNECTOR:
- case MULTICAST_ROUTER:
- return;
- default:
- goto out_inval;
- }
- } else {
- switch (*type) {
- case NO_ROUTER:
- case PRIMARY_ROUTER:
- case SECONDARY_ROUTER:
- return;
- case MULTICAST_ROUTER:
- if (qeth_is_ipafunc_supported(card, prot,
- IPA_OSA_MC_ROUTER))
- return;
- default:
- goto out_inval;
- }
- }
- out_inval:
- *type = NO_ROUTER;
- }
- int qeth_l3_setrouting_v4(struct qeth_card *card)
- {
- int rc;
- QETH_CARD_TEXT(card, 3, "setrtg4");
- qeth_l3_correct_routing_type(card, &card->options.route4.type,
- QETH_PROT_IPV4);
- rc = qeth_l3_send_setrouting(card, card->options.route4.type,
- QETH_PROT_IPV4);
- if (rc) {
- card->options.route4.type = NO_ROUTER;
- QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type"
- " on %s. Type set to 'no router'.\n", rc,
- QETH_CARD_IFNAME(card));
- }
- return rc;
- }
- int qeth_l3_setrouting_v6(struct qeth_card *card)
- {
- int rc = 0;
- QETH_CARD_TEXT(card, 3, "setrtg6");
- #ifdef CONFIG_QETH_IPV6
- if (!qeth_is_supported(card, IPA_IPV6))
- return 0;
- qeth_l3_correct_routing_type(card, &card->options.route6.type,
- QETH_PROT_IPV6);
- rc = qeth_l3_send_setrouting(card, card->options.route6.type,
- QETH_PROT_IPV6);
- if (rc) {
- card->options.route6.type = NO_ROUTER;
- QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type"
- " on %s. Type set to 'no router'.\n", rc,
- QETH_CARD_IFNAME(card));
- }
- #endif
- return rc;
- }
- /*
- * IP address takeover related functions
- */
- static void qeth_l3_clear_ipato_list(struct qeth_card *card)
- {
- struct qeth_ipato_entry *ipatoe, *tmp;
- unsigned long flags;
- spin_lock_irqsave(&card->ip_lock, flags);
- list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) {
- list_del(&ipatoe->entry);
- kfree(ipatoe);
- }
- spin_unlock_irqrestore(&card->ip_lock, flags);
- }
- int qeth_l3_add_ipato_entry(struct qeth_card *card,
- struct qeth_ipato_entry *new)
- {
- struct qeth_ipato_entry *ipatoe;
- unsigned long flags;
- int rc = 0;
- QETH_CARD_TEXT(card, 2, "addipato");
- spin_lock_irqsave(&card->ip_lock, flags);
- list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
- if (ipatoe->proto != new->proto)
- continue;
- if (!memcmp(ipatoe->addr, new->addr,
- (ipatoe->proto == QETH_PROT_IPV4)? 4:16) &&
- (ipatoe->mask_bits == new->mask_bits)) {
- rc = -EEXIST;
- break;
- }
- }
- if (!rc)
- list_add_tail(&new->entry, &card->ipato.entries);
- spin_unlock_irqrestore(&card->ip_lock, flags);
- return rc;
- }
- void qeth_l3_del_ipato_entry(struct qeth_card *card,
- enum qeth_prot_versions proto, u8 *addr, int mask_bits)
- {
- struct qeth_ipato_entry *ipatoe, *tmp;
- unsigned long flags;
- QETH_CARD_TEXT(card, 2, "delipato");
- spin_lock_irqsave(&card->ip_lock, flags);
- list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) {
- if (ipatoe->proto != proto)
- continue;
- if (!memcmp(ipatoe->addr, addr,
- (proto == QETH_PROT_IPV4)? 4:16) &&
- (ipatoe->mask_bits == mask_bits)) {
- list_del(&ipatoe->entry);
- kfree(ipatoe);
- }
- }
- spin_unlock_irqrestore(&card->ip_lock, flags);
- }
- /*
- * VIPA related functions
- */
- int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
- const u8 *addr)
- {
- struct qeth_ipaddr *ipaddr;
- unsigned long flags;
- int rc = 0;
- ipaddr = qeth_l3_get_addr_buffer(proto);
- if (ipaddr) {
- if (proto == QETH_PROT_IPV4) {
- QETH_CARD_TEXT(card, 2, "addvipa4");
- memcpy(&ipaddr->u.a4.addr, addr, 4);
- ipaddr->u.a4.mask = 0;
- } else if (proto == QETH_PROT_IPV6) {
- QETH_CARD_TEXT(card, 2, "addvipa6");
- memcpy(&ipaddr->u.a6.addr, addr, 16);
- ipaddr->u.a6.pfxlen = 0;
- }
- ipaddr->type = QETH_IP_TYPE_VIPA;
- ipaddr->set_flags = QETH_IPA_SETIP_VIPA_FLAG;
- ipaddr->del_flags = QETH_IPA_DELIP_VIPA_FLAG;
- } else
- return -ENOMEM;
- spin_lock_irqsave(&card->ip_lock, flags);
- if (qeth_l3_address_exists_in_list(&card->ip_list, ipaddr, 0) ||
- qeth_l3_address_exists_in_list(card->ip_tbd_list, ipaddr, 0))
- rc = -EEXIST;
- spin_unlock_irqrestore(&card->ip_lock, flags);
- if (rc) {
- return rc;
- }
- if (!qeth_l3_add_ip(card, ipaddr))
- kfree(ipaddr);
- qeth_l3_set_ip_addr_list(card);
- return rc;
- }
- void qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
- const u8 *addr)
- {
- struct qeth_ipaddr *ipaddr;
- ipaddr = qeth_l3_get_addr_buffer(proto);
- if (ipaddr) {
- if (proto == QETH_PROT_IPV4) {
- QETH_CARD_TEXT(card, 2, "delvipa4");
- memcpy(&ipaddr->u.a4.addr, addr, 4);
- ipaddr->u.a4.mask = 0;
- } else if (proto == QETH_PROT_IPV6) {
- QETH_CARD_TEXT(card, 2, "delvipa6");
- memcpy(&ipaddr->u.a6.addr, addr, 16);
- ipaddr->u.a6.pfxlen = 0;
- }
- ipaddr->type = QETH_IP_TYPE_VIPA;
- } else
- return;
- if (!qeth_l3_delete_ip(card, ipaddr))
- kfree(ipaddr);
- qeth_l3_set_ip_addr_list(card);
- }
- /*
- * proxy ARP related functions
- */
- int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
- const u8 *addr)
- {
- struct qeth_ipaddr *ipaddr;
- unsigned long flags;
- int rc = 0;
- ipaddr = qeth_l3_get_addr_buffer(proto);
- if (ipaddr) {
- if (proto == QETH_PROT_IPV4) {
- QETH_CARD_TEXT(card, 2, "addrxip4");
- memcpy(&ipaddr->u.a4.addr, addr, 4);
- ipaddr->u.a4.mask = 0;
- } else if (proto == QETH_PROT_IPV6) {
- QETH_CARD_TEXT(card, 2, "addrxip6");
- memcpy(&ipaddr->u.a6.addr, addr, 16);
- ipaddr->u.a6.pfxlen = 0;
- }
- ipaddr->type = QETH_IP_TYPE_RXIP;
- ipaddr->set_flags = QETH_IPA_SETIP_TAKEOVER_FLAG;
- ipaddr->del_flags = 0;
- } else
- return -ENOMEM;
- spin_lock_irqsave(&card->ip_lock, flags);
- if (qeth_l3_address_exists_in_list(&card->ip_list, ipaddr, 0) ||
- qeth_l3_address_exists_in_list(card->ip_tbd_list, ipaddr, 0))
- rc = -EEXIST;
- spin_unlock_irqrestore(&card->ip_lock, flags);
- if (rc) {
- return rc;
- }
- if (!qeth_l3_add_ip(card, ipaddr))
- kfree(ipaddr);
- qeth_l3_set_ip_addr_list(card);
- return 0;
- }
- void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
- const u8 *addr)
- {
- struct qeth_ipaddr *ipaddr;
- ipaddr = qeth_l3_get_addr_buffer(proto);
- if (ipaddr) {
- if (proto == QETH_PROT_IPV4) {
- QETH_CARD_TEXT(card, 2, "addrxip4");
- memcpy(&ipaddr->u.a4.addr, addr, 4);
- ipaddr->u.a4.mask = 0;
- } else if (proto == QETH_PROT_IPV6) {
- QETH_CARD_TEXT(card, 2, "addrxip6");
- memcpy(&ipaddr->u.a6.addr, addr, 16);
- ipaddr->u.a6.pfxlen = 0;
- }
- ipaddr->type = QETH_IP_TYPE_RXIP;
- } else
- return;
- if (!qeth_l3_delete_ip(card, ipaddr))
- kfree(ipaddr);
- qeth_l3_set_ip_addr_list(card);
- }
- static int qeth_l3_register_addr_entry(struct qeth_card *card,
- struct qeth_ipaddr *addr)
- {
- char buf[50];
- int rc = 0;
- int cnt = 3;
- if (addr->proto == QETH_PROT_IPV4) {
- QETH_CARD_TEXT(card, 2, "setaddr4");
- QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
- } else if (addr->proto == QETH_PROT_IPV6) {
- QETH_CARD_TEXT(card, 2, "setaddr6");
- QETH_CARD_HEX(card, 3, &addr->u.a6.addr, 8);
- QETH_CARD_HEX(card, 3, ((char *)&addr->u.a6.addr) + 8, 8);
- } else {
- QETH_CARD_TEXT(card, 2, "setaddr?");
- QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
- }
- do {
- if (addr->is_multicast)
- rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_SETIPM);
- else
- rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_SETIP,
- addr->set_flags);
- if (rc)
- QETH_CARD_TEXT(card, 2, "failed");
- } while ((--cnt > 0) && rc);
- if (rc) {
- QETH_CARD_TEXT(card, 2, "FAILED");
- qeth_l3_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
- dev_warn(&card->gdev->dev,
- "Registering IP address %s failed\n", buf);
- }
- return rc;
- }
- static int qeth_l3_deregister_addr_entry(struct qeth_card *card,
- struct qeth_ipaddr *addr)
- {
- int rc = 0;
- if (addr->proto == QETH_PROT_IPV4) {
- QETH_CARD_TEXT(card, 2, "deladdr4");
- QETH_CARD_HEX(card, 3, &addr->u.a4.addr, sizeof(int));
- } else if (addr->proto == QETH_PROT_IPV6) {
- QETH_CARD_TEXT(card, 2, "deladdr6");
- QETH_CARD_HEX(card, 3, &addr->u.a6.addr, 8);
- QETH_CARD_HEX(card, 3, ((char *)&addr->u.a6.addr) + 8, 8);
- } else {
- QETH_CARD_TEXT(card, 2, "deladdr?");
- QETH_CARD_HEX(card, 3, addr, sizeof(struct qeth_ipaddr));
- }
- if (addr->is_multicast)
- rc = qeth_l3_send_setdelmc(card, addr, IPA_CMD_DELIPM);
- else
- rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP,
- addr->del_flags);
- if (rc)
- QETH_CARD_TEXT(card, 2, "failed");
- return rc;
- }
- static inline 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 inline 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_send_setadp_mode(struct qeth_card *card, __u32 command,
- __u32 mode)
- {
- int rc;
- struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- QETH_CARD_TEXT(card, 4, "adpmode");
- iob = qeth_get_adapter_cmd(card, command,
- sizeof(struct qeth_ipacmd_setadpparms));
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- cmd->data.setadapterparms.data.mode = mode;
- rc = qeth_send_ipa_cmd(card, iob, qeth_default_setadapterparms_cb,
- NULL);
- return rc;
- }
- static int qeth_l3_setadapter_hstr(struct qeth_card *card)
- {
- int rc;
- QETH_CARD_TEXT(card, 4, "adphstr");
- if (qeth_adp_supported(card, IPA_SETADP_SET_BROADCAST_MODE)) {
- rc = qeth_l3_send_setadp_mode(card,
- IPA_SETADP_SET_BROADCAST_MODE,
- card->options.broadcast_mode);
- if (rc)
- QETH_DBF_MESSAGE(2, "couldn't set broadcast mode on "
- "device %s: x%x\n",
- CARD_BUS_ID(card), rc);
- rc = qeth_l3_send_setadp_mode(card,
- IPA_SETADP_ALTER_MAC_ADDRESS,
- card->options.macaddr_mode);
- if (rc)
- QETH_DBF_MESSAGE(2, "couldn't set macaddr mode on "
- "device %s: x%x\n", CARD_BUS_ID(card), rc);
- return rc;
- }
- if (card->options.broadcast_mode == QETH_TR_BROADCAST_LOCAL)
- QETH_DBF_MESSAGE(2, "set adapter parameters not available "
- "to set broadcast mode, using ALLRINGS "
- "on device %s:\n", CARD_BUS_ID(card));
- if (card->options.macaddr_mode == QETH_TR_MACADDR_CANONICAL)
- QETH_DBF_MESSAGE(2, "set adapter parameters not available "
- "to set macaddr mode, using NONCANONICAL "
- "on device %s:\n", CARD_BUS_ID(card));
- return 0;
- }
- static int qeth_l3_setadapter_parms(struct qeth_card *card)
- {
- int rc;
- QETH_DBF_TEXT(SETUP, 2, "setadprm");
- if (!qeth_is_supported(card, IPA_SETADAPTERPARMS)) {
- dev_info(&card->gdev->dev,
- "set adapter parameters not supported.\n");
- QETH_DBF_TEXT(SETUP, 2, " notsupp");
- return 0;
- }
- rc = qeth_query_setadapterparms(card);
- if (rc) {
- QETH_DBF_MESSAGE(2, "%s couldn't set adapter parameters: "
- "0x%x\n", dev_name(&card->gdev->dev), rc);
- return rc;
- }
- if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) {
- rc = qeth_setadpparms_change_macaddr(card);
- if (rc)
- dev_warn(&card->gdev->dev, "Reading the adapter MAC"
- " address failed\n");
- }
- if ((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
- (card->info.link_type == QETH_LINK_TYPE_LANE_TR))
- rc = qeth_l3_setadapter_hstr(card);
- return rc;
- }
- static int qeth_l3_default_setassparms_cb(struct qeth_card *card,
- struct qeth_reply *reply, unsigned long data)
- {
- struct qeth_ipa_cmd *cmd;
- QETH_CARD_TEXT(card, 4, "defadpcb");
- cmd = (struct qeth_ipa_cmd *) data;
- if (cmd->hdr.return_code == 0) {
- cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
- if (cmd->hdr.prot_version == QETH_PROT_IPV4)
- card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled;
- if (cmd->hdr.prot_version == QETH_PROT_IPV6)
- card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
- }
- if (cmd->data.setassparms.hdr.assist_no == IPA_INBOUND_CHECKSUM &&
- cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
- card->info.csum_mask = cmd->data.setassparms.data.flags_32bit;
- QETH_CARD_TEXT_(card, 3, "csum:%d", card->info.csum_mask);
- }
- if (cmd->data.setassparms.hdr.assist_no == IPA_OUTBOUND_CHECKSUM &&
- cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
- card->info.tx_csum_mask =
- cmd->data.setassparms.data.flags_32bit;
- QETH_CARD_TEXT_(card, 3, "tcsu:%d", card->info.tx_csum_mask);
- }
- return 0;
- }
- static struct qeth_cmd_buffer *qeth_l3_get_setassparms_cmd(
- struct qeth_card *card, enum qeth_ipa_funcs ipa_func, __u16 cmd_code,
- __u16 len, enum qeth_prot_versions prot)
- {
- struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- QETH_CARD_TEXT(card, 4, "getasscm");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, prot);
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- cmd->data.setassparms.hdr.assist_no = ipa_func;
- cmd->data.setassparms.hdr.length = 8 + len;
- cmd->data.setassparms.hdr.command_code = cmd_code;
- cmd->data.setassparms.hdr.return_code = 0;
- cmd->data.setassparms.hdr.seq_no = 0;
- return iob;
- }
- static int qeth_l3_send_setassparms(struct qeth_card *card,
- struct qeth_cmd_buffer *iob, __u16 len, long data,
- int (*reply_cb)(struct qeth_card *, struct qeth_reply *,
- unsigned long),
- void *reply_param)
- {
- int rc;
- struct qeth_ipa_cmd *cmd;
- QETH_CARD_TEXT(card, 4, "sendassp");
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- if (len <= sizeof(__u32))
- cmd->data.setassparms.data.flags_32bit = (__u32) data;
- else /* (len > sizeof(__u32)) */
- memcpy(&cmd->data.setassparms.data, (void *) data, len);
- rc = qeth_send_ipa_cmd(card, iob, reply_cb, reply_param);
- return rc;
- }
- #ifdef CONFIG_QETH_IPV6
- static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card,
- enum qeth_ipa_funcs ipa_func, __u16 cmd_code)
- {
- int rc;
- struct qeth_cmd_buffer *iob;
- QETH_CARD_TEXT(card, 4, "simassp6");
- iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code,
- 0, QETH_PROT_IPV6);
- rc = qeth_l3_send_setassparms(card, iob, 0, 0,
- qeth_l3_default_setassparms_cb, NULL);
- return rc;
- }
- #endif
- static int qeth_l3_send_simple_setassparms(struct qeth_card *card,
- enum qeth_ipa_funcs ipa_func, __u16 cmd_code, long data)
- {
- int rc;
- int length = 0;
- struct qeth_cmd_buffer *iob;
- QETH_CARD_TEXT(card, 4, "simassp4");
- if (data)
- length = sizeof(__u32);
- iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code,
- length, QETH_PROT_IPV4);
- rc = qeth_l3_send_setassparms(card, iob, length, data,
- qeth_l3_default_setassparms_cb, NULL);
- return rc;
- }
- static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card)
- {
- int rc;
- QETH_CARD_TEXT(card, 3, "ipaarp");
- if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
- dev_info(&card->gdev->dev,
- "ARP processing not supported on %s!\n",
- QETH_CARD_IFNAME(card));
- return 0;
- }
- rc = qeth_l3_send_simple_setassparms(card, IPA_ARP_PROCESSING,
- IPA_CMD_ASS_START, 0);
- if (rc) {
- dev_warn(&card->gdev->dev,
- "Starting ARP processing support for %s failed\n",
- QETH_CARD_IFNAME(card));
- }
- return rc;
- }
- static int qeth_l3_start_ipa_ip_fragmentation(struct qeth_card *card)
- {
- int rc;
- QETH_CARD_TEXT(card, 3, "ipaipfrg");
- if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) {
- dev_info(&card->gdev->dev,
- "Hardware IP fragmentation not supported on %s\n",
- QETH_CARD_IFNAME(card));
- return -EOPNOTSUPP;
- }
- rc = qeth_l3_send_simple_setassparms(card, IPA_IP_FRAGMENTATION,
- IPA_CMD_ASS_START, 0);
- if (rc) {
- dev_warn(&card->gdev->dev,
- "Starting IP fragmentation support for %s failed\n",
- QETH_CARD_IFNAME(card));
- } else
- dev_info(&card->gdev->dev,
- "Hardware IP fragmentation enabled \n");
- return rc;
- }
- static int qeth_l3_start_ipa_source_mac(struct qeth_card *card)
- {
- int rc;
- QETH_CARD_TEXT(card, 3, "stsrcmac");
- if (!qeth_is_supported(card, IPA_SOURCE_MAC)) {
- dev_info(&card->gdev->dev,
- "Inbound source MAC-address not supported on %s\n",
- QETH_CARD_IFNAME(card));
- return -EOPNOTSUPP;
- }
- rc = qeth_l3_send_simple_setassparms(card, IPA_SOURCE_MAC,
- IPA_CMD_ASS_START, 0);
- if (rc)
- dev_warn(&card->gdev->dev,
- "Starting source MAC-address support for %s failed\n",
- QETH_CARD_IFNAME(card));
- return rc;
- }
- static int qeth_l3_start_ipa_vlan(struct qeth_card *card)
- {
- int rc = 0;
- QETH_CARD_TEXT(card, 3, "strtvlan");
- if (!qeth_is_supported(card, IPA_FULL_VLAN)) {
- dev_info(&card->gdev->dev,
- "VLAN not supported on %s\n", QETH_CARD_IFNAME(card));
- return -EOPNOTSUPP;
- }
- rc = qeth_l3_send_simple_setassparms(card, IPA_VLAN_PRIO,
- IPA_CMD_ASS_START, 0);
- if (rc) {
- dev_warn(&card->gdev->dev,
- "Starting VLAN support for %s failed\n",
- QETH_CARD_IFNAME(card));
- } else {
- dev_info(&card->gdev->dev, "VLAN enabled\n");
- }
- return rc;
- }
- static int qeth_l3_start_ipa_multicast(struct qeth_card *card)
- {
- int rc;
- QETH_CARD_TEXT(card, 3, "stmcast");
- if (!qeth_is_supported(card, IPA_MULTICASTING)) {
- dev_info(&card->gdev->dev,
- "Multicast not supported on %s\n",
- QETH_CARD_IFNAME(card));
- return -EOPNOTSUPP;
- }
- rc = qeth_l3_send_simple_setassparms(card, IPA_MULTICASTING,
- IPA_CMD_ASS_START, 0);
- if (rc) {
- dev_warn(&card->gdev->dev,
- "Starting multicast support for %s failed\n",
- QETH_CARD_IFNAME(card));
- } else {
- dev_info(&card->gdev->dev, "Multicast enabled\n");
- card->dev->flags |= IFF_MULTICAST;
- }
- return rc;
- }
- #ifdef CONFIG_QETH_IPV6
- static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
- {
- int rc;
- QETH_CARD_TEXT(card, 3, "softipv6");
- if (card->info.type == QETH_CARD_TYPE_IQD)
- goto out;
- rc = qeth_query_ipassists(card, QETH_PROT_IPV6);
- if (rc) {
- dev_err(&card->gdev->dev,
- "Activating IPv6 support for %s failed\n",
- QETH_CARD_IFNAME(card));
- return rc;
- }
- rc = qeth_l3_send_simple_setassparms(card, IPA_IPV6,
- IPA_CMD_ASS_START, 3);
- if (rc) {
- dev_err(&card->gdev->dev,
- "Activating IPv6 support for %s failed\n",
- QETH_CARD_IFNAME(card));
- return rc;
- }
- rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_IPV6,
- IPA_CMD_ASS_START);
- if (rc) {
- dev_err(&card->gdev->dev,
- "Activating IPv6 support for %s failed\n",
- QETH_CARD_IFNAME(card));
- return rc;
- }
- rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_PASSTHRU,
- IPA_CMD_ASS_START);
- if (rc) {
- dev_warn(&card->gdev->dev,
- "Enabling the passthrough mode for %s failed\n",
- QETH_CARD_IFNAME(card));
- return rc;
- }
- out:
- dev_info(&card->gdev->dev, "IPV6 enabled\n");
- return 0;
- }
- #endif
- static int qeth_l3_start_ipa_ipv6(struct qeth_card *card)
- {
- int rc = 0;
- QETH_CARD_TEXT(card, 3, "strtipv6");
- if (!qeth_is_supported(card, IPA_IPV6)) {
- dev_info(&card->gdev->dev,
- "IPv6 not supported on %s\n", QETH_CARD_IFNAME(card));
- return 0;
- }
- #ifdef CONFIG_QETH_IPV6
- rc = qeth_l3_softsetup_ipv6(card);
- #endif
- return rc ;
- }
- static int qeth_l3_start_ipa_broadcast(struct qeth_card *card)
- {
- int rc;
- QETH_CARD_TEXT(card, 3, "stbrdcst");
- card->info.broadcast_capable = 0;
- if (!qeth_is_supported(card, IPA_FILTERING)) {
- dev_info(&card->gdev->dev,
- "Broadcast not supported on %s\n",
- QETH_CARD_IFNAME(card));
- rc = -EOPNOTSUPP;
- goto out;
- }
- rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING,
- IPA_CMD_ASS_START, 0);
- if (rc) {
- dev_warn(&card->gdev->dev, "Enabling broadcast filtering for "
- "%s failed\n", QETH_CARD_IFNAME(card));
- goto out;
- }
- rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING,
- IPA_CMD_ASS_CONFIGURE, 1);
- if (rc) {
- dev_warn(&card->gdev->dev,
- "Setting up broadcast filtering for %s failed\n",
- QETH_CARD_IFNAME(card));
- goto out;
- }
- card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO;
- dev_info(&card->gdev->dev, "Broadcast enabled\n");
- rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING,
- IPA_CMD_ASS_ENABLE, 1);
- if (rc) {
- dev_warn(&card->gdev->dev, "Setting up broadcast echo "
- "filtering for %s failed\n", QETH_CARD_IFNAME(card));
- goto out;
- }
- card->info.broadcast_capable = QETH_BROADCAST_WITHOUT_ECHO;
- out:
- if (card->info.broadcast_capable)
- card->dev->flags |= IFF_BROADCAST;
- else
- card->dev->flags &= ~IFF_BROADCAST;
- return rc;
- }
- static int qeth_l3_send_checksum_command(struct qeth_card *card)
- {
- int rc;
- rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
- IPA_CMD_ASS_START, 0);
- if (rc) {
- dev_warn(&card->gdev->dev, "Starting HW checksumming for %s "
- "failed, using SW checksumming\n",
- QETH_CARD_IFNAME(card));
- return rc;
- }
- rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
- IPA_CMD_ASS_ENABLE,
- card->info.csum_mask);
- if (rc) {
- dev_warn(&card->gdev->dev, "Enabling HW checksumming for %s "
- "failed, using SW checksumming\n",
- QETH_CARD_IFNAME(card));
- return rc;
- }
- return 0;
- }
- int qeth_l3_set_rx_csum(struct qeth_card *card, int on)
- {
- int rc = 0;
- if (on) {
- rc = qeth_l3_send_checksum_command(card);
- if (rc)
- return -EIO;
- dev_info(&card->gdev->dev,
- "HW Checksumming (inbound) enabled\n");
- } else {
- rc = qeth_l3_send_simple_setassparms(card,
- IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0);
- if (rc)
- return -EIO;
- }
- return 0;
- }
- static int qeth_l3_start_ipa_checksum(struct qeth_card *card)
- {
- QETH_CARD_TEXT(card, 3, "strtcsum");
- if (card->dev->features & NETIF_F_RXCSUM) {
- rtnl_lock();
- /* force set_features call */
- card->dev->features &= ~NETIF_F_RXCSUM;
- netdev_update_features(card->dev);
- rtnl_unlock();
- }
- return 0;
- }
- static int qeth_l3_start_ipa_tx_checksum(struct qeth_card *card)
- {
- int rc = 0;
- if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
- return rc;
- rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
- IPA_CMD_ASS_START, 0);
- if (rc)
- goto err_out;
- rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
- IPA_CMD_ASS_ENABLE, card->info.tx_csum_mask);
- if (rc)
- goto err_out;
- dev_info(&card->gdev->dev, "HW TX Checksumming enabled\n");
- return rc;
- err_out:
- dev_warn(&card->gdev->dev, "Enabling HW TX checksumming for %s "
- "failed, using SW TX checksumming\n", QETH_CARD_IFNAME(card));
- return rc;
- }
- static int qeth_l3_start_ipa_tso(struct qeth_card *card)
- {
- int rc;
- QETH_CARD_TEXT(card, 3, "sttso");
- if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
- dev_info(&card->gdev->dev,
- "Outbound TSO not supported on %s\n",
- QETH_CARD_IFNAME(card));
- rc = -EOPNOTSUPP;
- } else {
- rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_TSO,
- IPA_CMD_ASS_START, 0);
- if (rc)
- dev_warn(&card->gdev->dev, "Starting outbound TCP "
- "segmentation offload for %s failed\n",
- QETH_CARD_IFNAME(card));
- else
- dev_info(&card->gdev->dev,
- "Outbound TSO enabled\n");
- }
- if (rc)
- card->dev->features &= ~NETIF_F_TSO;
- return rc;
- }
- static int qeth_l3_start_ipassists(struct qeth_card *card)
- {
- QETH_CARD_TEXT(card, 3, "strtipas");
- qeth_set_access_ctrl_online(card); /* go on*/
- qeth_l3_start_ipa_arp_processing(card); /* go on*/
- qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/
- qeth_l3_start_ipa_source_mac(card); /* go on*/
- qeth_l3_start_ipa_vlan(card); /* go on*/
- qeth_l3_start_ipa_multicast(card); /* go on*/
- qeth_l3_start_ipa_ipv6(card); /* go on*/
- qeth_l3_start_ipa_broadcast(card); /* go on*/
- qeth_l3_start_ipa_checksum(card); /* go on*/
- qeth_l3_start_ipa_tx_checksum(card);
- qeth_l3_start_ipa_tso(card); /* go on*/
- return 0;
- }
- static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card,
- struct qeth_reply *reply, unsigned long data)
- {
- struct qeth_ipa_cmd *cmd;
- cmd = (struct qeth_ipa_cmd *) data;
- if (cmd->hdr.return_code == 0)
- memcpy(card->dev->dev_addr,
- cmd->data.create_destroy_addr.unique_id, ETH_ALEN);
- else
- random_ether_addr(card->dev->dev_addr);
- return 0;
- }
- static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card)
- {
- int rc = 0;
- struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(SETUP, 2, "hsrmac");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR,
- QETH_PROT_IPV6);
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) =
- card->info.unique_id;
- rc = qeth_send_ipa_cmd(card, iob, qeth_l3_iqd_read_initial_mac_cb,
- NULL);
- return rc;
- }
- static int qeth_l3_get_unique_id_cb(struct qeth_card *card,
- struct qeth_reply *reply, unsigned long data)
- {
- struct qeth_ipa_cmd *cmd;
- cmd = (struct qeth_ipa_cmd *) data;
- if (cmd->hdr.return_code == 0)
- card->info.unique_id = *((__u16 *)
- &cmd->data.create_destroy_addr.unique_id[6]);
- else {
- card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
- UNIQUE_ID_NOT_BY_CARD;
- dev_warn(&card->gdev->dev, "The network adapter failed to "
- "generate a unique ID\n");
- }
- return 0;
- }
- static int qeth_l3_get_unique_id(struct qeth_card *card)
- {
- int rc = 0;
- struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(SETUP, 2, "guniqeid");
- if (!qeth_is_supported(card, IPA_IPV6)) {
- card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
- UNIQUE_ID_NOT_BY_CARD;
- return 0;
- }
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR,
- QETH_PROT_IPV6);
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) =
- card->info.unique_id;
- rc = qeth_send_ipa_cmd(card, iob, qeth_l3_get_unique_id_cb, NULL);
- return rc;
- }
- static int
- qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
- unsigned long data)
- {
- struct qeth_ipa_cmd *cmd;
- __u16 rc;
- QETH_DBF_TEXT(SETUP, 2, "diastrcb");
- cmd = (struct qeth_ipa_cmd *)data;
- rc = cmd->hdr.return_code;
- if (rc)
- QETH_CARD_TEXT_(card, 2, "dxter%x", rc);
- switch (cmd->data.diagass.action) {
- case QETH_DIAGS_CMD_TRACE_QUERY:
- break;
- case QETH_DIAGS_CMD_TRACE_DISABLE:
- switch (rc) {
- case 0:
- case IPA_RC_INVALID_SUBCMD:
- card->info.promisc_mode = SET_PROMISC_MODE_OFF;
- dev_info(&card->gdev->dev, "The HiperSockets network "
- "traffic analyzer is deactivated\n");
- break;
- default:
- break;
- }
- break;
- case QETH_DIAGS_CMD_TRACE_ENABLE:
- switch (rc) {
- case 0:
- card->info.promisc_mode = SET_PROMISC_MODE_ON;
- dev_info(&card->gdev->dev, "The HiperSockets network "
- "traffic analyzer is activated\n");
- break;
- case IPA_RC_HARDWARE_AUTH_ERROR:
- dev_warn(&card->gdev->dev, "The device is not "
- "authorized to run as a HiperSockets network "
- "traffic analyzer\n");
- break;
- case IPA_RC_TRACE_ALREADY_ACTIVE:
- dev_warn(&card->gdev->dev, "A HiperSockets "
- "network traffic analyzer is already "
- "active in the HiperSockets LAN\n");
- break;
- default:
- break;
- }
- break;
- default:
- QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n",
- cmd->data.diagass.action, QETH_CARD_IFNAME(card));
- }
- return 0;
- }
- static int
- qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
- {
- struct qeth_cmd_buffer *iob;
- struct qeth_ipa_cmd *cmd;
- QETH_DBF_TEXT(SETUP, 2, "diagtrac");
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
- cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
- cmd->data.diagass.subcmd_len = 16;
- cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE;
- cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET;
- cmd->data.diagass.action = diags_cmd;
- return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL);
- }
- static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac,
- struct net_device *dev)
- {
- if (dev->type == ARPHRD_IEEE802_TR)
- ip_tr_mc_map(ipm, mac);
- else
- ip_eth_mc_map(ipm, mac);
- }
- static void qeth_l3_add_mc(struct qeth_card *card, struct in_device *in4_dev)
- {
- struct qeth_ipaddr *ipm;
- struct ip_mc_list *im4;
- char buf[MAX_ADDR_LEN];
- QETH_CARD_TEXT(card, 4, "addmc");
- for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL;
- im4 = rcu_dereference(im4->next_rcu)) {
- qeth_l3_get_mac_for_ipm(im4->multiaddr, buf, in4_dev->dev);
- ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
- if (!ipm)
- continue;
- ipm->u.a4.addr = im4->multiaddr;
- memcpy(ipm->mac, buf, OSA_ADDR_LEN);
- ipm->is_multicast = 1;
- if (!qeth_l3_add_ip(card, ipm))
- kfree(ipm);
- }
- }
- static void qeth_l3_add_vlan_mc(struct qeth_card *card)
- {
- struct in_device *in_dev;
- struct vlan_group *vg;
- int i;
- QETH_CARD_TEXT(card, 4, "addmcvl");
- if (!qeth_is_supported(card, IPA_FULL_VLAN) || (card->vlangrp == NULL))
- return;
- vg = card->vlangrp;
- for (i = 0; i < VLAN_N_VID; i++) {
- struct net_device *netdev = vlan_group_get_device(vg, i);
- if (netdev == NULL ||
- !(netdev->flags & IFF_UP))
- continue;
- in_dev = in_dev_get(netdev);
- if (!in_dev)
- continue;
- rcu_read_lock();
- qeth_l3_add_mc(card, in_dev);
- rcu_read_unlock();
- in_dev_put(in_dev);
- }
- }
- static void qeth_l3_add_multicast_ipv4(struct qeth_card *card)
- {
- struct in_device *in4_dev;
- QETH_CARD_TEXT(card, 4, "chkmcv4");
- in4_dev = in_dev_get(card->dev);
- if (in4_dev == NULL)
- return;
- rcu_read_lock();
- qeth_l3_add_mc(card, in4_dev);
- qeth_l3_add_vlan_mc(card);
- rcu_read_unlock();
- in_dev_put(in4_dev);
- }
- #ifdef CONFIG_QETH_IPV6
- static void qeth_l3_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
- {
- struct qeth_ipaddr *ipm;
- struct ifmcaddr6 *im6;
- char buf[MAX_ADDR_LEN];
- QETH_CARD_TEXT(card, 4, "addmc6");
- for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
- ndisc_mc_map(&im6->mca_addr, buf, in6_dev->dev, 0);
- ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
- if (!ipm)
- continue;
- ipm->is_multicast = 1;
- memcpy(ipm->mac, buf, OSA_ADDR_LEN);
- memcpy(&ipm->u.a6.addr, &im6->mca_addr.s6_addr,
- sizeof(struct in6_addr));
- if (!qeth_l3_add_ip(card, ipm))
- kfree(ipm);
- }
- }
- static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
- {
- struct inet6_dev *in_dev;
- struct vlan_group *vg;
- int i;
- QETH_CARD_TEXT(card, 4, "admc6vl");
- if (!qeth_is_supported(card, IPA_FULL_VLAN) || (card->vlangrp == NULL))
- return;
- vg = card->vlangrp;
- for (i = 0; i < VLAN_N_VID; i++) {
- struct net_device *netdev = vlan_group_get_device(vg, i);
- if (netdev == NULL ||
- !(netdev->flags & IFF_UP))
- continue;
- in_dev = in6_dev_get(netdev);
- if (!in_dev)
- continue;
- read_lock_bh(&in_dev->lock);
- qeth_l3_add_mc6(card, in_dev);
- read_unlock_bh(&in_dev->lock);
- in6_dev_put(in_dev);
- }
- }
- static void qeth_l3_add_multicast_ipv6(struct qeth_card *card)
- {
- struct inet6_dev *in6_dev;
- QETH_CARD_TEXT(card, 4, "chkmcv6");
- if (!qeth_is_supported(card, IPA_IPV6))
- return ;
- in6_dev = in6_dev_get(card->dev);
- if (in6_dev == NULL)
- return;
- read_lock_bh(&in6_dev->lock);
- qeth_l3_add_mc6(card, in6_dev);
- qeth_l3_add_vlan_mc6(card);
- read_unlock_bh(&in6_dev->lock);
- in6_dev_put(in6_dev);
- }
- #endif /* CONFIG_QETH_IPV6 */
- static void qeth_l3_free_vlan_addresses4(struct qeth_card *card,
- unsigned short vid)
- {
- struct in_device *in_dev;
- struct in_ifaddr *ifa;
- struct qeth_ipaddr *addr;
- QETH_CARD_TEXT(card, 4, "frvaddr4");
- in_dev = in_dev_get(vlan_group_get_device(card->vlangrp, vid));
- if (!in_dev)
- return;
- for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
- addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
- if (addr) {
- addr->u.a4.addr = ifa->ifa_address;
- addr->u.a4.mask = ifa->ifa_mask;
- addr->type = QETH_IP_TYPE_NORMAL;
- if (!qeth_l3_delete_ip(card, addr))
- kfree(addr);
- }
- }
- in_dev_put(in_dev);
- }
- static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
- unsigned short vid)
- {
- #ifdef CONFIG_QETH_IPV6
- struct inet6_dev *in6_dev;
- struct inet6_ifaddr *ifa;
- struct qeth_ipaddr *addr;
- QETH_CARD_TEXT(card, 4, "frvaddr6");
- in6_dev = in6_dev_get(vlan_group_get_device(card->vlangrp, vid));
- if (!in6_dev)
- return;
- list_for_each_entry(ifa, &in6_dev->addr_list, if_list) {
- addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
- if (addr) {
- memcpy(&addr->u.a6.addr, &ifa->addr,
- sizeof(struct in6_addr));
- addr->u.a6.pfxlen = ifa->prefix_len;
- addr->type = QETH_IP_TYPE_NORMAL;
- if (!qeth_l3_delete_ip(card, addr))
- kfree(addr);
- }
- }
- in6_dev_put(in6_dev);
- #endif /* CONFIG_QETH_IPV6 */
- }
- static void qeth_l3_free_vlan_addresses(struct qeth_card *card,
- unsigned short vid)
- {
- if (!card->vlangrp)
- return;
- qeth_l3_free_vlan_addresses4(card, vid);
- qeth_l3_free_vlan_addresses6(card, vid);
- }
- static void qeth_l3_vlan_rx_register(struct net_device *dev,
- struct vlan_group *grp)
- {
- struct qeth_card *card = dev->ml_priv;
- unsigned long flags;
- QETH_CARD_TEXT(card, 4, "vlanreg");
- spin_lock_irqsave(&card->vlanlock, flags);
- card->vlangrp = grp;
- spin_unlock_irqrestore(&card->vlanlock, flags);
- }
- static void qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
- {
- return;
- }
- static void qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
- {
- struct qeth_card *card = dev->ml_priv;
- unsigned long flags;
- QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
- if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
- QETH_CARD_TEXT(card, 3, "kidREC");
- return;
- }
- spin_lock_irqsave(&card->vlanlock, flags);
- /* unregister IP addresses of vlan device */
- qeth_l3_free_vlan_addresses(card, vid);
- vlan_group_set_device(card->vlangrp, vid, NULL);
- spin_unlock_irqrestore(&card->vlanlock, flags);
- qeth_l3_set_multicast_list(card->dev);
- }
- static inline int qeth_l3_rebuild_skb(struct qeth_card *card,
- struct sk_buff *skb, struct qeth_hdr *hdr,
- unsigned short *vlan_id)
- {
- __be16 prot;
- str…