Пример #1
0
static ssize_t brport_store(struct kobject *kobj,
			    struct attribute *attr,
			    const char *buf, size_t count)
{
	struct brport_attribute *brport_attr = to_brport_attr(attr);
	struct net_bridge_port *p = to_brport(kobj);
	ssize_t ret = -EINVAL;
	char *endp;
	unsigned long val;

	if (!ns_capable(dev_net(p->dev)->user_ns, CAP_NET_ADMIN))
		return -EPERM;

	val = simple_strtoul(buf, &endp, 0);
	if (endp != buf) {
		if (!rtnl_trylock())
			return restart_syscall();
		if (p->dev && p->br && brport_attr->store) {
			spin_lock_bh(&p->br->lock);
			ret = brport_attr->store(p, val);
			spin_unlock_bh(&p->br->lock);
			if (!ret) {
				br_ifinfo_notify(RTM_NEWLINK, p);
				ret = count;
			}
		}
		rtnl_unlock();
	}
	return ret;
}
Пример #2
0
/* Change state and parameters on port. */
int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
{
	struct ifinfomsg *ifm;
	struct nlattr *protinfo;
	struct nlattr *afspec;
	struct net_bridge_port *p;
	struct nlattr *tb[IFLA_BRPORT_MAX + 1];
	int err;

	ifm = nlmsg_data(nlh);

	protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
	afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC);
	if (!protinfo && !afspec)
		return 0;

	p = br_port_get_rtnl(dev);
	/* We want to accept dev as bridge itself if the AF_SPEC
	 * is set to see if someone is setting vlan info on the brigde
	 */
	if (!p && ((dev->priv_flags & IFF_EBRIDGE) && !afspec))
		return -EINVAL;

	if (p && protinfo) {
		if (protinfo->nla_type & NLA_F_NESTED) {
			err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
					       protinfo, ifla_brport_policy);
			if (err)
				return err;

			spin_lock_bh(&p->br->lock);
			err = br_setport(p, tb);
			spin_unlock_bh(&p->br->lock);
		} else {
			/* Binary compatability with old RSTP */
			if (nla_len(protinfo) < sizeof(u8))
				return -EINVAL;

			spin_lock_bh(&p->br->lock);
			err = br_set_port_state(p, nla_get_u8(protinfo));
			spin_unlock_bh(&p->br->lock);
		}
		if (err)
			goto out;
	}

	if (afspec) {
		err = br_afspec((struct net_bridge *)netdev_priv(dev), p,
				afspec, RTM_SETLINK);
	}

	if (err == 0)
		br_ifinfo_notify(RTM_NEWLINK, p);

out:
	return err;
}
Пример #3
0
/*
 * Handle changes in state of network devices enslaved to a bridge.
 *
 * Note: don't care about up/down if bridge itself is down, because
 *     port state is checked when bridge is brought up.
 */
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
{
	struct net_device *dev = ptr;
	struct net_bridge_port *p = dev->br_port;
	struct net_bridge *br;

	/* not a port of a bridge */
	if (p == NULL)
		return NOTIFY_DONE;

	br = p->br;

	switch (event) {
	case NETDEV_CHANGEMTU:
		dev_set_mtu(br->dev, br_min_mtu(br));
		break;

	case NETDEV_CHANGEADDR:
		spin_lock_bh(&br->lock);
		br_fdb_changeaddr(p, dev->dev_addr);
		br_ifinfo_notify(RTM_NEWLINK, p);
		br_stp_recalculate_bridge_id(br);
		spin_unlock_bh(&br->lock);
		break;

	case NETDEV_CHANGE:
		br_port_carrier_check(p);
		break;

	case NETDEV_FEAT_CHANGE:
		spin_lock_bh(&br->lock);
		if (netif_running(br->dev))
			br_features_recompute(br);
		spin_unlock_bh(&br->lock);
		break;

	case NETDEV_DOWN:
		spin_lock_bh(&br->lock);
		if (br->dev->flags & IFF_UP)
			br_stp_disable_port(p);
		spin_unlock_bh(&br->lock);
		break;

	case NETDEV_UP:
		spin_lock_bh(&br->lock);
		if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP))
			br_stp_enable_port(p);
		spin_unlock_bh(&br->lock);
		break;

	case NETDEV_UNREGISTER:
		br_del_if(br, dev);
		break;
	}

	return NOTIFY_DONE;
}
Пример #4
0
/*
 * Change state of port (ie from forwarding to blocking etc)
 * Used by spanning tree in user space.
 */
