mirror of
https://github.com/torvalds/linux.git
synced 2026-04-29 20:12:38 -04:00
This was done entirely with mindless brute force, using
git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'
to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.
Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.
For the same reason the 'flex' versions will be done as a separate
conversion.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
788 lines
20 KiB
C
788 lines
20 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright IBM Corp. 2007
|
|
* 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>
|
|
*/
|
|
|
|
#include <linux/slab.h>
|
|
#include <asm/ebcdic.h>
|
|
#include <linux/hashtable.h>
|
|
#include <linux/inet.h>
|
|
#include "qeth_l3.h"
|
|
|
|
#define QETH_DEVICE_ATTR(_id, _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,
|
|
struct qeth_routing_info *route, char *buf)
|
|
{
|
|
switch (route->type) {
|
|
case PRIMARY_ROUTER:
|
|
return sysfs_emit(buf, "%s\n", "primary router");
|
|
case SECONDARY_ROUTER:
|
|
return sysfs_emit(buf, "%s\n", "secondary router");
|
|
case MULTICAST_ROUTER:
|
|
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
|
|
return sysfs_emit(buf, "%s\n", "multicast router+");
|
|
else
|
|
return sysfs_emit(buf, "%s\n", "multicast router");
|
|
case PRIMARY_CONNECTOR:
|
|
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
|
|
return sysfs_emit(buf, "%s\n", "primary connector+");
|
|
else
|
|
return sysfs_emit(buf, "%s\n", "primary connector");
|
|
case SECONDARY_CONNECTOR:
|
|
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
|
|
return sysfs_emit(buf, "%s\n", "secondary connector+");
|
|
else
|
|
return sysfs_emit(buf, "%s\n", "secondary connector");
|
|
default:
|
|
return sysfs_emit(buf, "%s\n", "no");
|
|
}
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_route4_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_route_show(card, &card->options.route4, buf);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
|
|
struct qeth_routing_info *route, enum qeth_prot_versions prot,
|
|
const char *buf, size_t count)
|
|
{
|
|
enum qeth_routing_types old_route_type = route->type;
|
|
int rc = 0;
|
|
|
|
mutex_lock(&card->conf_mutex);
|
|
if (sysfs_streq(buf, "no_router")) {
|
|
route->type = NO_ROUTER;
|
|
} else if (sysfs_streq(buf, "primary_connector")) {
|
|
route->type = PRIMARY_CONNECTOR;
|
|
} else if (sysfs_streq(buf, "secondary_connector")) {
|
|
route->type = SECONDARY_CONNECTOR;
|
|
} else if (sysfs_streq(buf, "primary_router")) {
|
|
route->type = PRIMARY_ROUTER;
|
|
} else if (sysfs_streq(buf, "secondary_router")) {
|
|
route->type = SECONDARY_ROUTER;
|
|
} else if (sysfs_streq(buf, "multicast_router")) {
|
|
route->type = MULTICAST_ROUTER;
|
|
} else {
|
|
rc = -EINVAL;
|
|
goto out;
|
|
}
|
|
if (qeth_card_hw_is_reachable(card) &&
|
|
(old_route_type != route->type)) {
|
|
if (prot == QETH_PROT_IPV4)
|
|
rc = qeth_l3_setrouting_v4(card);
|
|
else if (prot == QETH_PROT_IPV6)
|
|
rc = qeth_l3_setrouting_v6(card);
|
|
}
|
|
out:
|
|
if (rc)
|
|
route->type = old_route_type;
|
|
mutex_unlock(&card->conf_mutex);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_route4_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_route_store(card, &card->options.route4,
|
|
QETH_PROT_IPV4, buf, count);
|
|
}
|
|
|
|
static DEVICE_ATTR(route4, 0644, qeth_l3_dev_route4_show,
|
|
qeth_l3_dev_route4_store);
|
|
|
|
static ssize_t qeth_l3_dev_route6_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_route_show(card, &card->options.route6, buf);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_route6_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_route_store(card, &card->options.route6,
|
|
QETH_PROT_IPV6, buf, count);
|
|
}
|
|
|
|
static DEVICE_ATTR(route6, 0644, qeth_l3_dev_route6_show,
|
|
qeth_l3_dev_route6_store);
|
|
|
|
static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return sysfs_emit(buf, "%i\n", card->options.sniffer ? 1 : 0);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
int rc = 0;
|
|
unsigned long i;
|
|
|
|
if (!IS_IQD(card))
|
|
return -EPERM;
|
|
if (card->options.cq == QETH_CQ_ENABLED)
|
|
return -EPERM;
|
|
|
|
mutex_lock(&card->conf_mutex);
|
|
if (card->state != CARD_STATE_DOWN) {
|
|
rc = -EPERM;
|
|
goto out;
|
|
}
|
|
|
|
rc = kstrtoul(buf, 16, &i);
|
|
if (rc) {
|
|
rc = -EINVAL;
|
|
goto out;
|
|
}
|
|
switch (i) {
|
|
case 0:
|
|
card->options.sniffer = i;
|
|
break;
|
|
case 1:
|
|
qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
|
|
if (card->ssqd.qdioac2 & CHSC_AC2_SNIFFER_AVAILABLE) {
|
|
card->options.sniffer = i;
|
|
qeth_resize_buffer_pool(card, QETH_IN_BUF_COUNT_MAX);
|
|
} else {
|
|
rc = -EPERM;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
rc = -EINVAL;
|
|
}
|
|
out:
|
|
mutex_unlock(&card->conf_mutex);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
|
|
qeth_l3_dev_sniffer_store);
|
|
|
|
static ssize_t qeth_l3_dev_hsuid_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
char tmp_hsuid[9];
|
|
|
|
if (!IS_IQD(card))
|
|
return -EPERM;
|
|
|
|
memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid));
|
|
EBCASC(tmp_hsuid, 8);
|
|
return sysfs_emit(buf, "%s\n", tmp_hsuid);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
int rc = 0;
|
|
char *tmp;
|
|
|
|
if (!IS_IQD(card))
|
|
return -EPERM;
|
|
|
|
mutex_lock(&card->conf_mutex);
|
|
if (card->state != CARD_STATE_DOWN) {
|
|
rc = -EPERM;
|
|
goto out;
|
|
}
|
|
|
|
if (card->options.sniffer) {
|
|
rc = -EPERM;
|
|
goto out;
|
|
}
|
|
|
|
if (card->options.cq == QETH_CQ_NOTAVAILABLE) {
|
|
rc = -EPERM;
|
|
goto out;
|
|
}
|
|
|
|
tmp = strsep((char **)&buf, "\n");
|
|
if (strlen(tmp) > 8) {
|
|
rc = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
if (card->options.hsuid[0])
|
|
/* delete old ip address */
|
|
qeth_l3_modify_hsuid(card, false);
|
|
|
|
if (strlen(tmp) == 0) {
|
|
/* delete ip address only */
|
|
card->options.hsuid[0] = '\0';
|
|
memcpy(card->dev->perm_addr, card->options.hsuid, 9);
|
|
qeth_configure_cq(card, QETH_CQ_DISABLED);
|
|
goto out;
|
|
}
|
|
|
|
if (qeth_configure_cq(card, QETH_CQ_ENABLED)) {
|
|
rc = -EPERM;
|
|
goto out;
|
|
}
|
|
|
|
scnprintf(card->options.hsuid, sizeof(card->options.hsuid),
|
|
"%-8s", tmp);
|
|
ASCEBC(card->options.hsuid, 8);
|
|
memcpy(card->dev->perm_addr, card->options.hsuid, 9);
|
|
|
|
rc = qeth_l3_modify_hsuid(card, true);
|
|
|
|
out:
|
|
mutex_unlock(&card->conf_mutex);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show,
|
|
qeth_l3_dev_hsuid_store);
|
|
|
|
|
|
static struct attribute *qeth_l3_device_attrs[] = {
|
|
&dev_attr_route4.attr,
|
|
&dev_attr_route6.attr,
|
|
&dev_attr_sniffer.attr,
|
|
&dev_attr_hsuid.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group qeth_l3_device_attr_group = {
|
|
.attrs = qeth_l3_device_attrs,
|
|
};
|
|
|
|
static ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return sysfs_emit(buf, "%u\n", card->ipato.enabled ? 1 : 0);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
bool enable;
|
|
int rc = 0;
|
|
|
|
mutex_lock(&card->conf_mutex);
|
|
if (card->state != CARD_STATE_DOWN) {
|
|
rc = -EPERM;
|
|
goto out;
|
|
}
|
|
|
|
mutex_lock(&card->ip_lock);
|
|
if (sysfs_streq(buf, "toggle")) {
|
|
enable = !card->ipato.enabled;
|
|
} else if (kstrtobool(buf, &enable)) {
|
|
rc = -EINVAL;
|
|
goto unlock_ip;
|
|
}
|
|
|
|
if (card->ipato.enabled != enable) {
|
|
card->ipato.enabled = enable;
|
|
qeth_l3_update_ipato(card);
|
|
}
|
|
|
|
unlock_ip:
|
|
mutex_unlock(&card->ip_lock);
|
|
out:
|
|
mutex_unlock(&card->conf_mutex);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(ipato_enable, enable, 0644,
|
|
qeth_l3_dev_ipato_enable_show,
|
|
qeth_l3_dev_ipato_enable_store);
|
|
|
|
static ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return sysfs_emit(buf, "%u\n", card->ipato.invert4 ? 1 : 0);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
bool invert;
|
|
int rc = 0;
|
|
|
|
mutex_lock(&card->ip_lock);
|
|
if (sysfs_streq(buf, "toggle")) {
|
|
invert = !card->ipato.invert4;
|
|
} else if (kstrtobool(buf, &invert)) {
|
|
rc = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
if (card->ipato.invert4 != invert) {
|
|
card->ipato.invert4 = invert;
|
|
qeth_l3_update_ipato(card);
|
|
}
|
|
|
|
out:
|
|
mutex_unlock(&card->ip_lock);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
|
|
qeth_l3_dev_ipato_invert4_show,
|
|
qeth_l3_dev_ipato_invert4_store);
|
|
|
|
static ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card,
|
|
enum qeth_prot_versions proto)
|
|
{
|
|
struct qeth_ipato_entry *ipatoe;
|
|
char addr_str[INET6_ADDRSTRLEN];
|
|
int offset = 0;
|
|
|
|
mutex_lock(&card->ip_lock);
|
|
list_for_each_entry(ipatoe, &card->ipato.entries, entry) {
|
|
if (ipatoe->proto != proto)
|
|
continue;
|
|
|
|
qeth_l3_ipaddr_to_string(proto, ipatoe->addr, addr_str);
|
|
offset += sysfs_emit_at(buf, offset, "%s/%i\n",
|
|
addr_str, ipatoe->mask_bits);
|
|
}
|
|
mutex_unlock(&card->ip_lock);
|
|
|
|
return offset ? offset : sysfs_emit(buf, "\n");
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
|
|
}
|
|
|
|
static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto,
|
|
u8 *addr, unsigned int *mask_bits)
|
|
{
|
|
char *sep;
|
|
int rc;
|
|
|
|
/* Expected input pattern: %addr/%mask */
|
|
sep = strnchr(buf, INET6_ADDRSTRLEN, '/');
|
|
if (!sep)
|
|
return -EINVAL;
|
|
|
|
/* Terminate the %addr sub-string, and parse it: */
|
|
*sep = '\0';
|
|
rc = qeth_l3_string_to_ipaddr(buf, proto, addr);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = kstrtouint(sep + 1, 10, mask_bits);
|
|
if (rc)
|
|
return rc;
|
|
|
|
if (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count,
|
|
struct qeth_card *card, enum qeth_prot_versions proto)
|
|
{
|
|
struct qeth_ipato_entry *ipatoe;
|
|
unsigned int mask_bits;
|
|
u8 addr[16];
|
|
int rc = 0;
|
|
|
|
rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
|
|
if (rc)
|
|
return rc;
|
|
|
|
ipatoe = kzalloc_obj(struct qeth_ipato_entry);
|
|
if (!ipatoe)
|
|
return -ENOMEM;
|
|
|
|
ipatoe->proto = proto;
|
|
memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4) ? 4 : 16);
|
|
ipatoe->mask_bits = mask_bits;
|
|
|
|
rc = qeth_l3_add_ipato_entry(card, ipatoe);
|
|
if (rc)
|
|
kfree(ipatoe);
|
|
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV4);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
|
|
qeth_l3_dev_ipato_add4_show,
|
|
qeth_l3_dev_ipato_add4_store);
|
|
|
|
static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count,
|
|
struct qeth_card *card, enum qeth_prot_versions proto)
|
|
{
|
|
unsigned int mask_bits;
|
|
u8 addr[16];
|
|
int rc = 0;
|
|
|
|
rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
|
|
if (!rc)
|
|
rc = qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL,
|
|
qeth_l3_dev_ipato_del4_store);
|
|
|
|
static ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return sysfs_emit(buf, "%u\n", card->ipato.invert6 ? 1 : 0);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
bool invert;
|
|
int rc = 0;
|
|
|
|
mutex_lock(&card->ip_lock);
|
|
if (sysfs_streq(buf, "toggle")) {
|
|
invert = !card->ipato.invert6;
|
|
} else if (kstrtobool(buf, &invert)) {
|
|
rc = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
if (card->ipato.invert6 != invert) {
|
|
card->ipato.invert6 = invert;
|
|
qeth_l3_update_ipato(card);
|
|
}
|
|
|
|
out:
|
|
mutex_unlock(&card->ip_lock);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644,
|
|
qeth_l3_dev_ipato_invert6_show,
|
|
qeth_l3_dev_ipato_invert6_store);
|
|
|
|
|
|
static ssize_t qeth_l3_dev_ipato_add6_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV6);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_ipato_add6_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(ipato_add6, add6, 0644,
|
|
qeth_l3_dev_ipato_add6_show,
|
|
qeth_l3_dev_ipato_add6_store);
|
|
|
|
static ssize_t qeth_l3_dev_ipato_del6_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
|
|
return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(ipato_del6, del6, 0200, NULL,
|
|
qeth_l3_dev_ipato_del6_store);
|
|
|
|
static struct attribute *qeth_ipato_device_attrs[] = {
|
|
&dev_attr_ipato_enable.attr,
|
|
&dev_attr_ipato_invert4.attr,
|
|
&dev_attr_ipato_add4.attr,
|
|
&dev_attr_ipato_del4.attr,
|
|
&dev_attr_ipato_invert6.attr,
|
|
&dev_attr_ipato_add6.attr,
|
|
&dev_attr_ipato_del6.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group qeth_device_ipato_group = {
|
|
.name = "ipa_takeover",
|
|
.attrs = qeth_ipato_device_attrs,
|
|
};
|
|
|
|
static ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf,
|
|
enum qeth_prot_versions proto,
|
|
enum qeth_ip_types type)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
char addr_str[INET6_ADDRSTRLEN];
|
|
struct qeth_ipaddr *ipaddr;
|
|
int offset = 0;
|
|
int i;
|
|
|
|
mutex_lock(&card->ip_lock);
|
|
hash_for_each(card->ip_htable, i, ipaddr, hnode) {
|
|
if (ipaddr->proto != proto || ipaddr->type != type)
|
|
continue;
|
|
|
|
qeth_l3_ipaddr_to_string(proto, (u8 *)&ipaddr->u, addr_str);
|
|
offset += sysfs_emit_at(buf, offset, "%s\n", addr_str);
|
|
}
|
|
mutex_unlock(&card->ip_lock);
|
|
|
|
return offset ? offset : sysfs_emit(buf, "\n");
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV4,
|
|
QETH_IP_TYPE_VIPA);
|
|
}
|
|
|
|
static ssize_t qeth_l3_vipa_store(struct device *dev, const char *buf, bool add,
|
|
size_t count, enum qeth_prot_versions proto)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
u8 addr[16] = {0, };
|
|
int rc;
|
|
|
|
rc = qeth_l3_string_to_ipaddr(buf, proto, addr);
|
|
if (!rc)
|
|
rc = qeth_l3_modify_rxip_vipa(card, add, addr,
|
|
QETH_IP_TYPE_VIPA, proto);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
return qeth_l3_vipa_store(dev, buf, true, count, QETH_PROT_IPV4);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
|
|
qeth_l3_dev_vipa_add4_show,
|
|
qeth_l3_dev_vipa_add4_store);
|
|
|
|
static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
return qeth_l3_vipa_store(dev, buf, false, count, QETH_PROT_IPV4);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL,
|
|
qeth_l3_dev_vipa_del4_store);
|
|
|
|
static ssize_t qeth_l3_dev_vipa_add6_show(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV6,
|
|
QETH_IP_TYPE_VIPA);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
return qeth_l3_vipa_store(dev, buf, true, count, QETH_PROT_IPV6);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(vipa_add6, add6, 0644,
|
|
qeth_l3_dev_vipa_add6_show,
|
|
qeth_l3_dev_vipa_add6_store);
|
|
|
|
static ssize_t qeth_l3_dev_vipa_del6_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
return qeth_l3_vipa_store(dev, buf, false, count, QETH_PROT_IPV6);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(vipa_del6, del6, 0200, NULL,
|
|
qeth_l3_dev_vipa_del6_store);
|
|
|
|
static struct attribute *qeth_vipa_device_attrs[] = {
|
|
&dev_attr_vipa_add4.attr,
|
|
&dev_attr_vipa_del4.attr,
|
|
&dev_attr_vipa_add6.attr,
|
|
&dev_attr_vipa_del6.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group qeth_device_vipa_group = {
|
|
.name = "vipa",
|
|
.attrs = qeth_vipa_device_attrs,
|
|
};
|
|
|
|
static ssize_t qeth_l3_dev_rxip_add4_show(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV4,
|
|
QETH_IP_TYPE_RXIP);
|
|
}
|
|
|
|
static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto,
|
|
u8 *addr)
|
|
{
|
|
__be32 ipv4_addr;
|
|
struct in6_addr ipv6_addr;
|
|
|
|
if (qeth_l3_string_to_ipaddr(buf, proto, addr)) {
|
|
return -EINVAL;
|
|
}
|
|
if (proto == QETH_PROT_IPV4) {
|
|
memcpy(&ipv4_addr, addr, sizeof(ipv4_addr));
|
|
if (ipv4_is_multicast(ipv4_addr)) {
|
|
QETH_DBF_MESSAGE(2, "multicast rxip not supported.\n");
|
|
return -EINVAL;
|
|
}
|
|
} else if (proto == QETH_PROT_IPV6) {
|
|
memcpy(&ipv6_addr, addr, sizeof(ipv6_addr));
|
|
if (ipv6_addr_is_multicast(&ipv6_addr)) {
|
|
QETH_DBF_MESSAGE(2, "multicast rxip not supported.\n");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t qeth_l3_rxip_store(struct device *dev, const char *buf, bool add,
|
|
size_t count, enum qeth_prot_versions proto)
|
|
{
|
|
struct qeth_card *card = dev_get_drvdata(dev);
|
|
u8 addr[16] = {0, };
|
|
int rc;
|
|
|
|
rc = qeth_l3_parse_rxipe(buf, proto, addr);
|
|
if (!rc)
|
|
rc = qeth_l3_modify_rxip_vipa(card, add, addr,
|
|
QETH_IP_TYPE_RXIP, proto);
|
|
return rc ? rc : count;
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
return qeth_l3_rxip_store(dev, buf, true, count, QETH_PROT_IPV4);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
|
|
qeth_l3_dev_rxip_add4_show,
|
|
qeth_l3_dev_rxip_add4_store);
|
|
|
|
static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
return qeth_l3_rxip_store(dev, buf, false, count, QETH_PROT_IPV4);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL,
|
|
qeth_l3_dev_rxip_del4_store);
|
|
|
|
static ssize_t qeth_l3_dev_rxip_add6_show(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV6,
|
|
QETH_IP_TYPE_RXIP);
|
|
}
|
|
|
|
static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
return qeth_l3_rxip_store(dev, buf, true, count, QETH_PROT_IPV6);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(rxip_add6, add6, 0644,
|
|
qeth_l3_dev_rxip_add6_show,
|
|
qeth_l3_dev_rxip_add6_store);
|
|
|
|
static ssize_t qeth_l3_dev_rxip_del6_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
return qeth_l3_rxip_store(dev, buf, false, count, QETH_PROT_IPV6);
|
|
}
|
|
|
|
static QETH_DEVICE_ATTR(rxip_del6, del6, 0200, NULL,
|
|
qeth_l3_dev_rxip_del6_store);
|
|
|
|
static struct attribute *qeth_rxip_device_attrs[] = {
|
|
&dev_attr_rxip_add4.attr,
|
|
&dev_attr_rxip_del4.attr,
|
|
&dev_attr_rxip_add6.attr,
|
|
&dev_attr_rxip_del6.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group qeth_device_rxip_group = {
|
|
.name = "rxip",
|
|
.attrs = qeth_rxip_device_attrs,
|
|
};
|
|
|
|
const struct attribute_group *qeth_l3_attr_groups[] = {
|
|
&qeth_l3_device_attr_group,
|
|
&qeth_device_ipato_group,
|
|
&qeth_device_vipa_group,
|
|
&qeth_device_rxip_group,
|
|
NULL,
|
|
};
|