diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 3abac028899f..ba974a2e409f 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -175,6 +175,8 @@ struct qeth_sbp_info { __u32 supported_funcs; enum qeth_sbp_roles role; __u32 hostnotification:1; + __u32 reflect_promisc:1; + __u32 reflect_promisc_primary:1; }; static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa, diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 1cdefaea866c..0ff926d4d63d 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -683,6 +683,39 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) return rc ? -EINVAL : 0; } +static void qeth_promisc_to_bridge(struct qeth_card *card) +{ + struct net_device *dev = card->dev; + enum qeth_ipa_promisc_modes promisc_mode; + int role; + int rc; + + QETH_CARD_TEXT(card, 3, "pmisc2br"); + + if (!card->options.sbp.reflect_promisc) + return; + promisc_mode = (dev->flags & IFF_PROMISC) ? SET_PROMISC_MODE_ON + : SET_PROMISC_MODE_OFF; + if (promisc_mode == card->info.promisc_mode) + return; + + if (promisc_mode == SET_PROMISC_MODE_ON) { + if (card->options.sbp.reflect_promisc_primary) + role = QETH_SBP_ROLE_PRIMARY; + else + role = QETH_SBP_ROLE_SECONDARY; + } else + role = QETH_SBP_ROLE_NONE; + + rc = qeth_bridgeport_setrole(card, role); + QETH_DBF_TEXT_(SETUP, 2, "bpm%c%04x", + (promisc_mode == SET_PROMISC_MODE_ON) ? '+' : '-', rc); + if (!rc) { + card->options.sbp.role = role; + card->info.promisc_mode = promisc_mode; + } +} + static void qeth_l2_set_multicast_list(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; @@ -704,9 +737,10 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) qeth_l2_add_mc(card, ha->addr, 1); spin_unlock_bh(&card->mclock); - if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) - return; - qeth_setadp_promisc_mode(card); + if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) + qeth_setadp_promisc_mode(card); + else + qeth_promisc_to_bridge(card); } static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) diff --git a/drivers/s390/net/qeth_l2_sys.c b/drivers/s390/net/qeth_l2_sys.c index 6504d48bdd97..a553fbab17fc 100644 --- a/drivers/s390/net/qeth_l2_sys.c +++ b/drivers/s390/net/qeth_l2_sys.c @@ -159,10 +159,66 @@ static DEVICE_ATTR(bridge_hostnotify, 0644, qeth_bridgeport_hostnotification_show, qeth_bridgeport_hostnotification_store); +static ssize_t qeth_bridgeport_reflect_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qeth_card *card = dev_get_drvdata(dev); + char *state; + + if (!card) + return -EINVAL; + + if (card->options.sbp.reflect_promisc) { + if (card->options.sbp.reflect_promisc_primary) + state = "primary"; + else + state = "secondary"; + } else + state = "none"; + + return sprintf(buf, "%s\n", state); +} + +static ssize_t qeth_bridgeport_reflect_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct qeth_card *card = dev_get_drvdata(dev); + int enable, primary; + + if (!card) + return -EINVAL; + + if (sysfs_streq(buf, "none")) { + enable = 0; + primary = 0; + } else if (sysfs_streq(buf, "primary")) { + enable = 1; + primary = 1; + } else if (sysfs_streq(buf, "secondary")) { + enable = 1; + primary = 0; + } else + return -EINVAL; + + mutex_lock(&card->conf_mutex); + + card->options.sbp.reflect_promisc = enable; + card->options.sbp.reflect_promisc_primary = primary; + + mutex_unlock(&card->conf_mutex); + + return count; +} + +static DEVICE_ATTR(bridge_reflect_promisc, 0644, + qeth_bridgeport_reflect_show, + qeth_bridgeport_reflect_store); + static struct attribute *qeth_l2_bridgeport_attrs[] = { &dev_attr_bridge_role.attr, &dev_attr_bridge_state.attr, &dev_attr_bridge_hostnotify.attr, + &dev_attr_bridge_reflect_promisc.attr, NULL, };