static int br_rtm_setlink(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
{
	struct net *net = sock_net(skb->sk);
	struct ifinfomsg *ifm;
	struct nlattr *protinfo;
	struct net_device *dev;
	struct net_bridge_port *p;
	u8 new_state;

	if (nlmsg_len(nlh) < sizeof(*ifm))
		return -EINVAL;

	ifm = nlmsg_data(nlh);
	if (ifm->ifi_family != AF_BRIDGE)
		return -EPFNOSUPPORT;

	protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
	if (!protinfo || nla_len(protinfo) < sizeof(u8))
		return -EINVAL;

	new_state = nla_get_u8(protinfo);
	if (new_state > BR_STATE_BLOCKING)
		return -EINVAL;

	dev = __dev_get_by_index(net, ifm->ifi_index);
	if (!dev)
		return -ENODEV;

	p = br_port_get_rtnl(dev);
	if (!p)
		return -EINVAL;

	/* if kernel STP is running, don't allow changes */
	if (p->br->stp_enabled == BR_KERNEL_STP)
		return -EBUSY;

	if (!netif_running(dev) ||
	    (!netif_carrier_ok(dev) && new_state != BR_STATE_DISABLED))
		return -ENETDOWN;

	p->state = new_state;
	br_log_state(p);

	spin_lock_bh(&p->br->lock);
	br_port_state_selection(p->br);
	spin_unlock_bh(&p->br->lock);

	br_ifinfo_notify(RTM_NEWLINK, p);

	return 0;
}
Пример #5
0
static int store_flag(struct net_bridge_port *p, unsigned long v,
		      unsigned long mask)
{
	unsigned long flags;

	flags = p->flags;

	if (v)
		flags |= mask;
	else
		flags &= ~mask;

	if (flags != p->flags) {
		p->flags = flags;
		br_port_flags_change(p, mask);
		br_ifinfo_notify(RTM_NEWLINK, p);
	}
	return 0;
}
Пример #6
0
/* Change state and parameters on port. */
int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
{
	struct ifinfomsg *ifm;
	struct nlattr *protinfo;
	struct net_bridge_port *p;
	struct nlattr *tb[IFLA_BRPORT_MAX + 1];
	int err;

	ifm = nlmsg_data(nlh);

	protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
	if (!protinfo)
		return 0;

	p = br_port_get_rtnl(dev);
	if (!p)
		return -EINVAL;

	if (protinfo->nla_type & NLA_F_NESTED) {
		err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
				       protinfo, ifla_brport_policy);
		if (err)
			return err;

		spin_lock_bh(&p->br->lock);
		err = br_setport(p, tb);
		spin_unlock_bh(&p->br->lock);
	} else {
		/* Binary compatability with old RSTP */
		if (nla_len(protinfo) < sizeof(u8))
			return -EINVAL;

		spin_lock_bh(&p->br->lock);
		err = br_set_port_state(p, nla_get_u8(protinfo));
		spin_unlock_bh(&p->br->lock);
	}

	if (err == 0)
		br_ifinfo_notify(RTM_NEWLINK, p);

	return err;
}
Пример #7
0
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
{
    struct net_device *dev = ptr;
    struct net_bridge_port *p = dev->br_port;
    struct net_bridge *br;
    int err;

    /* not a port of a bridge */
    if (p == NULL)
        return NOTIFY_DONE;

    br = p->br;

    switch (event) {
    case NETDEV_CHANGEMTU:
        dev_set_mtu(br->dev, br_min_mtu(br));
        break;

    case NETDEV_CHANGEADDR:
        spin_lock_bh(&br->lock);
        br_fdb_changeaddr(p, dev->dev_addr);
        br_stp_recalculate_bridge_id(br);
        spin_unlock_bh(&br->lock);
        break;

    case NETDEV_CHANGE:
        br_port_carrier_check(p);
        break;

    case NETDEV_FEAT_CHANGE:
        spin_lock_bh(&br->lock);
        if (netif_running(br->dev))
            br_features_recompute(br);
        spin_unlock_bh(&br->lock);
        break;

    case NETDEV_DOWN:
        spin_lock_bh(&br->lock);
        if (br->dev->flags & IFF_UP)
            br_stp_disable_port(p);
        spin_unlock_bh(&br->lock);
        break;

    case NETDEV_UP:
        if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) {
            spin_lock_bh(&br->lock);
            br_stp_enable_port(p);
            spin_unlock_bh(&br->lock);
        }
        break;

    case NETDEV_UNREGISTER:
        br_del_if(br, dev);
        break;

    case NETDEV_CHANGENAME:
        err = br_sysfs_renameif(p);
        if (err)
            return notifier_from_errno(err);
        break;

    case NETDEV_PRE_TYPE_CHANGE:
        /* Forbid underlaying device to change its type. */
        return NOTIFY_BAD;
    }

    /* Events that may cause spanning tree to refresh */
    if (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
            event == NETDEV_CHANGE || event == NETDEV_DOWN)
        br_ifinfo_notify(RTM_NEWLINK, p);

    return NOTIFY_DONE;
}
Пример #8
0
Файл: br.c Проект: 19Dan01/linux
/*
 * Handle changes in state of network devices enslaved to a bridge.
 *
 * Note: don't care about up/down if bridge itself is down, because
 *     port state is checked when bridge is brought up.
 */
