162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright IBM Corp. 2007 462306a36Sopenharmony_ci * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, 562306a36Sopenharmony_ci * Frank Pavlic <fpavlic@de.ibm.com>, 662306a36Sopenharmony_ci * Thomas Spatzier <tspat@de.ibm.com>, 762306a36Sopenharmony_ci * Frank Blaschka <frank.blaschka@de.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <asm/ebcdic.h> 1262306a36Sopenharmony_ci#include <linux/hashtable.h> 1362306a36Sopenharmony_ci#include <linux/inet.h> 1462306a36Sopenharmony_ci#include "qeth_l3.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ 1762306a36Sopenharmony_cistruct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store) 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int qeth_l3_string_to_ipaddr(const char *buf, 2062306a36Sopenharmony_ci enum qeth_prot_versions proto, u8 *addr) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci const char *end; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if ((proto == QETH_PROT_IPV4 && !in4_pton(buf, -1, addr, -1, &end)) || 2562306a36Sopenharmony_ci (proto == QETH_PROT_IPV6 && !in6_pton(buf, -1, addr, -1, &end))) 2662306a36Sopenharmony_ci return -EINVAL; 2762306a36Sopenharmony_ci return 0; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_route_show(struct qeth_card *card, 3162306a36Sopenharmony_ci struct qeth_routing_info *route, char *buf) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci switch (route->type) { 3462306a36Sopenharmony_ci case PRIMARY_ROUTER: 3562306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", "primary router"); 3662306a36Sopenharmony_ci case SECONDARY_ROUTER: 3762306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", "secondary router"); 3862306a36Sopenharmony_ci case MULTICAST_ROUTER: 3962306a36Sopenharmony_ci if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) 4062306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", "multicast router+"); 4162306a36Sopenharmony_ci else 4262306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", "multicast router"); 4362306a36Sopenharmony_ci case PRIMARY_CONNECTOR: 4462306a36Sopenharmony_ci if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) 4562306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", "primary connector+"); 4662306a36Sopenharmony_ci else 4762306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", "primary connector"); 4862306a36Sopenharmony_ci case SECONDARY_CONNECTOR: 4962306a36Sopenharmony_ci if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) 5062306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", "secondary connector+"); 5162306a36Sopenharmony_ci else 5262306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", "secondary connector"); 5362306a36Sopenharmony_ci default: 5462306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", "no"); 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_route4_show(struct device *dev, 5962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return qeth_l3_dev_route_show(card, &card->options.route4, buf); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_route_store(struct qeth_card *card, 6762306a36Sopenharmony_ci struct qeth_routing_info *route, enum qeth_prot_versions prot, 6862306a36Sopenharmony_ci const char *buf, size_t count) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci enum qeth_routing_types old_route_type = route->type; 7162306a36Sopenharmony_ci int rc = 0; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci mutex_lock(&card->conf_mutex); 7462306a36Sopenharmony_ci if (sysfs_streq(buf, "no_router")) { 7562306a36Sopenharmony_ci route->type = NO_ROUTER; 7662306a36Sopenharmony_ci } else if (sysfs_streq(buf, "primary_connector")) { 7762306a36Sopenharmony_ci route->type = PRIMARY_CONNECTOR; 7862306a36Sopenharmony_ci } else if (sysfs_streq(buf, "secondary_connector")) { 7962306a36Sopenharmony_ci route->type = SECONDARY_CONNECTOR; 8062306a36Sopenharmony_ci } else if (sysfs_streq(buf, "primary_router")) { 8162306a36Sopenharmony_ci route->type = PRIMARY_ROUTER; 8262306a36Sopenharmony_ci } else if (sysfs_streq(buf, "secondary_router")) { 8362306a36Sopenharmony_ci route->type = SECONDARY_ROUTER; 8462306a36Sopenharmony_ci } else if (sysfs_streq(buf, "multicast_router")) { 8562306a36Sopenharmony_ci route->type = MULTICAST_ROUTER; 8662306a36Sopenharmony_ci } else { 8762306a36Sopenharmony_ci rc = -EINVAL; 8862306a36Sopenharmony_ci goto out; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci if (qeth_card_hw_is_reachable(card) && 9162306a36Sopenharmony_ci (old_route_type != route->type)) { 9262306a36Sopenharmony_ci if (prot == QETH_PROT_IPV4) 9362306a36Sopenharmony_ci rc = qeth_l3_setrouting_v4(card); 9462306a36Sopenharmony_ci else if (prot == QETH_PROT_IPV6) 9562306a36Sopenharmony_ci rc = qeth_l3_setrouting_v6(card); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ciout: 9862306a36Sopenharmony_ci if (rc) 9962306a36Sopenharmony_ci route->type = old_route_type; 10062306a36Sopenharmony_ci mutex_unlock(&card->conf_mutex); 10162306a36Sopenharmony_ci return rc ? rc : count; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_route4_store(struct device *dev, 10562306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return qeth_l3_dev_route_store(card, &card->options.route4, 11062306a36Sopenharmony_ci QETH_PROT_IPV4, buf, count); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic DEVICE_ATTR(route4, 0644, qeth_l3_dev_route4_show, 11462306a36Sopenharmony_ci qeth_l3_dev_route4_store); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_route6_show(struct device *dev, 11762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return qeth_l3_dev_route_show(card, &card->options.route6, buf); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_route6_store(struct device *dev, 12562306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return qeth_l3_dev_route_store(card, &card->options.route6, 13062306a36Sopenharmony_ci QETH_PROT_IPV6, buf, count); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic DEVICE_ATTR(route6, 0644, qeth_l3_dev_route6_show, 13462306a36Sopenharmony_ci qeth_l3_dev_route6_store); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_sniffer_show(struct device *dev, 13762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return sysfs_emit(buf, "%i\n", card->options.sniffer ? 1 : 0); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_sniffer_store(struct device *dev, 14562306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 14862306a36Sopenharmony_ci int rc = 0; 14962306a36Sopenharmony_ci unsigned long i; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (!IS_IQD(card)) 15262306a36Sopenharmony_ci return -EPERM; 15362306a36Sopenharmony_ci if (card->options.cq == QETH_CQ_ENABLED) 15462306a36Sopenharmony_ci return -EPERM; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci mutex_lock(&card->conf_mutex); 15762306a36Sopenharmony_ci if (card->state != CARD_STATE_DOWN) { 15862306a36Sopenharmony_ci rc = -EPERM; 15962306a36Sopenharmony_ci goto out; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci rc = kstrtoul(buf, 16, &i); 16362306a36Sopenharmony_ci if (rc) { 16462306a36Sopenharmony_ci rc = -EINVAL; 16562306a36Sopenharmony_ci goto out; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci switch (i) { 16862306a36Sopenharmony_ci case 0: 16962306a36Sopenharmony_ci card->options.sniffer = i; 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci case 1: 17262306a36Sopenharmony_ci qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); 17362306a36Sopenharmony_ci if (card->ssqd.qdioac2 & CHSC_AC2_SNIFFER_AVAILABLE) { 17462306a36Sopenharmony_ci card->options.sniffer = i; 17562306a36Sopenharmony_ci qeth_resize_buffer_pool(card, QETH_IN_BUF_COUNT_MAX); 17662306a36Sopenharmony_ci } else { 17762306a36Sopenharmony_ci rc = -EPERM; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci default: 18262306a36Sopenharmony_ci rc = -EINVAL; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ciout: 18562306a36Sopenharmony_ci mutex_unlock(&card->conf_mutex); 18662306a36Sopenharmony_ci return rc ? rc : count; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, 19062306a36Sopenharmony_ci qeth_l3_dev_sniffer_store); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_hsuid_show(struct device *dev, 19362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 19662306a36Sopenharmony_ci char tmp_hsuid[9]; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (!IS_IQD(card)) 19962306a36Sopenharmony_ci return -EPERM; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid)); 20262306a36Sopenharmony_ci EBCASC(tmp_hsuid, 8); 20362306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", tmp_hsuid); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_hsuid_store(struct device *dev, 20762306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 21062306a36Sopenharmony_ci int rc = 0; 21162306a36Sopenharmony_ci char *tmp; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (!IS_IQD(card)) 21462306a36Sopenharmony_ci return -EPERM; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci mutex_lock(&card->conf_mutex); 21762306a36Sopenharmony_ci if (card->state != CARD_STATE_DOWN) { 21862306a36Sopenharmony_ci rc = -EPERM; 21962306a36Sopenharmony_ci goto out; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (card->options.sniffer) { 22362306a36Sopenharmony_ci rc = -EPERM; 22462306a36Sopenharmony_ci goto out; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (card->options.cq == QETH_CQ_NOTAVAILABLE) { 22862306a36Sopenharmony_ci rc = -EPERM; 22962306a36Sopenharmony_ci goto out; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci tmp = strsep((char **)&buf, "\n"); 23362306a36Sopenharmony_ci if (strlen(tmp) > 8) { 23462306a36Sopenharmony_ci rc = -EINVAL; 23562306a36Sopenharmony_ci goto out; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (card->options.hsuid[0]) 23962306a36Sopenharmony_ci /* delete old ip address */ 24062306a36Sopenharmony_ci qeth_l3_modify_hsuid(card, false); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (strlen(tmp) == 0) { 24362306a36Sopenharmony_ci /* delete ip address only */ 24462306a36Sopenharmony_ci card->options.hsuid[0] = '\0'; 24562306a36Sopenharmony_ci memcpy(card->dev->perm_addr, card->options.hsuid, 9); 24662306a36Sopenharmony_ci qeth_configure_cq(card, QETH_CQ_DISABLED); 24762306a36Sopenharmony_ci goto out; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (qeth_configure_cq(card, QETH_CQ_ENABLED)) { 25162306a36Sopenharmony_ci rc = -EPERM; 25262306a36Sopenharmony_ci goto out; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci scnprintf(card->options.hsuid, sizeof(card->options.hsuid), 25662306a36Sopenharmony_ci "%-8s", tmp); 25762306a36Sopenharmony_ci ASCEBC(card->options.hsuid, 8); 25862306a36Sopenharmony_ci memcpy(card->dev->perm_addr, card->options.hsuid, 9); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci rc = qeth_l3_modify_hsuid(card, true); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ciout: 26362306a36Sopenharmony_ci mutex_unlock(&card->conf_mutex); 26462306a36Sopenharmony_ci return rc ? rc : count; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show, 26862306a36Sopenharmony_ci qeth_l3_dev_hsuid_store); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic struct attribute *qeth_l3_device_attrs[] = { 27262306a36Sopenharmony_ci &dev_attr_route4.attr, 27362306a36Sopenharmony_ci &dev_attr_route6.attr, 27462306a36Sopenharmony_ci &dev_attr_sniffer.attr, 27562306a36Sopenharmony_ci &dev_attr_hsuid.attr, 27662306a36Sopenharmony_ci NULL, 27762306a36Sopenharmony_ci}; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic const struct attribute_group qeth_l3_device_attr_group = { 28062306a36Sopenharmony_ci .attrs = qeth_l3_device_attrs, 28162306a36Sopenharmony_ci}; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_enable_show(struct device *dev, 28462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", card->ipato.enabled ? 1 : 0); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, 29262306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 29562306a36Sopenharmony_ci bool enable; 29662306a36Sopenharmony_ci int rc = 0; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci mutex_lock(&card->conf_mutex); 29962306a36Sopenharmony_ci if (card->state != CARD_STATE_DOWN) { 30062306a36Sopenharmony_ci rc = -EPERM; 30162306a36Sopenharmony_ci goto out; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci mutex_lock(&card->ip_lock); 30562306a36Sopenharmony_ci if (sysfs_streq(buf, "toggle")) { 30662306a36Sopenharmony_ci enable = !card->ipato.enabled; 30762306a36Sopenharmony_ci } else if (kstrtobool(buf, &enable)) { 30862306a36Sopenharmony_ci rc = -EINVAL; 30962306a36Sopenharmony_ci goto unlock_ip; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (card->ipato.enabled != enable) { 31362306a36Sopenharmony_ci card->ipato.enabled = enable; 31462306a36Sopenharmony_ci qeth_l3_update_ipato(card); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ciunlock_ip: 31862306a36Sopenharmony_ci mutex_unlock(&card->ip_lock); 31962306a36Sopenharmony_ciout: 32062306a36Sopenharmony_ci mutex_unlock(&card->conf_mutex); 32162306a36Sopenharmony_ci return rc ? rc : count; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(ipato_enable, enable, 0644, 32562306a36Sopenharmony_ci qeth_l3_dev_ipato_enable_show, 32662306a36Sopenharmony_ci qeth_l3_dev_ipato_enable_store); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_invert4_show(struct device *dev, 32962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", card->ipato.invert4 ? 1 : 0); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, 33762306a36Sopenharmony_ci struct device_attribute *attr, 33862306a36Sopenharmony_ci const char *buf, size_t count) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 34162306a36Sopenharmony_ci bool invert; 34262306a36Sopenharmony_ci int rc = 0; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci mutex_lock(&card->ip_lock); 34562306a36Sopenharmony_ci if (sysfs_streq(buf, "toggle")) { 34662306a36Sopenharmony_ci invert = !card->ipato.invert4; 34762306a36Sopenharmony_ci } else if (kstrtobool(buf, &invert)) { 34862306a36Sopenharmony_ci rc = -EINVAL; 34962306a36Sopenharmony_ci goto out; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (card->ipato.invert4 != invert) { 35362306a36Sopenharmony_ci card->ipato.invert4 = invert; 35462306a36Sopenharmony_ci qeth_l3_update_ipato(card); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ciout: 35862306a36Sopenharmony_ci mutex_unlock(&card->ip_lock); 35962306a36Sopenharmony_ci return rc ? rc : count; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644, 36362306a36Sopenharmony_ci qeth_l3_dev_ipato_invert4_show, 36462306a36Sopenharmony_ci qeth_l3_dev_ipato_invert4_store); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_add_show(char *buf, struct qeth_card *card, 36762306a36Sopenharmony_ci enum qeth_prot_versions proto) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct qeth_ipato_entry *ipatoe; 37062306a36Sopenharmony_ci char addr_str[INET6_ADDRSTRLEN]; 37162306a36Sopenharmony_ci int offset = 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci mutex_lock(&card->ip_lock); 37462306a36Sopenharmony_ci list_for_each_entry(ipatoe, &card->ipato.entries, entry) { 37562306a36Sopenharmony_ci if (ipatoe->proto != proto) 37662306a36Sopenharmony_ci continue; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci qeth_l3_ipaddr_to_string(proto, ipatoe->addr, addr_str); 37962306a36Sopenharmony_ci offset += sysfs_emit_at(buf, offset, "%s/%i\n", 38062306a36Sopenharmony_ci addr_str, ipatoe->mask_bits); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci mutex_unlock(&card->ip_lock); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci return offset ? offset : sysfs_emit(buf, "\n"); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_add4_show(struct device *dev, 38862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV4); 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto, 39662306a36Sopenharmony_ci u8 *addr, unsigned int *mask_bits) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci char *sep; 39962306a36Sopenharmony_ci int rc; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Expected input pattern: %addr/%mask */ 40262306a36Sopenharmony_ci sep = strnchr(buf, INET6_ADDRSTRLEN, '/'); 40362306a36Sopenharmony_ci if (!sep) 40462306a36Sopenharmony_ci return -EINVAL; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Terminate the %addr sub-string, and parse it: */ 40762306a36Sopenharmony_ci *sep = '\0'; 40862306a36Sopenharmony_ci rc = qeth_l3_string_to_ipaddr(buf, proto, addr); 40962306a36Sopenharmony_ci if (rc) 41062306a36Sopenharmony_ci return rc; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci rc = kstrtouint(sep + 1, 10, mask_bits); 41362306a36Sopenharmony_ci if (rc) 41462306a36Sopenharmony_ci return rc; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128)) 41762306a36Sopenharmony_ci return -EINVAL; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count, 42362306a36Sopenharmony_ci struct qeth_card *card, enum qeth_prot_versions proto) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct qeth_ipato_entry *ipatoe; 42662306a36Sopenharmony_ci unsigned int mask_bits; 42762306a36Sopenharmony_ci u8 addr[16]; 42862306a36Sopenharmony_ci int rc = 0; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits); 43162306a36Sopenharmony_ci if (rc) 43262306a36Sopenharmony_ci return rc; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ipatoe = kzalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL); 43562306a36Sopenharmony_ci if (!ipatoe) 43662306a36Sopenharmony_ci return -ENOMEM; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci ipatoe->proto = proto; 43962306a36Sopenharmony_ci memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4) ? 4 : 16); 44062306a36Sopenharmony_ci ipatoe->mask_bits = mask_bits; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci rc = qeth_l3_add_ipato_entry(card, ipatoe); 44362306a36Sopenharmony_ci if (rc) 44462306a36Sopenharmony_ci kfree(ipatoe); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return rc ? rc : count; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev, 45062306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV4); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(ipato_add4, add4, 0644, 45862306a36Sopenharmony_ci qeth_l3_dev_ipato_add4_show, 45962306a36Sopenharmony_ci qeth_l3_dev_ipato_add4_store); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count, 46262306a36Sopenharmony_ci struct qeth_card *card, enum qeth_prot_versions proto) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci unsigned int mask_bits; 46562306a36Sopenharmony_ci u8 addr[16]; 46662306a36Sopenharmony_ci int rc = 0; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits); 46962306a36Sopenharmony_ci if (!rc) 47062306a36Sopenharmony_ci rc = qeth_l3_del_ipato_entry(card, proto, addr, mask_bits); 47162306a36Sopenharmony_ci return rc ? rc : count; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev, 47562306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL, 48362306a36Sopenharmony_ci qeth_l3_dev_ipato_del4_store); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_invert6_show(struct device *dev, 48662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", card->ipato.invert6 ? 1 : 0); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, 49462306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 49762306a36Sopenharmony_ci bool invert; 49862306a36Sopenharmony_ci int rc = 0; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci mutex_lock(&card->ip_lock); 50162306a36Sopenharmony_ci if (sysfs_streq(buf, "toggle")) { 50262306a36Sopenharmony_ci invert = !card->ipato.invert6; 50362306a36Sopenharmony_ci } else if (kstrtobool(buf, &invert)) { 50462306a36Sopenharmony_ci rc = -EINVAL; 50562306a36Sopenharmony_ci goto out; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (card->ipato.invert6 != invert) { 50962306a36Sopenharmony_ci card->ipato.invert6 = invert; 51062306a36Sopenharmony_ci qeth_l3_update_ipato(card); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ciout: 51462306a36Sopenharmony_ci mutex_unlock(&card->ip_lock); 51562306a36Sopenharmony_ci return rc ? rc : count; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644, 51962306a36Sopenharmony_ci qeth_l3_dev_ipato_invert6_show, 52062306a36Sopenharmony_ci qeth_l3_dev_ipato_invert6_store); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_add6_show(struct device *dev, 52462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return qeth_l3_dev_ipato_add_show(buf, card, QETH_PROT_IPV6); 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_add6_store(struct device *dev, 53262306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return qeth_l3_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(ipato_add6, add6, 0644, 54062306a36Sopenharmony_ci qeth_l3_dev_ipato_add6_show, 54162306a36Sopenharmony_ci qeth_l3_dev_ipato_add6_store); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ipato_del6_store(struct device *dev, 54462306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return qeth_l3_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6); 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(ipato_del6, del6, 0200, NULL, 55262306a36Sopenharmony_ci qeth_l3_dev_ipato_del6_store); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic struct attribute *qeth_ipato_device_attrs[] = { 55562306a36Sopenharmony_ci &dev_attr_ipato_enable.attr, 55662306a36Sopenharmony_ci &dev_attr_ipato_invert4.attr, 55762306a36Sopenharmony_ci &dev_attr_ipato_add4.attr, 55862306a36Sopenharmony_ci &dev_attr_ipato_del4.attr, 55962306a36Sopenharmony_ci &dev_attr_ipato_invert6.attr, 56062306a36Sopenharmony_ci &dev_attr_ipato_add6.attr, 56162306a36Sopenharmony_ci &dev_attr_ipato_del6.attr, 56262306a36Sopenharmony_ci NULL, 56362306a36Sopenharmony_ci}; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic const struct attribute_group qeth_device_ipato_group = { 56662306a36Sopenharmony_ci .name = "ipa_takeover", 56762306a36Sopenharmony_ci .attrs = qeth_ipato_device_attrs, 56862306a36Sopenharmony_ci}; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf, 57162306a36Sopenharmony_ci enum qeth_prot_versions proto, 57262306a36Sopenharmony_ci enum qeth_ip_types type) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 57562306a36Sopenharmony_ci char addr_str[INET6_ADDRSTRLEN]; 57662306a36Sopenharmony_ci struct qeth_ipaddr *ipaddr; 57762306a36Sopenharmony_ci int offset = 0; 57862306a36Sopenharmony_ci int i; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci mutex_lock(&card->ip_lock); 58162306a36Sopenharmony_ci hash_for_each(card->ip_htable, i, ipaddr, hnode) { 58262306a36Sopenharmony_ci if (ipaddr->proto != proto || ipaddr->type != type) 58362306a36Sopenharmony_ci continue; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci qeth_l3_ipaddr_to_string(proto, (u8 *)&ipaddr->u, addr_str); 58662306a36Sopenharmony_ci offset += sysfs_emit_at(buf, offset, "%s\n", addr_str); 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci mutex_unlock(&card->ip_lock); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return offset ? offset : sysfs_emit(buf, "\n"); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev, 59462306a36Sopenharmony_ci struct device_attribute *attr, 59562306a36Sopenharmony_ci char *buf) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV4, 59862306a36Sopenharmony_ci QETH_IP_TYPE_VIPA); 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic ssize_t qeth_l3_vipa_store(struct device *dev, const char *buf, bool add, 60262306a36Sopenharmony_ci size_t count, enum qeth_prot_versions proto) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 60562306a36Sopenharmony_ci u8 addr[16] = {0, }; 60662306a36Sopenharmony_ci int rc; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci rc = qeth_l3_string_to_ipaddr(buf, proto, addr); 60962306a36Sopenharmony_ci if (!rc) 61062306a36Sopenharmony_ci rc = qeth_l3_modify_rxip_vipa(card, add, addr, 61162306a36Sopenharmony_ci QETH_IP_TYPE_VIPA, proto); 61262306a36Sopenharmony_ci return rc ? rc : count; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev, 61662306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci return qeth_l3_vipa_store(dev, buf, true, count, QETH_PROT_IPV4); 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(vipa_add4, add4, 0644, 62262306a36Sopenharmony_ci qeth_l3_dev_vipa_add4_show, 62362306a36Sopenharmony_ci qeth_l3_dev_vipa_add4_store); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev, 62662306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci return qeth_l3_vipa_store(dev, buf, false, count, QETH_PROT_IPV4); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL, 63262306a36Sopenharmony_ci qeth_l3_dev_vipa_del4_store); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_vipa_add6_show(struct device *dev, 63562306a36Sopenharmony_ci struct device_attribute *attr, 63662306a36Sopenharmony_ci char *buf) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV6, 63962306a36Sopenharmony_ci QETH_IP_TYPE_VIPA); 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev, 64362306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci return qeth_l3_vipa_store(dev, buf, true, count, QETH_PROT_IPV6); 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(vipa_add6, add6, 0644, 64962306a36Sopenharmony_ci qeth_l3_dev_vipa_add6_show, 65062306a36Sopenharmony_ci qeth_l3_dev_vipa_add6_store); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_vipa_del6_store(struct device *dev, 65362306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci return qeth_l3_vipa_store(dev, buf, false, count, QETH_PROT_IPV6); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(vipa_del6, del6, 0200, NULL, 65962306a36Sopenharmony_ci qeth_l3_dev_vipa_del6_store); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic struct attribute *qeth_vipa_device_attrs[] = { 66262306a36Sopenharmony_ci &dev_attr_vipa_add4.attr, 66362306a36Sopenharmony_ci &dev_attr_vipa_del4.attr, 66462306a36Sopenharmony_ci &dev_attr_vipa_add6.attr, 66562306a36Sopenharmony_ci &dev_attr_vipa_del6.attr, 66662306a36Sopenharmony_ci NULL, 66762306a36Sopenharmony_ci}; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic const struct attribute_group qeth_device_vipa_group = { 67062306a36Sopenharmony_ci .name = "vipa", 67162306a36Sopenharmony_ci .attrs = qeth_vipa_device_attrs, 67262306a36Sopenharmony_ci}; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_rxip_add4_show(struct device *dev, 67562306a36Sopenharmony_ci struct device_attribute *attr, 67662306a36Sopenharmony_ci char *buf) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV4, 67962306a36Sopenharmony_ci QETH_IP_TYPE_RXIP); 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto, 68362306a36Sopenharmony_ci u8 *addr) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci __be32 ipv4_addr; 68662306a36Sopenharmony_ci struct in6_addr ipv6_addr; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (qeth_l3_string_to_ipaddr(buf, proto, addr)) { 68962306a36Sopenharmony_ci return -EINVAL; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci if (proto == QETH_PROT_IPV4) { 69262306a36Sopenharmony_ci memcpy(&ipv4_addr, addr, sizeof(ipv4_addr)); 69362306a36Sopenharmony_ci if (ipv4_is_multicast(ipv4_addr)) { 69462306a36Sopenharmony_ci QETH_DBF_MESSAGE(2, "multicast rxip not supported.\n"); 69562306a36Sopenharmony_ci return -EINVAL; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci } else if (proto == QETH_PROT_IPV6) { 69862306a36Sopenharmony_ci memcpy(&ipv6_addr, addr, sizeof(ipv6_addr)); 69962306a36Sopenharmony_ci if (ipv6_addr_is_multicast(&ipv6_addr)) { 70062306a36Sopenharmony_ci QETH_DBF_MESSAGE(2, "multicast rxip not supported.\n"); 70162306a36Sopenharmony_ci return -EINVAL; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci return 0; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic ssize_t qeth_l3_rxip_store(struct device *dev, const char *buf, bool add, 70962306a36Sopenharmony_ci size_t count, enum qeth_prot_versions proto) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct qeth_card *card = dev_get_drvdata(dev); 71262306a36Sopenharmony_ci u8 addr[16] = {0, }; 71362306a36Sopenharmony_ci int rc; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci rc = qeth_l3_parse_rxipe(buf, proto, addr); 71662306a36Sopenharmony_ci if (!rc) 71762306a36Sopenharmony_ci rc = qeth_l3_modify_rxip_vipa(card, add, addr, 71862306a36Sopenharmony_ci QETH_IP_TYPE_RXIP, proto); 71962306a36Sopenharmony_ci return rc ? rc : count; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev, 72362306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci return qeth_l3_rxip_store(dev, buf, true, count, QETH_PROT_IPV4); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(rxip_add4, add4, 0644, 72962306a36Sopenharmony_ci qeth_l3_dev_rxip_add4_show, 73062306a36Sopenharmony_ci qeth_l3_dev_rxip_add4_store); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev, 73362306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci return qeth_l3_rxip_store(dev, buf, false, count, QETH_PROT_IPV4); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL, 73962306a36Sopenharmony_ci qeth_l3_dev_rxip_del4_store); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_rxip_add6_show(struct device *dev, 74262306a36Sopenharmony_ci struct device_attribute *attr, 74362306a36Sopenharmony_ci char *buf) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV6, 74662306a36Sopenharmony_ci QETH_IP_TYPE_RXIP); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev, 75062306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci return qeth_l3_rxip_store(dev, buf, true, count, QETH_PROT_IPV6); 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(rxip_add6, add6, 0644, 75662306a36Sopenharmony_ci qeth_l3_dev_rxip_add6_show, 75762306a36Sopenharmony_ci qeth_l3_dev_rxip_add6_store); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic ssize_t qeth_l3_dev_rxip_del6_store(struct device *dev, 76062306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci return qeth_l3_rxip_store(dev, buf, false, count, QETH_PROT_IPV6); 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic QETH_DEVICE_ATTR(rxip_del6, del6, 0200, NULL, 76662306a36Sopenharmony_ci qeth_l3_dev_rxip_del6_store); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic struct attribute *qeth_rxip_device_attrs[] = { 76962306a36Sopenharmony_ci &dev_attr_rxip_add4.attr, 77062306a36Sopenharmony_ci &dev_attr_rxip_del4.attr, 77162306a36Sopenharmony_ci &dev_attr_rxip_add6.attr, 77262306a36Sopenharmony_ci &dev_attr_rxip_del6.attr, 77362306a36Sopenharmony_ci NULL, 77462306a36Sopenharmony_ci}; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic const struct attribute_group qeth_device_rxip_group = { 77762306a36Sopenharmony_ci .name = "rxip", 77862306a36Sopenharmony_ci .attrs = qeth_rxip_device_attrs, 77962306a36Sopenharmony_ci}; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ciconst struct attribute_group *qeth_l3_attr_groups[] = { 78262306a36Sopenharmony_ci &qeth_l3_device_attr_group, 78362306a36Sopenharmony_ci &qeth_device_ipato_group, 78462306a36Sopenharmony_ci &qeth_device_vipa_group, 78562306a36Sopenharmony_ci &qeth_device_rxip_group, 78662306a36Sopenharmony_ci NULL, 78762306a36Sopenharmony_ci}; 788