X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fs390%2Fnet%2Fqeth_sys.c;h=fe8b0e24e4465b02c258273bb6a39c6cdd7075d5;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=5a3c788cc36fa1b677c4acdb7fd5f08da8780e85;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index 5a3c788cc..fe8b0e24e 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.24 $) + * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.49 $) * * Linux on zSeries OSA Express and HiperSockets support * This file contains code related to sysfs. @@ -20,6 +20,8 @@ #include "qeth_mpc.h" #include "qeth_fs.h" +const char *VERSION_QETH_SYS_C = "$Revision: 1.49 $"; + /*****************************************************************************/ /* */ /* /sys-fs stuff UNDER DEVELOPMENT !!! */ @@ -73,8 +75,7 @@ qeth_dev_if_name_show(struct device *dev, char *buf) struct qeth_card *card = dev->driver_data; if (!card) return -EINVAL; - - return sprintf(buf, "%s\n", card->info.if_name); + return sprintf(buf, "%s\n", QETH_CARD_IFNAME(card)); } static DEVICE_ATTR(if_name, 0444, qeth_dev_if_name_show, NULL); @@ -320,7 +321,8 @@ static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show, qeth_dev_bufcnt_store); static inline ssize_t -qeth_dev_route_show(struct qeth_routing_info *route, char *buf) +qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route, + char *buf) { switch (route->type) { case PRIMARY_ROUTER: @@ -328,11 +330,20 @@ qeth_dev_route_show(struct qeth_routing_info *route, char *buf) case SECONDARY_ROUTER: return sprintf(buf, "%s\n", "secondary router"); case MULTICAST_ROUTER: - return sprintf(buf, "%s\n", "multicast router"); + if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) + return sprintf(buf, "%s\n", "multicast router+"); + else + return sprintf(buf, "%s\n", "multicast router"); case PRIMARY_CONNECTOR: - return sprintf(buf, "%s\n", "primary connector"); + if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) + return sprintf(buf, "%s\n", "primary connector+"); + else + return sprintf(buf, "%s\n", "primary connector"); case SECONDARY_CONNECTOR: - return sprintf(buf, "%s\n", "secondary connector"); + if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO) + return sprintf(buf, "%s\n", "secondary connector+"); + else + return sprintf(buf, "%s\n", "secondary connector"); default: return sprintf(buf, "%s\n", "no"); } @@ -346,7 +357,7 @@ qeth_dev_route4_show(struct device *dev, char *buf) if (!card) return -EINVAL; - return qeth_dev_route_show(&card->options.route4, buf); + return qeth_dev_route_show(card, &card->options.route4, buf); } static inline ssize_t @@ -414,7 +425,7 @@ qeth_dev_route6_show(struct device *dev, char *buf) if (!qeth_is_supported(card, IPA_IPV6)) return sprintf(buf, "%s\n", "n/a"); - return qeth_dev_route_show(&card->options.route6, buf); + return qeth_dev_route_show(card, &card->options.route6, buf); } static ssize_t @@ -428,7 +439,7 @@ qeth_dev_route6_store(struct device *dev, const char *buf, size_t count) if (!qeth_is_supported(card, IPA_IPV6)){ PRINT_WARN("IPv6 not supported for interface %s.\n" "Routing status no changed.\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); return -ENOTSUPP; } @@ -464,7 +475,7 @@ qeth_dev_add_hhlen_store(struct device *dev, const char *buf, size_t count) (card->state != CARD_STATE_RECOVER)) return -EPERM; - i = simple_strtoul(buf, &tmp, 16); + i = simple_strtoul(buf, &tmp, 10); if ((i < 0) || (i > MAX_ADD_HHLEN)) { PRINT_WARN("add_hhlen out of range\n"); return -EINVAL; @@ -503,12 +514,11 @@ qeth_dev_fake_ll_store(struct device *dev, const char *buf, size_t count) return -EPERM; i = simple_strtoul(buf, &tmp, 16); - if ((i == 0) || (i == 1)) - card->options.fake_ll = i; - else { + if ((i != 0) && (i != 1)) { PRINT_WARN("fake_ll: write 0 or 1 to this file!\n"); return -EINVAL; } + card->options.fake_ll = i; return count; } @@ -682,6 +692,45 @@ qeth_dev_canonical_macaddr_store(struct device *dev, const char *buf, static DEVICE_ATTR(canonical_macaddr, 0644, qeth_dev_canonical_macaddr_show, qeth_dev_canonical_macaddr_store); +static ssize_t +qeth_dev_layer2_show(struct device *dev, char *buf) +{ + struct qeth_card *card = dev->driver_data; + + if (!card) + return -EINVAL; + + return sprintf(buf, "%i\n", card->options.layer2 ? 1:0); +} + +static ssize_t +qeth_dev_layer2_store(struct device *dev, const char *buf, size_t count) +{ + struct qeth_card *card = dev->driver_data; + char *tmp; + int i; + + if (!card) + return -EINVAL; + + if (((card->state != CARD_STATE_DOWN) && + (card->state != CARD_STATE_RECOVER)) || + (card->info.type != QETH_CARD_TYPE_OSAE)) + return -EPERM; + + i = simple_strtoul(buf, &tmp, 16); + if ((i == 0) || (i == 1)) + card->options.layer2 = i; + else { + PRINT_WARN("layer2: write 0 or 1 to this file!\n"); + return -EINVAL; + } + return count; +} + +static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show, + qeth_dev_layer2_store); + static struct device_attribute * qeth_device_attrs[] = { &dev_attr_state, &dev_attr_chpid, @@ -702,6 +751,7 @@ static struct device_attribute * qeth_device_attrs[] = { &dev_attr_recover, &dev_attr_broadcast_mode, &dev_attr_canonical_macaddr, + &dev_attr_layer2, NULL, }; @@ -717,6 +767,15 @@ struct device_attribute dev_attr_##_id = { \ .store = _store, \ }; +int +qeth_check_layer2(struct qeth_card *card) +{ + if (card->options.layer2) + return -EPERM; + return 0; +} + + static ssize_t qeth_dev_ipato_enable_show(struct device *dev, char *buf) { @@ -725,6 +784,8 @@ qeth_dev_ipato_enable_show(struct device *dev, char *buf) if (!card) return -EINVAL; + if (qeth_check_layer2(card)) + return -EPERM; return sprintf(buf, "%i\n", card->ipato.enabled? 1:0); } @@ -737,6 +798,13 @@ qeth_dev_ipato_enable_store(struct device *dev, const char *buf, size_t count) if (!card) return -EINVAL; + if ((card->state != CARD_STATE_DOWN) && + (card->state != CARD_STATE_RECOVER)) + return -EPERM; + + if (qeth_check_layer2(card)) + return -EPERM; + tmp = strsep((char **) &buf, "\n"); if (!strcmp(tmp, "toggle")){ card->ipato.enabled = (card->ipato.enabled)? 0 : 1; @@ -764,6 +832,9 @@ qeth_dev_ipato_invert4_show(struct device *dev, char *buf) if (!card) return -EINVAL; + if (qeth_check_layer2(card)) + return -EPERM; + return sprintf(buf, "%i\n", card->ipato.invert4? 1:0); } @@ -776,6 +847,9 @@ qeth_dev_ipato_invert4_store(struct device *dev, const char *buf, size_t count) if (!card) return -EINVAL; + if (qeth_check_layer2(card)) + return -EPERM; + tmp = strsep((char **) &buf, "\n"); if (!strcmp(tmp, "toggle")){ card->ipato.invert4 = (card->ipato.invert4)? 0 : 1; @@ -801,18 +875,31 @@ qeth_dev_ipato_add_show(char *buf, struct qeth_card *card, { struct qeth_ipato_entry *ipatoe; unsigned long flags; - char addr_str[49]; + char addr_str[40]; + int entry_len; /* length of 1 entry string, differs between v4 and v6 */ int i = 0; + if (qeth_check_layer2(card)) + return -EPERM; + + entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; + /* add strlen for "/\n" */ + entry_len += (proto == QETH_PROT_IPV4)? 5 : 6; spin_lock_irqsave(&card->ip_lock, flags); list_for_each_entry(ipatoe, &card->ipato.entries, entry){ if (ipatoe->proto != proto) continue; + /* String must not be longer than PAGE_SIZE. So we check if + * string length gets near PAGE_SIZE. Then we can savely display + * the next IPv6 address (worst case, compared to IPv4) */ + if ((PAGE_SIZE - i) <= entry_len) + break; qeth_ipaddr_to_string(proto, ipatoe->addr, addr_str); - i += sprintf(buf + i, "%s/%i\n", addr_str, ipatoe->mask_bits); + i += snprintf(buf + i, PAGE_SIZE - i, + "%s/%i\n", addr_str, ipatoe->mask_bits); } spin_unlock_irqrestore(&card->ip_lock, flags); - i += sprintf(buf + i, "\n"); + i += snprintf(buf + i, PAGE_SIZE - i, "\n"); return i; } @@ -864,6 +951,8 @@ qeth_dev_ipato_add_store(const char *buf, size_t count, int mask_bits; int rc; + if (qeth_check_layer2(card)) + return -EPERM; if ((rc = qeth_parse_ipatoe(buf, proto, addr, &mask_bits))) return rc; @@ -907,6 +996,8 @@ qeth_dev_ipato_del_store(const char *buf, size_t count, int mask_bits; int rc; + if (qeth_check_layer2(card)) + return -EPERM; if ((rc = qeth_parse_ipatoe(buf, proto, addr, &mask_bits))) return rc; @@ -938,6 +1029,9 @@ qeth_dev_ipato_invert6_show(struct device *dev, char *buf) if (!card) return -EINVAL; + if (qeth_check_layer2(card)) + return -EPERM; + return sprintf(buf, "%i\n", card->ipato.invert6? 1:0); } @@ -950,6 +1044,9 @@ qeth_dev_ipato_invert6_store(struct device *dev, const char *buf, size_t count) if (!card) return -EINVAL; + if (qeth_check_layer2(card)) + return -EPERM; + tmp = strsep((char **) &buf, "\n"); if (!strcmp(tmp, "toggle")){ card->ipato.invert6 = (card->ipato.invert6)? 0 : 1; @@ -1034,21 +1131,32 @@ qeth_dev_vipa_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { struct qeth_ipaddr *ipaddr; - char addr_str[49]; + char addr_str[40]; + int entry_len; /* length of 1 entry string, differs between v4 and v6 */ unsigned long flags; int i = 0; + if (qeth_check_layer2(card)) + return -EPERM; + + entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; + entry_len += 2; /* \n + terminator */ spin_lock_irqsave(&card->ip_lock, flags); list_for_each_entry(ipaddr, &card->ip_list, entry){ if (ipaddr->proto != proto) continue; if (ipaddr->type != QETH_IP_TYPE_VIPA) continue; + /* String must not be longer than PAGE_SIZE. So we check if + * string length gets near PAGE_SIZE. Then we can savely display + * the next IPv6 address (worst case, compared to IPv4) */ + if ((PAGE_SIZE - i) <= entry_len) + break; qeth_ipaddr_to_string(proto, (const u8 *)&ipaddr->u, addr_str); - i += sprintf(buf + i, "%s\n", addr_str); + i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str); } spin_unlock_irqrestore(&card->ip_lock, flags); - i += sprintf(buf + i, "\n"); + i += snprintf(buf + i, PAGE_SIZE - i, "\n"); return i; } @@ -1082,6 +1190,8 @@ qeth_dev_vipa_add_store(const char *buf, size_t count, u8 addr[16] = {0, }; int rc; + if (qeth_check_layer2(card)) + return -EPERM; if ((rc = qeth_parse_vipae(buf, proto, addr))) return rc; @@ -1113,6 +1223,8 @@ qeth_dev_vipa_del_store(const char *buf, size_t count, u8 addr[16]; int rc; + if (qeth_check_layer2(card)) + return -EPERM; if ((rc = qeth_parse_vipae(buf, proto, addr))) return rc; @@ -1170,6 +1282,9 @@ qeth_dev_vipa_del6_store(struct device *dev, const char *buf, size_t count) if (!card) return -EINVAL; + if (qeth_check_layer2(card)) + return -EPERM; + return qeth_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV6); } @@ -1197,21 +1312,32 @@ qeth_dev_rxip_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { struct qeth_ipaddr *ipaddr; - char addr_str[49]; + char addr_str[40]; + int entry_len; /* length of 1 entry string, differs between v4 and v6 */ unsigned long flags; int i = 0; + if (qeth_check_layer2(card)) + return -EPERM; + + entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; + entry_len += 2; /* \n + terminator */ spin_lock_irqsave(&card->ip_lock, flags); list_for_each_entry(ipaddr, &card->ip_list, entry){ if (ipaddr->proto != proto) continue; if (ipaddr->type != QETH_IP_TYPE_RXIP) continue; + /* String must not be longer than PAGE_SIZE. So we check if + * string length gets near PAGE_SIZE. Then we can savely display + * the next IPv6 address (worst case, compared to IPv4) */ + if ((PAGE_SIZE - i) <= entry_len) + break; qeth_ipaddr_to_string(proto, (const u8 *)&ipaddr->u, addr_str); - i += sprintf(buf + i, "%s\n", addr_str); + i += snprintf(buf + i, PAGE_SIZE - i, "%s\n", addr_str); } spin_unlock_irqrestore(&card->ip_lock, flags); - i += sprintf(buf + i, "\n"); + i += snprintf(buf + i, PAGE_SIZE - i, "\n"); return i; } @@ -1245,6 +1371,8 @@ qeth_dev_rxip_add_store(const char *buf, size_t count, u8 addr[16] = {0, }; int rc; + if (qeth_check_layer2(card)) + return -EPERM; if ((rc = qeth_parse_rxipe(buf, proto, addr))) return rc; @@ -1276,6 +1404,8 @@ qeth_dev_rxip_del_store(const char *buf, size_t count, u8 addr[16]; int rc; + if (qeth_check_layer2(card)) + return -EPERM; if ((rc = qeth_parse_rxipe(buf, proto, addr))) return rc; @@ -1426,22 +1556,33 @@ qeth_driver_group_store(struct device_driver *ddrv, const char *buf, static DRIVER_ATTR(group, 0200, 0, qeth_driver_group_store); static ssize_t -qeth_driver_snmp_register_show(struct device_driver *ddrv, char *buf) -{ - /* TODO */ - return 0; -} - -static ssize_t -qeth_driver_snmp_register_store(struct device_driver *ddrv, const char *buf, +qeth_driver_notifier_register_store(struct device_driver *ddrv, const char *buf, size_t count) { - /* TODO */ + int rc; + int signum; + char *tmp, *tmp2; + + tmp = strsep((char **) &buf, "\n"); + if (!strncmp(tmp, "unregister", 10)){ + if ((rc = qeth_notifier_unregister(current))) + return rc; + return count; + } + + signum = simple_strtoul(tmp, &tmp2, 10); + if ((signum < 0) || (signum > 32)){ + PRINT_WARN("Signal number %d is out of range\n", signum); + return -EINVAL; + } + if ((rc = qeth_notifier_register(current, signum))) + return rc; + return count; } -static DRIVER_ATTR(snmp_register, 0644, qeth_driver_snmp_register_show, - qeth_driver_snmp_register_store); +static DRIVER_ATTR(notifier_register, 0200, 0, + qeth_driver_notifier_register_store); int qeth_create_driver_attributes(void) @@ -1452,7 +1593,7 @@ qeth_create_driver_attributes(void) &driver_attr_group))) return rc; return driver_create_file(&qeth_ccwgroup_driver.driver, - &driver_attr_snmp_register); + &driver_attr_notifier_register); } void @@ -1461,5 +1602,5 @@ qeth_remove_driver_attributes(void) driver_remove_file(&qeth_ccwgroup_driver.driver, &driver_attr_group); driver_remove_file(&qeth_ccwgroup_driver.driver, - &driver_attr_snmp_register); + &driver_attr_notifier_register); }