static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct net_bridge_port *p;
	struct net_bridge *br;
	bool changed_addr;
	int err;

	/* register of bridge completed, add sysfs entries */
	if ((dev->priv_flags & IFF_EBRIDGE) && event == NETDEV_REGISTER) {
		br_sysfs_addbr(dev);
		return NOTIFY_DONE;
	}

	/* not a port of a bridge */
	p = br_port_get_rtnl(dev);
	if (!p)
		return NOTIFY_DONE;

	br = p->br;

	switch (event) {
	case NETDEV_CHANGEMTU:
		dev_set_mtu(br->dev, br_min_mtu(br));
		break;

	case NETDEV_CHANGEADDR:
		spin_lock_bh(&br->lock);
		br_fdb_changeaddr(p, dev->dev_addr);
		changed_addr = br_stp_recalculate_bridge_id(br);
		spin_unlock_bh(&br->lock);

		if (changed_addr)
			call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);

		break;

	case NETDEV_CHANGE:
		br_port_carrier_check(p);
		break;

	case NETDEV_FEAT_CHANGE:
		netdev_update_features(br->dev);
		break;

	case NETDEV_DOWN:
		spin_lock_bh(&br->lock);
		if (br->dev->flags & IFF_UP)
			br_stp_disable_port(p);
		spin_unlock_bh(&br->lock);
		break;

	case NETDEV_UP:
		if (netif_running(br->dev) && netif_oper_up(dev)) {
			spin_lock_bh(&br->lock);
			br_stp_enable_port(p);
			spin_unlock_bh(&br->lock);
		}
		break;

	case NETDEV_UNREGISTER:
		br_del_if(br, dev);
		break;

	case NETDEV_CHANGENAME:
		err = br_sysfs_renameif(p);
		if (err)
			return notifier_from_errno(err);
		break;

	case NETDEV_PRE_TYPE_CHANGE:
		/* Forbid underlaying device to change its type. */
		return NOTIFY_BAD;

	case NETDEV_RESEND_IGMP:
		/* Propagate to master device */
		call_netdevice_notifiers(event, br->dev);
		break;
	}

	/* Events that may cause spanning tree to refresh */
	if (event == NETDEV_CHANGEADDR || event == NETDEV_UP ||
	    event == NETDEV_CHANGE || event == NETDEV_DOWN)
		br_ifinfo_notify(RTM_NEWLINK, p);

	return NOTIFY_DONE;
}