static int can_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct can_priv *priv = netdev_priv(dev); int err; /* We need synchronization with dev->stop() */ ASSERT_RTNL(); if (data[IFLA_CAN_BITTIMING]) { struct can_bittiming bt; /* Do not allow changing bittiming while running */ if (dev->flags & IFF_UP) return -EBUSY; memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq)) return -EINVAL; err = can_get_bittiming(dev, &bt); if (err) return err; memcpy(&priv->bittiming, &bt, sizeof(bt)); if (priv->do_set_bittiming) { /* Finally, set the bit-timing registers */ err = priv->do_set_bittiming(dev); if (err) return err; } } if (data[IFLA_CAN_CTRLMODE]) { struct can_ctrlmode *cm; /* Do not allow changing controller mode while running */ if (dev->flags & IFF_UP) return -EBUSY; cm = nla_data(data[IFLA_CAN_CTRLMODE]); if (cm->flags & ~priv->ctrlmode_supported) return -EOPNOTSUPP; priv->ctrlmode &= ~cm->mask; priv->ctrlmode |= cm->flags; } if (data[IFLA_CAN_RESTART_MS]) { /* Do not allow changing restart delay while running */ if (dev->flags & IFF_UP) return -EBUSY; priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]); } if (data[IFLA_CAN_RESTART]) { /* Do not allow a restart while not running */ if (!(dev->flags & IFF_UP)) return -EINVAL; err = can_restart_now(dev); if (err) return err; } return 0; }
static void sit_add_v4_addrs(struct inet6_dev *idev) { struct inet6_ifaddr * ifp; struct in6_addr addr; struct net_device *dev; int scope; ASSERT_RTNL(); memset(&addr, 0, sizeof(struct in6_addr)); memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4); if (idev->dev->flags&IFF_POINTOPOINT) { addr.s6_addr32[0] = htonl(0xfe800000); scope = IFA_LINK; } else { scope = IPV6_ADDR_COMPATv4; } if (addr.s6_addr32[3]) { ifp = ipv6_add_addr(idev, &addr, 128, scope, IFA_F_PERMANENT); if (ifp) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); in6_ifa_put(ifp); } return; } for (dev = dev_base; dev != NULL; dev = dev->next) { struct in_device * in_dev = __in_dev_get(dev); if (in_dev && (dev->flags & IFF_UP)) { struct in_ifaddr * ifa; int flag = scope; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { int plen; addr.s6_addr32[3] = ifa->ifa_local; if (ifa->ifa_scope == RT_SCOPE_LINK) continue; if (ifa->ifa_scope >= RT_SCOPE_HOST) { if (idev->dev->flags&IFF_POINTOPOINT) continue; flag |= IFA_HOST; } if (idev->dev->flags&IFF_POINTOPOINT) plen = 10; else plen = 96; ifp = ipv6_add_addr(idev, &addr, plen, flag, IFA_F_PERMANENT); if (ifp) { spin_lock_bh(&ifp->lock); ifp->flags &= ~IFA_F_TENTATIVE; spin_unlock_bh(&ifp->lock); ipv6_ifa_notify(RTM_NEWADDR, ifp); in6_ifa_put(ifp); } } } } }
int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) { struct ipv6_pinfo *np = inet6_sk(sk); struct net_device *dev = NULL; struct inet6_dev *idev; struct ipv6_ac_socklist *pac; struct net *net = sock_net(sk); int ishost = !net->ipv6.devconf_all->forwarding; int err = 0; ASSERT_RTNL(); if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) return -EPERM; if (ipv6_addr_is_multicast(addr)) return -EINVAL; if (ipv6_chk_addr(net, addr, NULL, 0)) return -EINVAL; pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL); if (!pac) return -ENOMEM; pac->acl_next = NULL; pac->acl_addr = *addr; if (ifindex == 0) { struct rt6_info *rt; rt = rt6_lookup(net, addr, NULL, 0, 0); if (rt) { dev = rt->dst.dev; ip6_rt_put(rt); } else if (ishost) { err = -EADDRNOTAVAIL; goto error; } else { /* router, no matching interface: just pick one */ dev = __dev_get_by_flags(net, IFF_UP, IFF_UP | IFF_LOOPBACK); } } else dev = __dev_get_by_index(net, ifindex); if (!dev) { err = -ENODEV; goto error; } idev = __in6_dev_get(dev); if (!idev) { if (ifindex) err = -ENODEV; else err = -EADDRNOTAVAIL; goto error; } /* reset ishost, now that we have a specific device */ ishost = !idev->cnf.forwarding; pac->acl_ifindex = dev->ifindex; /* XXX * For hosts, allow link-local or matching prefix anycasts. * This obviates the need for propagating anycast routes while * still allowing some non-router anycast participation. */ if (!ipv6_chk_prefix(addr, dev)) { if (ishost) err = -EADDRNOTAVAIL; if (err) goto error; } err = __ipv6_dev_ac_inc(idev, addr); if (!err) { pac->acl_next = np->ipv6_ac_list; np->ipv6_ac_list = pac; pac = NULL; } error: if (pac) sock_kfree_s(sk, pac, sizeof(*pac)); return err; }
static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy, struct nlmsghdr *nlh, u32 pid) { struct in_ifaddr *promote = NULL; struct in_ifaddr *ifa, *ifa1 = *ifap; struct in_ifaddr *last_prim = in_dev->ifa_list; struct in_ifaddr *prev_prom = NULL; int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev); ASSERT_RTNL(); /* 1. Deleting primary ifaddr forces deletion all secondaries * unless alias promotion is set **/ if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { struct in_ifaddr **ifap1 = &ifa1->ifa_next; while ((ifa = *ifap1) != NULL) { if (!(ifa->ifa_flags & IFA_F_SECONDARY) && ifa1->ifa_scope <= ifa->ifa_scope) last_prim = ifa; if (!(ifa->ifa_flags & IFA_F_SECONDARY) || ifa1->ifa_mask != ifa->ifa_mask || !inet_ifa_match(ifa1->ifa_address, ifa)) { ifap1 = &ifa->ifa_next; prev_prom = ifa; continue; } if (!do_promote) { *ifap1 = ifa->ifa_next; rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid); blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); inet_free_ifa(ifa); } else { promote = ifa; break; } } } /* 2. Unlink it */ *ifap = ifa1->ifa_next; /* 3. Announce address deletion */ /* Send message first, then call notifier. At first sight, FIB update triggered by notifier will refer to already deleted ifaddr, that could confuse netlink listeners. It is not true: look, gated sees that route deleted and if it still thinks that ifaddr is valid, it will try to restore deleted routes... Grr. So that, this order is correct. */ rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid); blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); if (promote) { if (prev_prom) { prev_prom->ifa_next = promote->ifa_next; promote->ifa_next = last_prim->ifa_next; last_prim->ifa_next = promote; } promote->ifa_flags &= ~IFA_F_SECONDARY; rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid); blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote); for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) { if (ifa1->ifa_mask != ifa->ifa_mask || !inet_ifa_match(ifa1->ifa_address, ifa)) continue; fib_add_ifaddr(ifa); } } if (destroy) inet_free_ifa(ifa1); }
/** * rmnet_force_unassociate_device() - Force a device to unassociate * @dev: Device to unassociate * * Return: * - void */ static void rmnet_force_unassociate_device(struct net_device *dev) { int i, j; struct net_device *vndev; struct rmnet_logical_ep_conf_s *cfg; struct rmnet_free_vnd_work *vnd_work; ASSERT_RTNL(); if (!dev) BUG(); if (!_rmnet_is_physical_endpoint_associated(dev)) { LOGM("%s", "Called on unassociated device, skipping"); return; } trace_rmnet_unregister_cb_clear_vnds(dev); vnd_work = (struct rmnet_free_vnd_work *) kmalloc(sizeof(struct rmnet_free_vnd_work), GFP_KERNEL); if (!vnd_work) { LOGH("%s", "Out of Memory"); return; } INIT_WORK(&vnd_work->work, _rmnet_free_vnd_later); vnd_work->count = 0; /* Check the VNDs for offending mappings */ for (i = 0, j = 0; i < RMNET_DATA_MAX_VND && j < RMNET_DATA_MAX_VND; i++) { vndev = rmnet_vnd_get_by_id(i); if (!vndev) { LOGL("VND %d not in use; skipping", i); continue; } cfg = rmnet_vnd_get_le_config(vndev); if (!cfg) { LOGH("Got NULL config from VND %d", i); BUG(); continue; } if (cfg->refcount && (cfg->egress_dev == dev)) { rmnet_unset_logical_endpoint_config(vndev, RMNET_LOCAL_LOGICAL_ENDPOINT); vnd_work->vnd_id[j] = i; j++; } } if (j > 0) { vnd_work->count = j; schedule_work(&vnd_work->work); } else { kfree(vnd_work); } /* Clear the mappings on the phys ep */ trace_rmnet_unregister_cb_clear_lepcs(dev); rmnet_unset_logical_endpoint_config(dev, RMNET_LOCAL_LOGICAL_ENDPOINT); for (i = 0; i < RMNET_DATA_MAX_LOGICAL_EP; i++) rmnet_unset_logical_endpoint_config(dev, i); rmnet_unassociate_network_device(dev); }
/* * device anycast group inc (add if not found) */ int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr) { struct ifacaddr6 *aca; struct inet6_dev *idev; struct rt6_info *rt; int err; ASSERT_RTNL(); idev = in6_dev_get(dev); if (idev == NULL) return -EINVAL; write_lock_bh(&idev->lock); if (idev->dead) { err = -ENODEV; goto out; } for (aca = idev->ac_list; aca; aca = aca->aca_next) { if (ipv6_addr_equal(&aca->aca_addr, addr)) { aca->aca_users++; err = 0; goto out; } } /* * not found: create a new one. */ aca = kzalloc(sizeof(struct ifacaddr6), GFP_ATOMIC); if (aca == NULL) { err = -ENOMEM; goto out; } rt = addrconf_dst_alloc(idev, addr, true); if (IS_ERR(rt)) { kfree(aca); err = PTR_ERR(rt); goto out; } aca->aca_addr = *addr; aca->aca_idev = idev; aca->aca_rt = rt; aca->aca_users = 1; /* aca_tstamp should be updated upon changes */ aca->aca_cstamp = aca->aca_tstamp = jiffies; atomic_set(&aca->aca_refcnt, 2); spin_lock_init(&aca->aca_lock); aca->aca_next = idev->ac_list; idev->ac_list = aca; write_unlock_bh(&idev->lock); ip6_ins_rt(rt); addrconf_join_solict(dev, &aca->aca_addr); aca_put(aca); return 0; out: write_unlock_bh(&idev->lock); in6_dev_put(idev); return err; }
/** * @brief Request the driver to add a virtual interface * * @param wiphy A pointer to wiphy structure * @param name Virtual interface name * @param type Virtual interface type * @param flags Flags for the virtual interface * @param params A pointer to vif_params structure * @param new_dev new net_device to return * * @return 0 -- success, otherwise fail */ int woal_cfg80211_add_virt_if(struct wiphy *wiphy, #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) const #endif char *name, enum nl80211_iftype type, u32 *flags, struct vif_params *params, struct net_device **new_dev) { int ret = 0; struct net_device *ndev = NULL; moal_private *priv = NULL, *new_priv = NULL; moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy); struct wireless_dev *wdev = NULL; moal_private *vir_priv; int i = 0; ENTER(); ASSERT_RTNL(); priv = (moal_private *)woal_get_priv_bss_type(handle, MLAN_BSS_TYPE_WIFIDIRECT); if (!priv || !priv->phandle) { PRINTM(MERROR, "priv or handle is NULL\n"); LEAVE(); return -EFAULT; } if (priv->phandle->drv_mode.intf_num == priv->phandle->priv_num) { PRINTM(MERROR, "max virtual interface limit reached\n"); for (i = 0; i < priv->phandle->priv_num; i++) { vir_priv = priv->phandle->priv[i]; if (vir_priv->bss_virtual) { woal_cfg80211_del_virt_if(wiphy, vir_priv->netdev); break; } } if (priv->phandle->drv_mode.intf_num == priv->phandle->priv_num) { LEAVE(); return -ENOMEM; } } PRINTM(MMSG, "Add virtual interface %s\n", name); if ((type != NL80211_IFTYPE_P2P_CLIENT) && (type != NL80211_IFTYPE_P2P_GO)) { PRINTM(MERROR, "Invalid iftype: %d\n", type); LEAVE(); return -EINVAL; } handle = priv->phandle; /* Cancel previous scan req */ woal_cancel_scan(priv, MOAL_IOCTL_WAIT); new_priv = woal_alloc_virt_interface(handle, handle->priv_num, MLAN_BSS_TYPE_WIFIDIRECT, name); if (!new_priv) { PRINTM(MERROR, "Add virtual interface fail."); LEAVE(); return -EFAULT; } handle->priv_num++; wdev = (struct wireless_dev *)&new_priv->w_dev; memset(wdev, 0, sizeof(struct wireless_dev)); ndev = new_priv->netdev; SET_NETDEV_DEV(ndev, wiphy_dev(wiphy)); ndev->ieee80211_ptr = wdev; wdev->iftype = type; wdev->wiphy = wiphy; new_priv->wdev = wdev; new_priv->bss_virtual = MTRUE; new_priv->pa_netdev = priv->netdev; woal_init_sta_dev(ndev, new_priv); /* Initialize priv structure */ woal_init_priv(new_priv, MOAL_CMD_WAIT); /** Init to GO/CLIENT mode */ if (type == NL80211_IFTYPE_P2P_CLIENT) woal_cfg80211_init_p2p_client(new_priv); else if (type == NL80211_IFTYPE_P2P_GO) woal_cfg80211_init_p2p_go(new_priv); ret = register_netdevice(ndev); if (ret) { handle->priv[new_priv->bss_index] = NULL; handle->priv_num--; if (ndev->reg_state == NETREG_REGISTERED) { unregister_netdevice(ndev); free_netdev(ndev); ndev = NULL; } PRINTM(MFATAL, "register net_device failed, ret=%d\n", ret); goto done; } netif_carrier_off(ndev); woal_stop_queue(ndev); if (new_dev) *new_dev = ndev; #ifdef CONFIG_PROC_FS woal_create_proc_entry(new_priv); #ifdef PROC_DEBUG woal_debug_entry(new_priv); #endif /* PROC_DEBUG */ #endif /* CONFIG_PROC_FS */ done: LEAVE(); return ret; }
static int phylink_sfp_module_insert(void *upstream, const struct sfp_eeprom_id *id) { struct phylink *pl = upstream; __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; struct phylink_link_state config; phy_interface_t iface; int ret = 0; bool changed; u8 port; ASSERT_RTNL(); sfp_parse_support(pl->sfp_bus, id, support); port = sfp_parse_port(pl->sfp_bus, id, support); memset(&config, 0, sizeof(config)); linkmode_copy(config.advertising, support); config.interface = PHY_INTERFACE_MODE_NA; config.speed = SPEED_UNKNOWN; config.duplex = DUPLEX_UNKNOWN; config.pause = MLO_PAUSE_AN; config.an_enabled = pl->link_config.an_enabled; /* Ignore errors if we're expecting a PHY to attach later */ ret = phylink_validate(pl, support, &config); if (ret) { netdev_err(pl->netdev, "validation with support %*pb failed: %d\n", __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); return ret; } iface = sfp_select_interface(pl->sfp_bus, id, config.advertising); if (iface == PHY_INTERFACE_MODE_NA) { netdev_err(pl->netdev, "selection of interface failed, advertisement %*pb\n", __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising); return -EINVAL; } config.interface = iface; ret = phylink_validate(pl, support, &config); if (ret) { netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n", phylink_an_mode_str(MLO_AN_INBAND), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support, ret); return ret; } netdev_dbg(pl->netdev, "requesting link mode %s/%s with support %*pb\n", phylink_an_mode_str(MLO_AN_INBAND), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support); if (phy_interface_mode_is_8023z(iface) && pl->phydev) return -EINVAL; changed = !bitmap_equal(pl->supported, support, __ETHTOOL_LINK_MODE_MASK_NBITS); if (changed) { linkmode_copy(pl->supported, support); linkmode_copy(pl->link_config.advertising, config.advertising); } if (pl->link_an_mode != MLO_AN_INBAND || pl->link_config.interface != config.interface) { pl->link_config.interface = config.interface; pl->link_an_mode = MLO_AN_INBAND; changed = true; netdev_info(pl->netdev, "switched to %s/%s link mode\n", phylink_an_mode_str(MLO_AN_INBAND), phy_modes(config.interface)); } pl->link_port = port; if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) phylink_mac_config(pl, &pl->link_config); return ret; }
/** * phylink_ethtool_ksettings_set() - set the link settings * @pl: a pointer to a &struct phylink returned from phylink_create() * @kset: a pointer to a &struct ethtool_link_ksettings for the desired modes */ int phylink_ethtool_ksettings_set(struct phylink *pl, const struct ethtool_link_ksettings *kset) { struct ethtool_link_ksettings our_kset; struct phylink_link_state config; int ret; ASSERT_RTNL(); if (kset->base.autoneg != AUTONEG_DISABLE && kset->base.autoneg != AUTONEG_ENABLE) return -EINVAL; config = pl->link_config; /* Mask out unsupported advertisements */ linkmode_and(config.advertising, kset->link_modes.advertising, pl->supported); /* FIXME: should we reject autoneg if phy/mac does not support it? */ if (kset->base.autoneg == AUTONEG_DISABLE) { const struct phy_setting *s; /* Autonegotiation disabled, select a suitable speed and * duplex. */ s = phy_lookup_setting(kset->base.speed, kset->base.duplex, pl->supported, false); if (!s) return -EINVAL; /* If we have a fixed link (as specified by firmware), refuse * to change link parameters. */ if (pl->link_an_mode == MLO_AN_FIXED && (s->speed != pl->link_config.speed || s->duplex != pl->link_config.duplex)) return -EINVAL; config.speed = s->speed; config.duplex = s->duplex; config.an_enabled = false; __clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising); } else { /* If we have a fixed link, refuse to enable autonegotiation */ if (pl->link_an_mode == MLO_AN_FIXED) return -EINVAL; config.speed = SPEED_UNKNOWN; config.duplex = DUPLEX_UNKNOWN; config.an_enabled = true; __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising); } if (phylink_validate(pl, pl->supported, &config)) return -EINVAL; /* If autonegotiation is enabled, we must have an advertisement */ if (config.an_enabled && phylink_is_empty_linkmode(config.advertising)) return -EINVAL; our_kset = *kset; linkmode_copy(our_kset.link_modes.advertising, config.advertising); our_kset.base.speed = config.speed; our_kset.base.duplex = config.duplex; /* If we have a PHY, configure the phy */ if (pl->phydev) { ret = phy_ethtool_ksettings_set(pl->phydev, &our_kset); if (ret) return ret; } mutex_lock(&pl->state_mutex); /* Configure the MAC to match the new settings */ linkmode_copy(pl->link_config.advertising, our_kset.link_modes.advertising); pl->link_config.interface = config.interface; pl->link_config.speed = our_kset.base.speed; pl->link_config.duplex = our_kset.base.duplex; pl->link_config.an_enabled = our_kset.base.autoneg != AUTONEG_DISABLE; if (!test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) { phylink_mac_config(pl, &pl->link_config); phylink_mac_an_restart(pl); } mutex_unlock(&pl->state_mutex); return 0; }