/* 16 SIOCSIFFLAGS -- Set flags of a network interface.  */
kern_return_t
S_iioctl_siocsifflags (io_t port,
		       ifname_t ifnam,
		       short flags)
{
  struct sock_user *user = begin_using_socket_port (port);
  error_t err = 0;
  struct device *dev;

  if (!user)
    return EOPNOTSUPP;

  dev = get_dev (ifnam);

  if (!user->isroot)
    err = EPERM;
  else if (!dev)
    err = ENODEV;
  else
    {
      err = dev_change_flags (dev, flags);
      if (!err)
        err = ethernet_change_flags (dev, flags);
    }

  __mutex_unlock (&global_lock);
  end_using_socket_port (user);
  return err;
}
Exemple #2
0
static struct vport *gre_tnl_create(const struct vport_parms *parms)
{
	struct net *net = ovs_dp_get_net(parms->dp);
	struct net_device *dev;
	struct vport *vport;
	int err;

	vport = ovs_vport_alloc(0, &ovs_gre_vport_ops, parms);
	if (IS_ERR(vport))
		return vport;

	rtnl_lock();
	dev = gretap_fb_dev_create(net, parms->name, NET_NAME_USER);
	if (IS_ERR(dev)) {
		rtnl_unlock();
		ovs_vport_free(vport);
		return ERR_CAST(dev);
	}

	err = dev_change_flags(dev, dev->flags | IFF_UP);
	if (err < 0) {
		rtnl_delete_link(dev);
		rtnl_unlock();
		ovs_vport_free(vport);
		return ERR_PTR(err);
	}

	rtnl_unlock();
	return vport;
}
Exemple #3
0
/* cycle interface to flush neighbor cache and move routes across tables */
static void cycle_netdev(struct net_device *dev)
{
	unsigned int flags = dev->flags;
	int ret;

	if (!netif_running(dev))
		return;

	ret = dev_change_flags(dev, flags & ~IFF_UP);
	if (ret >= 0)
		ret = dev_change_flags(dev, flags);

	if (ret < 0) {
		netdev_err(dev,
			   "Failed to cycle device %s; route tables might be wrong!\n",
			   dev->name);
	}
}
static int ipoib_set_ring_param(struct net_device *dev,
				struct ethtool_ringparam *ringparam)
{
	struct ipoib_dev_priv *priv = netdev_priv(dev);
	unsigned int new_recvq_size, new_sendq_size;
	unsigned long priv_current_flags;
	unsigned int dev_current_flags;
	bool init = false;

	if (ringparam->rx_pending <= IPOIB_MAX_QUEUE_SIZE &&
	    ringparam->rx_pending >= IPOIB_MIN_QUEUE_SIZE) {
		new_recvq_size = roundup_pow_of_two(ringparam->rx_pending);
		if (ringparam->rx_pending != new_recvq_size)
			pr_warn("%s: %s: rx_pending should be power of two. rx_pending is %d\n",
				dev->name, __func__, new_recvq_size);
	} else {
		pr_err(KERN_ERR "rx_pending (%d) is out of bounds [%d-%d]\n",
		       ringparam->rx_pending,
		       IPOIB_MIN_QUEUE_SIZE, IPOIB_MAX_QUEUE_SIZE);
		return -EINVAL;
	}

	if (ringparam->tx_pending <= IPOIB_MAX_QUEUE_SIZE &&
	    ringparam->tx_pending >= IPOIB_MIN_QUEUE_SIZE) {
		new_sendq_size = roundup_pow_of_two(ringparam->tx_pending);
		if (ringparam->tx_pending != new_sendq_size)
			pr_warn("%s: %s: tx_pending should be power of two. tx_pending is %d\n",
				dev->name, __func__, new_sendq_size);
	} else {
		pr_err(KERN_ERR "tx_pending (%d) is out of bounds [%d-%d]\n",
		       ringparam->tx_pending,
		       IPOIB_MIN_QUEUE_SIZE, IPOIB_MAX_QUEUE_SIZE);
		return -EINVAL;
	}

	if ((new_recvq_size != priv->recvq_size) ||
	    (new_sendq_size != priv->sendq_size)) {
		priv_current_flags = priv->flags;
		dev_current_flags = dev->flags;

		dev_change_flags(dev, dev->flags & ~IFF_UP);
		ipoib_dev_uninit(dev);

		do {
			priv->recvq_size = new_recvq_size;
			priv->sendq_size = new_sendq_size;
			if (ipoib_ethtool_dev_init(dev)) {
				new_recvq_size >>= 1;
				new_sendq_size >>= 1;
				/* keep the values always legal */
				new_recvq_size = max_t(unsigned int, new_recvq_size, IPOIB_MIN_QUEUE_SIZE);
				new_sendq_size = max_t(unsigned int, new_sendq_size, IPOIB_MIN_QUEUE_SIZE);
			} else {
				init = true;
			}
		} while (!init &&
Exemple #5
0
Fichier : net.c Projet : ctos/bpi
static io_return_t
device_set_status(void *d, dev_flavor_t flavor, dev_status_t status,
		  mach_msg_type_number_t count)
{
  if (flavor == NET_FLAGS)
    {
      if (count != 1)
        return D_INVALID_SIZE;

      short flags = status[0];
      struct net_data *net = (struct net_data *) d;

      dev_change_flags (net->dev, flags);

      /* Change the flags of the Mach device, too. */
      net->ifnet.if_flags = net->dev->flags;
      return D_SUCCESS;
    }

  if(flavor < SIOCIWFIRST || flavor > SIOCIWLAST)
    return D_INVALID_OPERATION;

  if(! IW_IS_SET(flavor))
    return D_INVALID_OPERATION;
  
  if(count * sizeof(int) < sizeof(struct ifreq))
    return D_INVALID_OPERATION;

  struct net_data *nd = d;
  struct linux_device *dev = nd->dev;

  if(! dev->do_ioctl)
    return D_INVALID_OPERATION;

  if((flavor == SIOCSIWENCODE || flavor == SIOCSIWESSID
      || flavor == SIOCSIWNICKN || flavor == SIOCSIWSPY)
     && ((struct iwreq *) status)->u.data.pointer)
    {
      struct iw_point *iwp = &((struct iwreq *) status)->u.data;

      /* safety check whether the status array is long enough ... */
      if(count * sizeof(int) < sizeof(struct ifreq) + iwp->length)
	return D_INVALID_OPERATION;

      /* make sure, iwp->pointer points to the correct address */
      if(iwp->pointer) iwp->pointer = (void *) status + sizeof(struct ifreq);
    }
  
  int result = dev->do_ioctl(dev, (struct ifreq *) status, flavor);
  return result ? D_IO_ERROR : D_SUCCESS;
}
Exemple #6
0
static struct vport *geneve_tnl_create(const struct vport_parms *parms)
{
	struct net *net = ovs_dp_get_net(parms->dp);
	struct nlattr *options = parms->options;
	struct geneve_port *geneve_port;
	struct net_device *dev;
	struct vport *vport;
	struct nlattr *a;
	u16 dst_port;
	int err;

	if (!options) {
		err = -EINVAL;
		goto error;
	}

	a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
	if (a && nla_len(a) == sizeof(u16)) {
		dst_port = nla_get_u16(a);
	} else {
		/* Require destination port from userspace. */
		err = -EINVAL;
		goto error;
	}

	vport = ovs_vport_alloc(sizeof(struct geneve_port),
				&ovs_geneve_vport_ops, parms);
	if (IS_ERR(vport))
		return vport;

	geneve_port = geneve_vport(vport);
	geneve_port->dst_port = dst_port;

	rtnl_lock();
	dev = geneve_dev_create_fb(net, parms->name, NET_NAME_USER, dst_port);
	if (IS_ERR(dev)) {
		rtnl_unlock();
		ovs_vport_free(vport);
		return ERR_CAST(dev);
	}

	dev_change_flags(dev, dev->flags | IFF_UP);
	rtnl_unlock();
	return vport;
error:
	return ERR_PTR(err);
}
int vlan_dev_set_mac_address(struct net_device *dev, void *addr_struct_p)
{
	struct sockaddr *addr = (struct sockaddr *)(addr_struct_p);
	int i;

	if (netif_running(dev))
		return -EBUSY;

	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);

	printk("%s: Setting MAC address to ", dev->name);
	for (i = 0; i < 6; i++)
		printk(" %2.2x", dev->dev_addr[i]);
	printk(".\n");

	if (memcmp(VLAN_DEV_INFO(dev)->real_dev->dev_addr,
		   dev->dev_addr,
		   dev->addr_len) != 0) {
		if (!(VLAN_DEV_INFO(dev)->real_dev->flags & IFF_PROMISC)) {
			int flgs = VLAN_DEV_INFO(dev)->real_dev->flags;

			/* Increment our in-use promiscuity counter */
			dev_set_promiscuity(VLAN_DEV_INFO(dev)->real_dev, 1);

			/* Make PROMISC visible to the user. */
			flgs |= IFF_PROMISC;
			printk("VLAN (%s):  Setting underlying device (%s) to promiscious mode.\n",
			       dev->name, VLAN_DEV_INFO(dev)->real_dev->name);
			dev_change_flags(VLAN_DEV_INFO(dev)->real_dev, flgs);
		}
	} else {
		printk("VLAN (%s):  Underlying device (%s) has same MAC, not checking promiscious mode.\n",
		       dev->name, VLAN_DEV_INFO(dev)->real_dev->name);
	}

	return 0;
}
int android_ioctl_siwpriv(struct net_device *dev,
              struct iw_request_info *__info,
              struct iw_point *data, char *__extra)
{
    char cmd[384]; /* assume that android command will not excess 384 */
    char buf[512];
    int len = sizeof(cmd)-1;
    AR_SOFTC_DEV_T *arPriv = (AR_SOFTC_DEV_T *)ar6k_priv(dev);
    AR_SOFTC_STA_T *arSta = &arPriv->arSta;

    if (!data->pointer) {
        return -EOPNOTSUPP;
    }
    if (data->length < len) {
        len = data->length;
    }
    if (copy_from_user(cmd, data->pointer, len)) {
        return -EIO;
    }
    cmd[len] = 0;

    if (strcasecmp(cmd, "RSSI")==0 || strcasecmp(cmd, "RSSI-APPROX") == 0) {
        int rssi = -200;
        struct iw_statistics *iwStats;
        struct iw_statistics* (*get_iwstats)(struct net_device *);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
        get_iwstats = dev->get_wireless_stats;
#else
        get_iwstats = dev->wireless_handlers->get_wireless_stats;
#endif
        if (get_iwstats && arPriv->arConnected) {
            iwStats = get_iwstats(dev);
            if (iwStats) {
                rssi = iwStats->qual.qual;          
                if (rssi == 255)
                    rssi = -200;
                else
                    rssi += (161 - 256);                
            }
        }
        len = snprintf(buf, data->length, "SSID rssi %d\n", rssi) + 1;
        return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;
    } else if (strcasecmp(cmd, "LINKSPEED")==0) {
        /* We skip to use SIOCGIWRATE since Android always asked LINKSPEED just after RSSI*/
        unsigned int speed_mbps;
        if (arPriv->arConnected) {
            speed_mbps = arPriv->arTargetStats.tx_unicast_rate / 1000;
        } else {
            speed_mbps = 1;
        }
        len = snprintf(buf, data->length, "LinkSpeed %u\n", speed_mbps) + 1;
        return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;
    } else if (memcmp(cmd, "CSCAN S\x01\x00\x00S\x00", 12)==0) {
        int iocmd = SIOCSIWSCAN - SIOCSIWCOMMIT;
        const iw_handler setScan = dev->wireless_handlers->standard[iocmd];
        A_INT32 home_dwell=0, pas_dwell=0, act_dwell=0;
        A_UCHAR ssid[IW_ESSID_MAX_SIZE+1] = { 0 };       
        A_INT32 ssid_len = 0, ie_len;
        A_UINT8 index = 1; /* reserve index 0 for wext */
        A_INT32 ch = 0;
        A_CHAR nprobe, scantype;
        struct iw_freq chList[IW_MAX_FREQUENCIES];
        A_UCHAR *scanBuf = (A_UCHAR*)(cmd + 12);
        A_UCHAR *scanEnd = (A_UCHAR*)(cmd + len);
        A_BOOL broadcastSsid = FALSE;

        while ( scanBuf < scanEnd ) {
            A_UCHAR *sp = scanBuf;
            switch (*scanBuf) {
            case 'S': /* SSID section */
                if (ssid_len > 0 && index < MAX_PROBED_SSID_INDEX) {
                    /* setup the last parsed ssid, reserve index 0 for wext */
                    if (wmi_probedSsid_cmd(arPriv->arWmi, index,
                                           SPECIFIC_SSID_FLAG, ssid_len, ssid) == A_OK) {
                        ++index;
                        if (arSta->scanSpecificSsid<index) {
                            arSta->scanSpecificSsid = index;
                        }
                    }
                }
                ie_len = ((scanBuf + 1) < scanEnd) ? ((A_INT32)*(scanBuf+1) + 1) : 0;
                if ((scanBuf+ie_len) < scanEnd ) {
                    ssid_len = *(scanBuf+1);
                    if (ssid_len == 0) {
                        broadcastSsid = TRUE;
                    } else {
                        A_MEMCPY(ssid, scanBuf+2, ssid_len);
                        ssid[ssid_len] = '\0';
                    }
                }
                scanBuf += 1 + ie_len;
                break;
            case 'C': /* Channel section */
                if (scanBuf+1 < scanEnd) {
                    int value = *(scanBuf+1);
                    if (value == 0) {
                        ch = 0; /* scan for all channels */
                    } else if (ch < IW_MAX_FREQUENCIES) {
                        if (value>1000) {
                            chList[ch].e = 1;
                            chList[ch].m = value * 100000;
                        } else {
                            chList[ch].e = 0;
                            chList[ch].m = value;
                        }
                        ++ch;
                    }
                }
                scanBuf += 2;
                break;
            case 'P': /* Passive dwell section */
                if (scanBuf+2 < scanEnd) {
                    pas_dwell = *(scanBuf+1) + (*(scanBuf+2) << 8);
                }
                scanBuf += 3;
                break;
            case 'H': /* Home dwell section */
                if (scanBuf+2 < scanEnd) {
                    home_dwell = *(scanBuf+1) + (*(scanBuf+2) << 8);
                }
                scanBuf += 3;
                break;
            case 'N': /* Number of probe section */
                if (scanBuf+1 < scanEnd) {
                    nprobe = *(scanBuf+1);
                }
                scanBuf += 2;
                break;
            case 'A': /* Active dwell section */
                if (scanBuf+2 < scanEnd) {
                    act_dwell = *(scanBuf+1) + (*(scanBuf+2) << 8);
                }
                scanBuf += 3;
                break;
            case 'T': /* Scan active type section */
                if (scanBuf+1 < scanEnd) {
                    scantype = *(scanBuf+1);
                }
                scanBuf += 2;
                break;
            default:
                break;
            }
            if (sp == scanBuf) {
                return -1; /* parsing error */
            }
        }

        if (ssid_len>0) {
            A_UINT8 idx; /* Clean up the last specific scan items */
            for (idx=index; idx<arSta->scanSpecificSsid; ++idx) {
                wmi_probedSsid_cmd(arPriv->arWmi, idx, DISABLE_SSID_FLAG, 0, NULL);
            }
            arSta->scanSpecificSsid = index;
            /* 
             * There is no way to know when we need to send broadcast probe in current Android wpa_supplicant_6 
             * combo scan implemenation. Always force to sent it here uniti future Android version will set
             * the broadcast flags for combo scan.
             */
#if 0
            if (broadcastSsid)
#endif
            {
                /* setup the last index as broadcast SSID for combo scan */
                ++arSta->scanSpecificSsid;
                wmi_probedSsid_cmd(arPriv->arWmi, index, ANY_SSID_FLAG, 0, NULL);
            }
        }

        if (pas_dwell>0) {
            /* TODO: Should we change our passive dwell? There may be some impact for bt-coex */
        }

        if (home_dwell>0) {
            /* TODO: Should we adjust home_dwell? How to pass it to wext handler? */
        }

        if (setScan) {
            union iwreq_data miwr;
            struct iw_request_info minfo;
            struct iw_scan_req scanreq, *pScanReq = NULL;
            A_MEMZERO(&minfo, sizeof(minfo));
            A_MEMZERO(&miwr, sizeof(miwr));            
            A_MEMZERO(&scanreq, sizeof(scanreq));
            if (ssid_len > 0) {
                pScanReq = &scanreq;
                memcpy(scanreq.essid, ssid, ssid_len);
                scanreq.essid_len = ssid_len;
                miwr.data.flags |= IW_SCAN_THIS_ESSID;
            }
            if (ch > 0) {
                pScanReq = &scanreq;
                scanreq.num_channels = ch;
                memcpy(scanreq.channel_list, chList, ch * sizeof(chList[0]));
                miwr.data.flags |= IW_SCAN_THIS_FREQ;
            }
            if (pScanReq) {
                miwr.data.pointer = (__force void __user *)&scanreq;
                miwr.data.length = sizeof(scanreq);
            }
            minfo.cmd = SIOCSIWSCAN;
            return setScan(dev, &minfo, &miwr, (char*)pScanReq);
        }
        return -1;
    } else if (strcasecmp(cmd, "MACADDR")==0) {
        /* reply comes back in the form "Macaddr = XX:XX:XX:XX:XX:XX" where XX */
        A_UCHAR *mac = dev->dev_addr;
        len = snprintf(buf, data->length, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
                        mac[0], mac[1], mac[2],
                        mac[3], mac[4], mac[5]) + 1;
        return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;
    } else if (strcasecmp(cmd, "SCAN-ACTIVE")==0) {
        return 0; /* unsupport function. Suppress the error */
    } else if (strcasecmp(cmd, "SCAN-PASSIVE")==0) {
        return 0; /* unsupport function. Suppress the error */
    } else if (strcasecmp(cmd, "START")==0 || strcasecmp(cmd, "STOP")==0) {
        struct ifreq ifr;
        char userBuf[16];
        int ex_arg = (strcasecmp(cmd, "START")==0) ? WLAN_ENABLED : WLAN_DISABLED;
        int ret;
        A_MEMZERO(userBuf, sizeof(userBuf));
        ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_SET_WLAN_STATE;
        ((int *)userBuf)[1] = ex_arg;
        ret = android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf);
        if (ret==0) {
            /* Send wireless event which need by android supplicant */
            union iwreq_data wrqu;
            A_MEMZERO(&wrqu, sizeof(wrqu));
            wrqu.data.length = strlen(cmd);
            wireless_send_event(dev, IWEVCUSTOM, &wrqu, cmd);
        }
        return ret;
    } else if (strncasecmp(cmd, "POWERMODE ", 10)==0) {
        int mode;
        if (sscanf(cmd, "%*s %d", &mode) == 1) {
            int iocmd = SIOCSIWPOWER - SIOCSIWCOMMIT;
            iw_handler setPower = dev->wireless_handlers->standard[iocmd];
            if (setPower) {
                union iwreq_data miwr;
                struct iw_request_info minfo;
                A_MEMZERO(&minfo, sizeof(minfo));
                A_MEMZERO(&miwr, sizeof(miwr));
                minfo.cmd = SIOCSIWPOWER;
                if (mode == 0 /* auto */)
                    miwr.power.disabled = 0;
                else if (mode == 1 /* active */)
                    miwr.power.disabled = 1;
                else
                    return -1;
                return setPower(dev, &minfo, &miwr, NULL);
            }
        }
        return -1;
    } else if (strcasecmp(cmd, "GETPOWER")==0) {
        struct ifreq ifr;
        int userBuf[2];
        A_MEMZERO(userBuf, sizeof(userBuf));
        ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_GET_POWER_MODE;
        if (android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf)>=0) {
            WMI_POWER_MODE_CMD *getPowerMode = (WMI_POWER_MODE_CMD *)userBuf;
            len = snprintf(buf, data->length, "powermode = %u\n", 
                           (getPowerMode->powerMode==MAX_PERF_POWER) ? 1/*active*/ : 0/*auto*/) + 1;
            return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;        
        }
        return -1;
    } else if (strncasecmp(cmd, "SETSUSPENDOPT ", 14)==0) {
        int enable;
        if (sscanf(cmd, "%*s %d", &enable)==1) {
            /* 
             * We set our suspend mode by wlan_config.h now. 
             * Should we follow Android command?? TODO
             */
            return 0;
        }
        return -1;
    } else if (strcasecmp(cmd, "SCAN-CHANNELS")==0) {
        // reply comes back in the form "Scan-Channels = X" where X is the number of channels        
        int iocmd = SIOCGIWRANGE - SIOCSIWCOMMIT;
        iw_handler getRange = dev->wireless_handlers->standard[iocmd];            
        if (getRange) {
            union iwreq_data miwr;
            struct iw_request_info minfo;
            struct iw_range range;
            A_MEMZERO(&minfo, sizeof(minfo));
            A_MEMZERO(&miwr, sizeof(miwr));
            A_MEMZERO(&range, sizeof(range));
            minfo.cmd = SIOCGIWRANGE;
            miwr.data.pointer = (__force void __user *) &range;
            miwr.data.length = sizeof(range);
            getRange(dev, &minfo, &miwr, (char*)&range);
        }
        if (arSta->arNumChannels!=-1) {
            len = snprintf(buf, data->length, "Scan-Channels = %d\n", arSta->arNumChannels) + 1;
            return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;
        }
        return -1;
    } else if (strncasecmp(cmd, "SCAN-CHANNELS ", 14)==0 || 
               strncasecmp(cmd, "COUNTRY ", 8)==0) {
        /* 
         * Set the available channels with WMI_SET_CHANNELPARAMS cmd
         * However, the channels will be limited by the eeprom regulator domain
         * Try to use a regulator domain which will not limited the channels range.
         */
        int i;
        int chan = 0;
        A_UINT16 *clist;
        struct ifreq ifr; 
        char ioBuf[256];
        WMI_CHANNEL_PARAMS_CMD *chParamCmd = (WMI_CHANNEL_PARAMS_CMD *)ioBuf;
        if (strncasecmp(cmd, "COUNTRY ", 8)==0) {
            char *country = cmd + 8;
            if (strcasecmp(country, "US")==0) {
                chan = 11;
            } else if (strcasecmp(country, "JP")==0) {
                chan = 14;
            } else if (strcasecmp(country, "EU")==0) {
                chan = 13;
            }
        } else if (sscanf(cmd, "%*s %d", &chan) != 1) {
            return -1;
        }
        if ( (chan != 11) && (chan != 13) && (chan != 14)) {
            return -1;
        }
        if (arPriv->arNextMode == AP_NETWORK) {
            return -1;
        }
        A_MEMZERO(&ifr, sizeof(ifr));
        A_MEMZERO(ioBuf, sizeof(ioBuf));

        chParamCmd->phyMode = WMI_11G_MODE;
        clist = chParamCmd->channelList;
        chParamCmd->numChannels = chan;
        chParamCmd->scanParam = 1;        
        for (i = 0; i < chan; i++) {
            clist[i] = wlan_ieee2freq(i + 1);
        }
        
        return android_do_ioctl_direct(dev, AR6000_IOCTL_WMI_SET_CHANNELPARAMS, &ifr, ioBuf);
    } else if (strncasecmp(cmd, "BTCOEXMODE ", 11)==0) {
        int mode;
        if (sscanf(cmd, "%*s %d", &mode)==1) {
            /* 
            * Android disable BT-COEX when obtaining dhcp packet except there is headset is connected 
             * It enable the BT-COEX after dhcp process is finished
             * We ignore since we have our way to do bt-coex during dhcp obtaining.
             */
            switch (mode) {
            case 1: /* Disable*/
                break;
            case 0: /* Enable */
                /* fall through */
            case 2: /* Sense*/
                /* fall through */
            default:
                break;
            }
            return 0; /* ignore it */
        }
        return -1;
    } else if (strcasecmp(cmd, "BTCOEXSCAN-START")==0) {
        /* Android enable or disable Bluetooth coexistence scan mode. When this mode is on,
         * some of the low-level scan parameters used by the driver are changed to
         * reduce interference with A2DP streaming.
         */
        return 0; /* ignore it since we have btfilter  */
    } else if (strcasecmp(cmd, "BTCOEXSCAN-STOP")==0) {
        return 0; /* ignore it since we have btfilter  */
    } else if (strncasecmp(cmd, "RXFILTER-ADD ", 13)==0) {
        return 0; /* ignore it */
    } else if (strncasecmp(cmd, "RXFILTER-REMOVE ", 16)==0) {
        return 0; /* ignoret it */
    } else if (strcasecmp(cmd, "RXFILTER-START")==0 || strcasecmp(cmd, "RXFILTER-STOP")==0) {
        unsigned int flags = dev->flags;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
        int mc_count = dev->mc_count;   
#else
        int mc_count = netdev_mc_count(dev);
#endif
        if (strcasecmp(cmd, "RXFILTER-START")==0) {
            if (mc_count > 0 || (flags & IFF_MULTICAST) ) {
                flags &= ~IFF_MULTICAST;
            }
        } else {
            flags |= IFF_MULTICAST;
        }
        if (flags != dev->flags) {
            dev_change_flags(dev, flags);
        }
        return 0;
    }

    return -EOPNOTSUPP;
}
int android_ioctl_siwpriv(struct net_device *dev,
              struct iw_request_info *__info,
              struct iw_point *data, char *__extra)
{
    char *cmd = data->pointer;
    char *buf = data->pointer;
    AR_SOFTC_T *ar = (AR_SOFTC_T *)ar6k_priv(dev);

    if (!cmd || !buf) {
        return -EOPNOTSUPP;
    }
    if (strcasecmp(cmd, "RSSI")==0 || strcasecmp(cmd, "RSSI-APPROX") == 0) {
        int rssi = 255;
        struct iw_statistics *iwStats;
        struct iw_statistics* (*get_iwstats)(struct net_device *);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
        get_iwstats = dev->get_wireless_stats;
#else
        get_iwstats = dev->wireless_handlers->get_wireless_stats;
#endif
        iwStats = get_iwstats(dev);
        if (iwStats) {
            rssi = iwStats->qual.qual;          
            if (rssi == 255)
                rssi = -200;
            else
                rssi += (161 - 256);                
        }
        return snprintf(buf, data->length, "SSID rssi %d\n", rssi);               
    } else if (strcasecmp(cmd, "LINKSPEED")==0) {
        int iocmd = SIOCGIWRATE - SIOCSIWCOMMIT;
        const iw_handler getRate = dev->wireless_handlers->standard[iocmd];
        if (getRate) {
            union iwreq_data miwr;
            struct iw_request_info minfo;
            A_MEMZERO(&minfo, sizeof(minfo));
            A_MEMZERO(&miwr, sizeof(miwr));
            minfo.cmd = SIOCGIWRATE;
            if (getRate(dev, &minfo, &miwr, NULL) == 0) {
                unsigned int speed_kbps = miwr.param.value / 1000000;
                if ((!miwr.param.fixed)) {
                    return snprintf(buf, data->length, "LinkSpeed %u\n", speed_kbps);
                }
            }
        }
        return -1;
    } else if (strcasecmp(cmd, "MACADDR")==0) {
        /* reply comes back in the form "Macaddr = XX.XX.XX.XX.XX.XX" where XX */
        A_UCHAR *mac = dev->dev_addr;
        return snprintf(buf, data->length, "Macaddr = %02X.%02X.%02X.%02X.%02X.%02X\n",
                        mac[0], mac[1], mac[2],
                        mac[3], mac[4], mac[5]);
    } else if (strcasecmp(cmd, "SCAN-ACTIVE")==0) {
        return 0; /* unsupport function. Suppress the error */
    } else if (strcasecmp(cmd, "SCAN-PASSIVE")==0) {
        return 0; /* unsupport function. Suppress the error */
    } else if (strcasecmp(cmd, "START")==0 || strcasecmp(cmd, "STOP")==0) {
        struct ifreq ifr;
        char userBuf[16];
        int ex_arg = (strcasecmp(cmd, "START")==0) ? WLAN_ENABLED : WLAN_DISABLED;

        A_MEMZERO(userBuf, sizeof(userBuf));
        ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_SET_WLAN_STATE;
        ((int *)userBuf)[1] = ex_arg;
        return android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf);
    } else if (strncasecmp(cmd, "POWERMODE ", 10)==0) {
        int mode;
        if (sscanf(cmd, "%*s %d", &mode) == 1) {
            int iocmd = SIOCSIWPOWER - SIOCSIWCOMMIT;
            iw_handler setPower = dev->wireless_handlers->standard[iocmd];
            if (setPower) {
                union iwreq_data miwr;
                struct iw_request_info minfo;
                A_MEMZERO(&minfo, sizeof(minfo));
                A_MEMZERO(&miwr, sizeof(miwr));
                minfo.cmd = SIOCSIWPOWER;
                if (mode == 0 /* auto */)
                    miwr.power.disabled = 0;
                else if (mode == 1 /* active */)
                    miwr.power.disabled = 1;
                else
                    return -1;
                return setPower(dev, &minfo, &miwr, NULL);
            }
        }
        return -1;
    } else if (strcasecmp(cmd, "SCAN-CHANNELS")==0) {
        /* reply comes back in the form "Scan-Channels = X" where X is the number of channels         */
        int iocmd = SIOCGIWRANGE - SIOCSIWCOMMIT;
        iw_handler getRange = dev->wireless_handlers->standard[iocmd];            
        if (getRange) {
            union iwreq_data miwr;
            struct iw_request_info minfo;
            struct iw_range range;
            A_MEMZERO(&minfo, sizeof(minfo));
            A_MEMZERO(&miwr, sizeof(miwr));
            A_MEMZERO(&range, sizeof(range));
            minfo.cmd = SIOCGIWRANGE;
            miwr.data.pointer = (caddr_t) &range;
            miwr.data.length = sizeof(range);
            getRange(dev, &minfo, &miwr, (char*)&range);
        }
        if (ar->arNumChannels!=-1) {
            return snprintf(buf, data->length, "Scan-Channels = %d\n", ar->arNumChannels);
        }
        return -1;
    } else if (strncasecmp(cmd, "SCAN-CHANNELS ", 14)==0 || 
               strncasecmp(cmd, "COUNTRY ", 8)==0) {
        /* 
         * Set the available channels with WMI_SET_CHANNELPARAMS cmd
         * However, the channels will be limited by the eeprom regulator domain
         * Try to use a regulator domain which will not limited the channels range.
         */
        int i;
        int chan = 0;
        A_UINT16 *clist;
        struct ifreq ifr; 
        char ioBuf[256];
        WMI_CHANNEL_PARAMS_CMD *chParamCmd = (WMI_CHANNEL_PARAMS_CMD *)ioBuf;
        if (strncasecmp(cmd, "COUNTRY ", 8)==0) {
            char *country = cmd + 8;
            if (strcasecmp(country, "US")==0) {
                chan = 11;
            } else if (strcasecmp(country, "JP")==0) {
                chan = 14;
            } else if (strcasecmp(country, "EU")==0) {
                chan = 13;
            }
        } else if (sscanf(cmd, "%*s %d", &chan) != 1) {
            return -1;
        }
        if ( (chan != 11) && (chan != 13) && (chan != 14)) {
            return -1;
        }
        if (ar->arNextMode == AP_NETWORK) {
            return -1;
        }
        A_MEMZERO(&ifr, sizeof(ifr));
        A_MEMZERO(ioBuf, sizeof(ioBuf));

        chParamCmd->phyMode = WMI_11G_MODE;
        clist = chParamCmd->channelList;
        chParamCmd->numChannels = chan;
        chParamCmd->scanParam = 1;        
        for (i = 0; i < chan; i++) {
            clist[i] = wlan_ieee2freq(i + 1);
        }
        
        return android_do_ioctl_direct(dev, AR6000_IOCTL_WMI_SET_CHANNELPARAMS, &ifr, ioBuf);
    } else if (strncasecmp(cmd, "BTCOEXMODE ", 11)==0) {
        int mode;
        if (sscanf(cmd, "%*s %d", &mode)==1) {
            /* 
            * Android disable BT-COEX when obtaining dhcp packet except there is headset is connected 
             * It enable the BT-COEX after dhcp process is finished
             * We ignore since we have our way to do bt-coex during dhcp obtaining.
             */
            switch (mode) {
            case 1: /* Disable*/
                break;
            case 0: /* Enable */
                /* fall through */
            case 2: /* Sense*/
                /* fall through */
            default:
                break;
            }
            return 0; /* ignore it */
        }
        return -1;
    } else if (strcasecmp(cmd, "BTCOEXSCAN-START")==0) {
        /* Android enable or disable Bluetooth coexistence scan mode. When this mode is on,
         * some of the low-level scan parameters used by the driver are changed to
         * reduce interference with A2DP streaming.
         */
        return 0; /* ignore it since we have btfilter  */
    } else if (strcasecmp(cmd, "BTCOEXSCAN-STOP")==0) {
        return 0; /* ignore it since we have btfilter  */
    } else if (strncasecmp(cmd, "RXFILTER-ADD ", 13)==0) {
        return 0; /* ignore it */
    } else if (strncasecmp(cmd, "RXFILTER-REMOVE ", 16)==0) {
        return 0; /* ignoret it */
    } else if (strcasecmp(cmd, "RXFILTER-START")==0 || strcasecmp(cmd, "RXFILTER-STOP")==0) {
        unsigned int flags = dev->flags;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
        int mc_count = dev->mc_count;   
#else
        int mc_count = netdev_mc_count(dev);
#endif           
        if (!(flags & IFF_UP)) {
            return -1;
        }
        if (strcasecmp(cmd, "RXFILTER-START")==0) {
            if (mc_count > 0 || (flags & IFF_MULTICAST) ) {
                flags &= ~IFF_MULTICAST;
            }
        } else {
            flags |= IFF_MULTICAST;
        }
        if (flags != dev->flags) {
            dev_change_flags(dev, flags);
        }
        return 0;
    }

    return -EOPNOTSUPP;
}
static int vlan_device_event(struct notifier_block *unused, unsigned long event,
			     void *ptr)
{
	struct net_device *dev = ptr;
	struct vlan_group *grp;
	struct vlan_info *vlan_info;
	int i, flgs;
	struct net_device *vlandev;
	struct vlan_dev_priv *vlan;
	LIST_HEAD(list);

	if (is_vlan_dev(dev))
		__vlan_device_event(dev, event);

	if ((event == NETDEV_UP) &&
	    (dev->features & NETIF_F_HW_VLAN_FILTER)) {
		pr_info("adding VLAN 0 to HW filter on device %s\n",
			dev->name);
		vlan_vid_add(dev, 0);
	}

	vlan_info = rtnl_dereference(dev->vlan_info);
	if (!vlan_info)
		goto out;
	grp = &vlan_info->grp;


	switch (event) {
	case NETDEV_CHANGE:
		
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			netif_stacked_transfer_operstate(dev, vlandev);
		}
		break;

	case NETDEV_CHANGEADDR:
		
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			flgs = vlandev->flags;
			if (!(flgs & IFF_UP))
				continue;

			vlan_sync_address(dev, vlandev);
		}
		break;

	case NETDEV_CHANGEMTU:
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			if (vlandev->mtu <= dev->mtu)
				continue;

			dev_set_mtu(vlandev, dev->mtu);
		}
		break;

	case NETDEV_FEAT_CHANGE:
		
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			vlan_transfer_features(dev, vlandev);
		}

		break;

	case NETDEV_DOWN:
		
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			flgs = vlandev->flags;
			if (!(flgs & IFF_UP))
				continue;

			vlan = vlan_dev_priv(vlandev);
			if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
				dev_change_flags(vlandev, flgs & ~IFF_UP);
			netif_stacked_transfer_operstate(dev, vlandev);
		}
		break;

	case NETDEV_UP:
		
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			flgs = vlandev->flags;
			if (flgs & IFF_UP)
				continue;

			vlan = vlan_dev_priv(vlandev);
			if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
				dev_change_flags(vlandev, flgs | IFF_UP);
			netif_stacked_transfer_operstate(dev, vlandev);
		}
		break;

	case NETDEV_UNREGISTER:
		
		if (dev->reg_state != NETREG_UNREGISTERING)
			break;

		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			if (vlan_info->nr_vids == 1)
				i = VLAN_N_VID;

			unregister_vlan_dev(vlandev, &list);
		}
		unregister_netdevice_many(&list);
		break;

	case NETDEV_PRE_TYPE_CHANGE:
		
		return NOTIFY_BAD;

	case NETDEV_NOTIFY_PEERS:
	case NETDEV_BONDING_FAILOVER:
		
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			call_netdevice_notifiers(event, vlandev);
		}
		break;
	}

out:
	return NOTIFY_DONE;
}
Exemple #11
0
static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
    struct ifinfomsg  *ifm = NLMSG_DATA(nlh);
    struct rtattr    **ida = arg;
    struct net_device *dev;
    int err, send_addr_notify = 0;

    if (ifm->ifi_index >= 0)
        dev = dev_get_by_index(ifm->ifi_index);
    else if (ida[IFLA_IFNAME - 1]) {
        char ifname[IFNAMSIZ];

        if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
                           IFNAMSIZ) >= IFNAMSIZ)
            return -EINVAL;
        dev = dev_get_by_name(ifname);
    } else
        return -EINVAL;

    if (!dev)
        return -ENODEV;

    err = -EINVAL;

    if (ifm->ifi_flags)
        dev_change_flags(dev, ifm->ifi_flags);

    if (ida[IFLA_MAP - 1]) {
        struct rtnl_link_ifmap *u_map;
        struct ifmap k_map;

        if (!dev->set_config) {
            err = -EOPNOTSUPP;
            goto out;
        }

        if (!netif_device_present(dev)) {
            err = -ENODEV;
            goto out;
        }

        if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(*u_map)))
            goto out;

        u_map = RTA_DATA(ida[IFLA_MAP - 1]);

        k_map.mem_start = (unsigned long) u_map->mem_start;
        k_map.mem_end = (unsigned long) u_map->mem_end;
        k_map.base_addr = (unsigned short) u_map->base_addr;
        k_map.irq = (unsigned char) u_map->irq;
        k_map.dma = (unsigned char) u_map->dma;
        k_map.port = (unsigned char) u_map->port;

        err = dev->set_config(dev, &k_map);

        if (err)
            goto out;
    }

    if (ida[IFLA_ADDRESS - 1]) {
        struct sockaddr *sa;
        int len;

        if (!dev->set_mac_address) {
            err = -EOPNOTSUPP;
            goto out;
        }
        if (!netif_device_present(dev)) {
            err = -ENODEV;
            goto out;
        }
        if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len))
            goto out;

        len = sizeof(sa_family_t) + dev->addr_len;
        sa = kmalloc(len, GFP_KERNEL);
        if (!sa) {
            err = -ENOMEM;
            goto out;
        }
        sa->sa_family = dev->type;
        memcpy(sa->sa_data, RTA_DATA(ida[IFLA_ADDRESS - 1]),
               dev->addr_len);
        err = dev->set_mac_address(dev, sa);
        kfree(sa);
        if (err)
            goto out;
        send_addr_notify = 1;
    }

    if (ida[IFLA_BROADCAST - 1]) {
        if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len))
            goto out;
        memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]),
               dev->addr_len);
        send_addr_notify = 1;
    }

    if (ida[IFLA_MTU - 1]) {
        if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
            goto out;
        err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1])));

        if (err)
            goto out;

    }

    if (ida[IFLA_TXQLEN - 1]) {
        if (ida[IFLA_TXQLEN - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
            goto out;

        dev->tx_queue_len = *((u32 *) RTA_DATA(ida[IFLA_TXQLEN - 1]));
    }

    if (ida[IFLA_WEIGHT - 1]) {
        if (ida[IFLA_WEIGHT - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
            goto out;

        dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1]));
    }

    if (ida[IFLA_OPERSTATE - 1]) {
        if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
            goto out;

        set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1])));
    }

    if (ida[IFLA_LINKMODE - 1]) {
        if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8)))
            goto out;

        write_lock_bh(&dev_base_lock);
        dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1]));
        write_unlock_bh(&dev_base_lock);
    }

    if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
        char ifname[IFNAMSIZ];

        if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
                           IFNAMSIZ) >= IFNAMSIZ)
            goto out;
        err = dev_change_name(dev, ifname);
        if (err)
            goto out;
    }

#ifdef CONFIG_NET_WIRELESS_RTNETLINK
    if (ida[IFLA_WIRELESS - 1]) {

        /* Call Wireless Extensions.
         * Various stuff checked in there... */
        err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len);
        if (err)
            goto out;
    }
#endif	/* CONFIG_NET_WIRELESS_RTNETLINK */

    err = 0;

out:
    if (send_addr_notify)
        call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);

    dev_put(dev);
    return err;
}
Exemple #12
0
int devinet_ioctl(unsigned int cmd, void *arg)
{
	struct ifreq ifr;
	struct sockaddr_in sin_orig;
	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
	struct in_device *in_dev;
	struct in_ifaddr **ifap = NULL;
	struct in_ifaddr *ifa = NULL;
	struct net_device *dev;
	char *colon;
	int ret = 0;
	int tryaddrmatch = 0;

	/*
	 *	Fetch the caller's info block into kernel space
	 */

	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
		return -EFAULT;
	ifr.ifr_name[IFNAMSIZ-1] = 0;

	/* save original address for comparison */
	memcpy(&sin_orig, sin, sizeof(*sin));

	colon = strchr(ifr.ifr_name, ':');
	if (colon)
		*colon = 0;

#ifdef CONFIG_KMOD
	dev_load(ifr.ifr_name);
#endif

	switch(cmd) {
	case SIOCGIFADDR:	/* Get interface address */
	case SIOCGIFBRDADDR:	/* Get the broadcast address */
	case SIOCGIFDSTADDR:	/* Get the destination address */
	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
		/* Note that these ioctls will not sleep,
		   so that we do not impose a lock.
		   One day we will be forced to put shlock here (I mean SMP)
		 */
		tryaddrmatch = (sin_orig.sin_family == AF_INET);
		memset(sin, 0, sizeof(*sin));
		sin->sin_family = AF_INET;
		break;

	case SIOCSIFFLAGS:
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;
		break;
	case SIOCSIFADDR:	/* Set interface address (and family) */
	case SIOCSIFBRDADDR:	/* Set the broadcast address */
	case SIOCSIFDSTADDR:	/* Set the destination address */
	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
		if (!capable(CAP_NET_ADMIN))
			return -EACCES;
		if (sin->sin_family != AF_INET)
			return -EINVAL;
		break;
	default:
		return -EINVAL;
	}

	dev_probe_lock();
	rtnl_lock();

	if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) {
		ret = -ENODEV;
		goto done;
	}

	if (colon)
		*colon = ':';

	if ((in_dev=__in_dev_get(dev)) != NULL) {
		if (tryaddrmatch) {
			/* Matthias Andree */
			/* compare label and address (4.4BSD style) */
			/* note: we only do this for a limited set of ioctls
			   and only if the original address family was AF_INET.
			   This is checked above. */
			for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next) {
				if ((strcmp(ifr.ifr_name, ifa->ifa_label) == 0)
				    && (sin_orig.sin_addr.s_addr == ifa->ifa_address)) {
					break; /* found */
				}
			}
		}
		/* we didn't get a match, maybe the application is
		   4.3BSD-style and passed in junk so we fall back to 
		   comparing just the label */
		if (ifa == NULL) {
			for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next)
				if (strcmp(ifr.ifr_name, ifa->ifa_label) == 0)
					break;
		}
	}

	if (ifa == NULL && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) {
		ret = -EADDRNOTAVAIL;
		goto done;
	}

	switch(cmd) {
		case SIOCGIFADDR:	/* Get interface address */
			sin->sin_addr.s_addr = ifa->ifa_local;
			goto rarok;

		case SIOCGIFBRDADDR:	/* Get the broadcast address */
			sin->sin_addr.s_addr = ifa->ifa_broadcast;
			goto rarok;

		case SIOCGIFDSTADDR:	/* Get the destination address */
			sin->sin_addr.s_addr = ifa->ifa_address;
			goto rarok;

		case SIOCGIFNETMASK:	/* Get the netmask for the interface */
			sin->sin_addr.s_addr = ifa->ifa_mask;
			goto rarok;

		case SIOCSIFFLAGS:
			if (colon) {
				if (ifa == NULL) {
					ret = -EADDRNOTAVAIL;
					break;
				}
				if (!(ifr.ifr_flags&IFF_UP))
					inet_del_ifa(in_dev, ifap, 1);
				break;
			}
			ret = dev_change_flags(dev, ifr.ifr_flags);
			break;
	
		case SIOCSIFADDR:	/* Set interface address (and family) */
			if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
				ret = -EINVAL;
				break;
			}

			if (!ifa) {
				if ((ifa = inet_alloc_ifa()) == NULL) {
					ret = -ENOBUFS;
					break;
				}
				if (colon)
					memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
				else
					memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
			} else {
				ret = 0;
				if (ifa->ifa_local == sin->sin_addr.s_addr)
					break;
				inet_del_ifa(in_dev, ifap, 0);
				ifa->ifa_broadcast = 0;
				ifa->ifa_anycast = 0;
			}

			ifa->ifa_address =
			ifa->ifa_local = sin->sin_addr.s_addr;

			if (!(dev->flags&IFF_POINTOPOINT)) {
				ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
				ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
				if ((dev->flags&IFF_BROADCAST) && ifa->ifa_prefixlen < 31)
					ifa->ifa_broadcast = ifa->ifa_address|~ifa->ifa_mask;
			} else {
				ifa->ifa_prefixlen = 32;
				ifa->ifa_mask = inet_make_mask(32);
			}
			ret = inet_set_ifa(dev, ifa);
			break;

		case SIOCSIFBRDADDR:	/* Set the broadcast address */
			if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
				inet_del_ifa(in_dev, ifap, 0);
				ifa->ifa_broadcast = sin->sin_addr.s_addr;
				inet_insert_ifa(ifa);
			}
			break;
	
		case SIOCSIFDSTADDR:	/* Set the destination address */
			if (ifa->ifa_address != sin->sin_addr.s_addr) {
				if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
					ret = -EINVAL;
					break;
				}
				inet_del_ifa(in_dev, ifap, 0);
				ifa->ifa_address = sin->sin_addr.s_addr;
				inet_insert_ifa(ifa);
			}
			break;

		case SIOCSIFNETMASK: 	/* Set the netmask for the interface */

			/*
			 *	The mask we set must be legal.
			 */
			if (bad_mask(sin->sin_addr.s_addr, 0)) {
				ret = -EINVAL;
				break;
			}

			if (ifa->ifa_mask != sin->sin_addr.s_addr) {
				inet_del_ifa(in_dev, ifap, 0);
				ifa->ifa_mask = sin->sin_addr.s_addr;
				ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
				inet_insert_ifa(ifa);
			}
			break;
	}
done:
	rtnl_unlock();
	dev_probe_unlock();
	return ret;

rarok:
	rtnl_unlock();
	dev_probe_unlock();
	if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
		return -EFAULT;
	return 0;
}
Exemple #13
0
int android_ioctl_siwpriv(struct net_device *dev,
              struct iw_request_info *__info,
              struct iw_point *data, char *__extra)
{
    char cmd[32]; /* assume that android command will not excess 32 */
    char buf[32];
    char *cmdbuf;
    int len = sizeof(cmd)-1;
    AR_SOFTC_DEV_T *arPriv = (AR_SOFTC_DEV_T *)ar6k_priv(dev);
    AR_SOFTC_STA_T *arSta = &arPriv->arSta;

    if (!data->pointer) {
        return -EOPNOTSUPP;
    }
    if (data->length < len) {
        len = data->length;
    }
    if (copy_from_user(cmd, data->pointer, len)) {
        return -EIO;
    }
    cmd[len] = 0;

    if (strcasecmp(cmd, "RSSI")==0 || strcasecmp(cmd, "RSSI-APPROX") == 0) {
        int rssi = -200;
        struct iw_statistics *iwStats;
        struct iw_statistics* (*get_iwstats)(struct net_device *);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
        get_iwstats = dev->get_wireless_stats;
#else
        get_iwstats = dev->wireless_handlers->get_wireless_stats;
#endif
        if (get_iwstats && arPriv->arConnected) {
            iwStats = get_iwstats(dev);
            if (iwStats) {
                rssi = iwStats->qual.qual;          
                if (rssi == 255)
                    rssi = -200;
                else
                    rssi += (161 - 256);                
            }
        }
        len = snprintf(buf, data->length, "SSID rssi %d\n", rssi) + 1;
        return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;
    } else if (strcasecmp(cmd, "LINKSPEED")==0) {
        /* We skip to use SIOCGIWRATE since Android always asked LINKSPEED just after RSSI*/
        unsigned int speed_mbps;
        if (arPriv->arConnected) {
            speed_mbps = arPriv->arTargetStats.tx_unicast_rate / 1000;
        } else {
            speed_mbps = 1;
        }
        len = snprintf(buf, data->length, "LinkSpeed %u\n", speed_mbps) + 1;
        return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;
    } else if (memcmp(cmd, "CSCAN S\x01\x00\x00S\x00", 12)==0) {

		int ret=0;

        if (!(cmdbuf = A_MALLOC(data->length)))
            return -ENOMEM;

        if (copy_from_user(cmdbuf, data->pointer, data->length)) {
            A_FREE(cmdbuf);
            return -EFAULT;
        }

        ret = ar6000_cscan(dev,data, cmdbuf);

        A_FREE(cmdbuf);
        return ret;
        
    } else if (strcasecmp(cmd, "MACADDR")==0) {
        /* reply comes back in the form "Macaddr = XX:XX:XX:XX:XX:XX" where XX */
        A_UCHAR *mac = dev->dev_addr;
        len = snprintf(buf, data->length, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
                        mac[0], mac[1], mac[2],
                        mac[3], mac[4], mac[5]) + 1;
        return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;
    } else if (strcasecmp(cmd, "SCAN-ACTIVE")==0) {
        return 0; /* unsupport function. Suppress the error */
    } else if (strcasecmp(cmd, "SCAN-PASSIVE")==0) {
        return 0; /* unsupport function. Suppress the error */
    } else if (strcasecmp(cmd, "START")==0 || strcasecmp(cmd, "STOP")==0) {
        struct ifreq ifr;
        char userBuf[16];
        int ex_arg = (strcasecmp(cmd, "START")==0) ? WLAN_ENABLED : WLAN_DISABLED;
        int ret;
        A_MEMZERO(userBuf, sizeof(userBuf));
        ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_SET_WLAN_STATE;
        ((int *)userBuf)[1] = ex_arg;
        ret = android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf);
        if (ret==0) {
            /* Send wireless event which need by android supplicant */
            union iwreq_data wrqu;
            A_MEMZERO(&wrqu, sizeof(wrqu));
            wrqu.data.length = strlen(cmd);
            wireless_send_event(dev, IWEVCUSTOM, &wrqu, cmd);
        }
        return ret;
    } else if (strncasecmp(cmd, "POWERMODE ", 10)==0) {
        int mode;
        if (sscanf(cmd, "%*s %d", &mode) == 1) {
            int iocmd = SIOCSIWPOWER - SIOCSIWCOMMIT;
            iw_handler setPower = dev->wireless_handlers->standard[iocmd];
            if (setPower) {
                union iwreq_data miwr;
                struct iw_request_info minfo;
                A_MEMZERO(&minfo, sizeof(minfo));
                A_MEMZERO(&miwr, sizeof(miwr));
                minfo.cmd = SIOCSIWPOWER;
                if (mode == 0 /* auto */)
                    miwr.power.disabled = 0;
                else if (mode == 1 /* active */)
                    miwr.power.disabled = 1;
                else
                    return -1;
                return setPower(dev, &minfo, &miwr, NULL);
            }
        }
        return -1;
    } else if (strcasecmp(cmd, "GETPOWER")==0) {
        struct ifreq ifr;
        int userBuf[2];
        A_MEMZERO(userBuf, sizeof(userBuf));
        ((int *)userBuf)[0] = AR6000_XIOCTRL_WMI_GET_POWER_MODE;
        if (android_do_ioctl_direct(dev, AR6000_IOCTL_EXTENDED, &ifr, userBuf)>=0) {
            WMI_POWER_MODE_CMD *getPowerMode = (WMI_POWER_MODE_CMD *)userBuf;
            len = snprintf(buf, data->length, "powermode = %u\n", 
                           (getPowerMode->powerMode==MAX_PERF_POWER) ? 1/*active*/ : 0/*auto*/) + 1;
            return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;        
        }
        return -1;
    } else if (strcasecmp(cmd, "GETBAND")==0) {
        int band; /*0: auto, 1: 5GHz only, 2: 2.4GHz Only*/
        switch (arPriv->arPhyCapability) {
        case WMI_11A_CAPABILITY:
        case WMI_11NA_CAPABILITY:
            band = 1;
            break;
        case WMI_11NG_CAPABILITY:
        case WMI_11G_CAPABILITY:
            band = 2;
            break;
        case WMI_11AG_CAPABILITY:
        case WMI_11NAG_CAPABILITY:
        default:
            band = 0;
            break;
        }
        len = snprintf(buf, data->length, "Band %d\n", band) + 1;
        return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;    
    } else if (strncasecmp(cmd, "SETBAND ", 8)==0) {
        int band;
        if (sscanf(cmd, "%*s %d", &band) == 1) {
            switch (band) {
            case 1: /* 5GHz Only*/
                /* TODO: Using WMI_CHANNEL_PARAMS_CMD to disable all 5GHz channels? */
                break;
            case 2: /* 5GHz Only*/
                /* TODO: Using WMI_CHANNEL_PARAMS_CMD to disable all 2.4GHz channels? */
                break;
            case 0: /* auto */
            default:
                break;
            }
            return 0;
        }
        return -1;
    } else if (strncasecmp(cmd, "SETSUSPENDOPT ", 14)==0) {
        int enable;
        if (sscanf(cmd, "%*s %d", &enable)==1) {
            /* 
             * We set our suspend mode by wlan_config.h now. 
             * Should we follow Android command?? TODO
             */
            return 0;
        }
        return -1;
    } else if (strcasecmp(cmd, "SCAN-CHANNELS")==0) {
        // reply comes back in the form "Scan-Channels = X" where X is the number of channels        
        int iocmd = SIOCGIWRANGE - SIOCSIWCOMMIT;
        iw_handler getRange = dev->wireless_handlers->standard[iocmd];            
        if (getRange) {
            union iwreq_data miwr;
            struct iw_request_info minfo;
            struct iw_range range;
            A_MEMZERO(&minfo, sizeof(minfo));
            A_MEMZERO(&miwr, sizeof(miwr));
            A_MEMZERO(&range, sizeof(range));
            minfo.cmd = SIOCGIWRANGE;
            miwr.data.pointer = (__force void __user *) &range;
            miwr.data.length = sizeof(range);
            getRange(dev, &minfo, &miwr, (char*)&range);
        }
        if (arSta->arNumChannels!=-1) {
            len = snprintf(buf, data->length, "Scan-Channels = %d\n", arSta->arNumChannels) + 1;
            return (copy_to_user(data->pointer, buf, len)==0) ? len : -1;
        }
        return -1;
    } else if (strncasecmp(cmd, "SCAN-CHANNELS ", 14)==0 || 
               strncasecmp(cmd, "COUNTRY ", 8)==0) {
        /* 
         * Set the available channels with WMI_SET_CHANNELPARAMS cmd
         * However, the channels will be limited by the eeprom regulator domain
         * Try to use a regulator domain which will not limited the channels range.
         */
        int i;
        int chan = 0;
        A_UINT16 *clist;
        struct ifreq ifr; 
        char ioBuf[256];
        WMI_CHANNEL_PARAMS_CMD *chParamCmd = (WMI_CHANNEL_PARAMS_CMD *)ioBuf;
        if (strncasecmp(cmd, "COUNTRY ", 8)==0) {
            char *country = cmd + 8;
            if (strcasecmp(country, "US")==0) {
                chan = 11;
            } else if (strcasecmp(country, "JP")==0) {
                chan = 14;
            } else if (strcasecmp(country, "EU")==0) {
                chan = 13;
            }
        } else if (sscanf(cmd, "%*s %d", &chan) != 1) {
            return -1;
        }
        if ( (chan != 11) && (chan != 13) && (chan != 14)) {
            return -1;
        }
        if (arPriv->arNextMode == AP_NETWORK) {
            return -1;
        }
        A_MEMZERO(&ifr, sizeof(ifr));
        A_MEMZERO(ioBuf, sizeof(ioBuf));

        chParamCmd->phyMode = WMI_11G_MODE;
        clist = chParamCmd->channelList;
        chParamCmd->numChannels = chan;
        chParamCmd->scanParam = 1;        
        for (i = 0; i < chan; i++) {
            clist[i] = wlan_ieee2freq(i + 1);
        }
        
        return android_do_ioctl_direct(dev, AR6000_IOCTL_WMI_SET_CHANNELPARAMS, &ifr, ioBuf);
    } else if (strncasecmp(cmd, "BTCOEXMODE ", 11)==0) {
        int mode;
        if (sscanf(cmd, "%*s %d", &mode)==1) {
            /* 
            * Android disable BT-COEX when obtaining dhcp packet except there is headset is connected 
             * It enable the BT-COEX after dhcp process is finished
             * We ignore since we have our way to do bt-coex during dhcp obtaining.
             */
            switch (mode) {
            case 1: /* Disable*/
                break;
            case 0: /* Enable */
                /* fall through */
            case 2: /* Sense*/
                /* fall through */
            default:
                break;
            }
            return 0; /* ignore it */
        }
        return -1;
    } else if (strcasecmp(cmd, "BTCOEXSCAN-START")==0) {
        /* Android enable or disable Bluetooth coexistence scan mode. When this mode is on,
         * some of the low-level scan parameters used by the driver are changed to
         * reduce interference with A2DP streaming.
         */
        return 0; /* ignore it since we have btfilter  */
    } else if (strcasecmp(cmd, "BTCOEXSCAN-STOP")==0) {
        return 0; /* ignore it since we have btfilter  */
    } else if (strncasecmp(cmd, "RXFILTER-ADD ", 13)==0) {
        return 0; /* ignore it */
    } else if (strncasecmp(cmd, "RXFILTER-REMOVE ", 16)==0) {
        return 0; /* ignoret it */
    } else if (strcasecmp(cmd, "RXFILTER-START")==0 || strcasecmp(cmd, "RXFILTER-STOP")==0) {
        unsigned int flags = dev->flags;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
        int mc_count = dev->mc_count;   
#else
        int mc_count = netdev_mc_count(dev);
#endif
        if (strcasecmp(cmd, "RXFILTER-START")==0) {
            if (mc_count > 0 || (flags & IFF_MULTICAST) ) {
                //flags &= ~IFF_MULTICAST;							//to always enable multicast
                flags |= IFF_MULTICAST;
            }
        } else {
            flags |= IFF_MULTICAST;
        }
        if (flags != dev->flags) {
            dev_change_flags(dev, flags);
        }
        return 0;
    }

    return -EOPNOTSUPP;
}
Exemple #14
0
int rst_restore_netdev(struct cpt_context *ctx)
{
	struct net *net = get_exec_env()->ve_netns;
	int err;
	loff_t sec = ctx->sections[CPT_SECT_NET_DEVICE];
	loff_t endsec;
	struct cpt_section_hdr h;
	struct cpt_netdev_image di;
	struct net_device *dev;

	get_exec_env()->disable_net = 1;

	if (sec == CPT_NULL)
		return 0;

	err = ctx->pread(&h, sizeof(h), ctx, sec);
	if (err)
		return err;
	if (h.cpt_section != CPT_SECT_NET_DEVICE || h.cpt_hdrlen < sizeof(h))
		return -EINVAL;

	endsec = sec + h.cpt_next;
	sec += h.cpt_hdrlen;
	while (sec < endsec) {
		loff_t pos;
		struct net_device *dev_new;
		struct netdev_rst *ops;

		err = rst_get_object(CPT_OBJ_NET_DEVICE, sec, &di, ctx);
		if (err)
			return err;

		rtnl_lock();
		pos = sec + di.cpt_hdrlen;
		if (di.cpt_next > sizeof(di)) {
			struct cpt_object_hdr hdr;
			err = ctx->pread(&hdr, sizeof(struct cpt_object_hdr),
					ctx, sec + di.cpt_hdrlen);
			if (err)
				goto out;

			ops = NULL;
			while (1) {
				ops = netdev_find_rst(hdr.cpt_object, ops);
				if (ops == NULL)
					break;

				err = ops->ndo_rst(sec, &di, &rst_ops, ctx);
				if (!err) {
					pos += hdr.cpt_next;
					break;
				} else if (err < 0) {
					eprintk_ctx("netdev %d rst failed %d\n",
							hdr.cpt_object, err);
					goto out;
				}
			}
		}

		dev = __dev_get_by_name(net, di.cpt_name);
		if (dev) {
			if (dev->ifindex != di.cpt_index) {
				dev_new = __dev_get_by_index(net, di.cpt_index);
				if (!dev_new) {
					write_lock_bh(&dev_base_lock);
					hlist_del(&dev->index_hlist);
					if (dev->iflink == dev->ifindex)
						dev->iflink = di.cpt_index;
					dev->ifindex = di.cpt_index;
					hlist_add_head(&dev->index_hlist,
							dev_index_hash(net, dev->ifindex));
					write_unlock_bh(&dev_base_lock);
				} else {
					write_lock_bh(&dev_base_lock);
					hlist_del(&dev->index_hlist);
					hlist_del(&dev_new->index_hlist);
					if (dev_new->iflink == dev_new->ifindex)
						dev_new->iflink = dev->ifindex;
					dev_new->ifindex = dev->ifindex;
					if (dev->iflink == dev->ifindex)
						dev->iflink = di.cpt_index;
					dev->ifindex = di.cpt_index;
					hlist_add_head(&dev->index_hlist,
							dev_index_hash(net, dev->ifindex));
					hlist_add_head(&dev_new->index_hlist,
							dev_index_hash(net, dev_new->ifindex));
					write_unlock_bh(&dev_base_lock);
				}
			}
			if (di.cpt_flags^dev->flags) {
				err = dev_change_flags(dev, di.cpt_flags);
				if (err)
					eprintk_ctx("dev_change_flags err: %d\n", err);
			}
			while (pos < sec + di.cpt_next) {
				struct cpt_object_hdr hdr;
				err = ctx->pread(&hdr, sizeof(struct cpt_object_hdr),
						ctx, pos);
				if (err)
					goto out;
				if (hdr.cpt_object == CPT_OBJ_NET_HWADDR) {
					/* Restore hardware address */
					struct cpt_hwaddr_image hw;
					err = rst_get_object(CPT_OBJ_NET_HWADDR,
							pos, &hw, ctx);
					if (err)
						goto out;
					BUILD_BUG_ON(sizeof(hw.cpt_dev_addr) !=
							MAX_ADDR_LEN);
					memcpy(dev->dev_addr, hw.cpt_dev_addr,
							sizeof(hw.cpt_dev_addr));
				} else if (hdr.cpt_object == CPT_OBJ_NET_STATS) {
					err = rst_restore_netstats(pos, dev, ctx);
					if (err) {
						eprintk_ctx("rst stats %s: %d\n",
								di.cpt_name, err);
						goto out;
					}
				}
				pos += hdr.cpt_next;
			}
		} else {
			eprintk_ctx("unknown interface 2 %s\n", di.cpt_name);
		}
		rtnl_unlock();
		sec += di.cpt_next;
	}
	return 0;
out:
	rtnl_unlock();
	return err;
}
Exemple #15
0
int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
	struct ifreq ifr;
	struct sockaddr_in sin_orig;
	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
	struct in_device *in_dev;
	struct in_ifaddr **ifap = NULL;
	struct in_ifaddr *ifa = NULL;
	struct net_device *dev;
	char *colon;
	int ret = -EFAULT;
	int tryaddrmatch = 0;

	/*
	 *	Fetch the caller's info block into kernel space
	 */

	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
		goto out;
	ifr.ifr_name[IFNAMSIZ - 1] = 0;

	/* save original address for comparison */
	memcpy(&sin_orig, sin, sizeof(*sin));

	colon = strchr(ifr.ifr_name, ':');
	if (colon)
		*colon = 0;

	dev_load(net, ifr.ifr_name);

	switch (cmd) {
	case SIOCGIFADDR:	/* Get interface address */
	case SIOCGIFBRDADDR:	/* Get the broadcast address */
	case SIOCGIFDSTADDR:	/* Get the destination address */
	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
		/* Note that these ioctls will not sleep,
		   so that we do not impose a lock.
		   One day we will be forced to put shlock here (I mean SMP)
		 */
		tryaddrmatch = (sin_orig.sin_family == AF_INET);
		memset(sin, 0, sizeof(*sin));
		sin->sin_family = AF_INET;
		break;

	case SIOCSIFFLAGS:
		ret = -EACCES;
		if (!capable(CAP_NET_ADMIN))
			goto out;
		break;
	case SIOCSIFADDR:	/* Set interface address (and family) */
	case SIOCSIFBRDADDR:	/* Set the broadcast address */
	case SIOCSIFDSTADDR:	/* Set the destination address */
	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
	case SIOCKILLADDR:	/* Nuke all sockets on this address */
		ret = -EACCES;
		if (!capable(CAP_NET_ADMIN))
			goto out;
		ret = -EINVAL;
		if (sin->sin_family != AF_INET)
			goto out;
		break;
	default:
		ret = -EINVAL;
		goto out;
	}

	rtnl_lock();

	ret = -ENODEV;
	dev = __dev_get_by_name(net, ifr.ifr_name);
	if (!dev)
		goto done;

	if (colon)
		*colon = ':';

	in_dev = __in_dev_get_rtnl(dev);
	if (in_dev) {
		if (tryaddrmatch) {
			/* Matthias Andree */
			/* compare label and address (4.4BSD style) */
			/* note: we only do this for a limited set of ioctls
			   and only if the original address family was AF_INET.
			   This is checked above. */
			for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
			     ifap = &ifa->ifa_next) {
				if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
				    sin_orig.sin_addr.s_addr ==
							ifa->ifa_address) {
					break; /* found */
				}
			}
		}
		/* we didn't get a match, maybe the application is
		   4.3BSD-style and passed in junk so we fall back to
		   comparing just the label */
		if (!ifa) {
			for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
			     ifap = &ifa->ifa_next)
				if (!strcmp(ifr.ifr_name, ifa->ifa_label))
					break;
		}
	}

	ret = -EADDRNOTAVAIL;
	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS
	    && cmd != SIOCKILLADDR)
		goto done;

	switch (cmd) {
	case SIOCGIFADDR:	/* Get interface address */
		sin->sin_addr.s_addr = ifa->ifa_local;
		goto rarok;

	case SIOCGIFBRDADDR:	/* Get the broadcast address */
		sin->sin_addr.s_addr = ifa->ifa_broadcast;
		goto rarok;

	case SIOCGIFDSTADDR:	/* Get the destination address */
		sin->sin_addr.s_addr = ifa->ifa_address;
		goto rarok;

	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
		sin->sin_addr.s_addr = ifa->ifa_mask;
		goto rarok;

	case SIOCSIFFLAGS:
		if (colon) {
			ret = -EADDRNOTAVAIL;
			if (!ifa)
				break;
			ret = 0;
			if (!(ifr.ifr_flags & IFF_UP))
				inet_del_ifa(in_dev, ifap, 1);
			break;
		}
		ret = dev_change_flags(dev, ifr.ifr_flags);
		break;

	case SIOCSIFADDR:	/* Set interface address (and family) */
		ret = -EINVAL;
		if (inet_abc_len(sin->sin_addr.s_addr) < 0)
			break;

		if (!ifa) {
			ret = -ENOBUFS;
			ifa = inet_alloc_ifa();
			if (!ifa)
				break;
			if (colon)
				memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
			else
				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
		} else {
			ret = 0;
			if (ifa->ifa_local == sin->sin_addr.s_addr)
				break;
			inet_del_ifa(in_dev, ifap, 0);
			ifa->ifa_broadcast = 0;
			ifa->ifa_scope = 0;
		}

		ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;

		if (!(dev->flags & IFF_POINTOPOINT)) {
			ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
			ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
			if ((dev->flags & IFF_BROADCAST) &&
			    ifa->ifa_prefixlen < 31)
				ifa->ifa_broadcast = ifa->ifa_address |
						     ~ifa->ifa_mask;
		} else {
			ifa->ifa_prefixlen = 32;
			ifa->ifa_mask = inet_make_mask(32);
		}
		ret = inet_set_ifa(dev, ifa);
		break;

	case SIOCSIFBRDADDR:	/* Set the broadcast address */
		ret = 0;
		if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
			inet_del_ifa(in_dev, ifap, 0);
			ifa->ifa_broadcast = sin->sin_addr.s_addr;
			inet_insert_ifa(ifa);
		}
		break;

	case SIOCSIFDSTADDR:	/* Set the destination address */
		ret = 0;
		if (ifa->ifa_address == sin->sin_addr.s_addr)
			break;
		ret = -EINVAL;
		if (inet_abc_len(sin->sin_addr.s_addr) < 0)
			break;
		ret = 0;
		inet_del_ifa(in_dev, ifap, 0);
		ifa->ifa_address = sin->sin_addr.s_addr;
		inet_insert_ifa(ifa);
		break;

	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */

		/*
		 *	The mask we set must be legal.
		 */
		ret = -EINVAL;
		if (bad_mask(sin->sin_addr.s_addr, 0))
			break;
		ret = 0;
		if (ifa->ifa_mask != sin->sin_addr.s_addr) {
			__be32 old_mask = ifa->ifa_mask;
			inet_del_ifa(in_dev, ifap, 0);
			ifa->ifa_mask = sin->sin_addr.s_addr;
			ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);

			/* See if current broadcast address matches
			 * with current netmask, then recalculate
			 * the broadcast address. Otherwise it's a
			 * funny address, so don't touch it since
			 * the user seems to know what (s)he's doing...
			 */
			if ((dev->flags & IFF_BROADCAST) &&
			    (ifa->ifa_prefixlen < 31) &&
			    (ifa->ifa_broadcast ==
			     (ifa->ifa_local|~old_mask))) {
				ifa->ifa_broadcast = (ifa->ifa_local |
						      ~sin->sin_addr.s_addr);
			}
			inet_insert_ifa(ifa);
		}
		break;
	case SIOCKILLADDR:	/* Nuke all connections on this address */
		ret = 0;
		tcp_v4_nuke_addr(sin->sin_addr.s_addr);
		break;
	}
done:
	rtnl_unlock();
out:
	return ret;
rarok:
	rtnl_unlock();
	ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
	goto out;
}
Exemple #16
0
/*
 *	Perform the SIOCxIFxxx calls, inside rtnl_lock()
 */
static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
{
	int err;
	struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
	const struct net_device_ops *ops;

	if (!dev)
		return -ENODEV;

	ops = dev->netdev_ops;

	switch (cmd) {
	case SIOCSIFFLAGS:	/* Set interface flags */
		return dev_change_flags(dev, ifr->ifr_flags);

	case SIOCSIFMETRIC:	/* Set the metric on the interface
				   (currently unused) */
		return -EOPNOTSUPP;

	case SIOCSIFMTU:	/* Set the MTU of a device */
		return dev_set_mtu(dev, ifr->ifr_mtu);

	case SIOCSIFHWADDR:
		if (dev->addr_len > sizeof(struct sockaddr))
			return -EINVAL;
		return dev_set_mac_address(dev, &ifr->ifr_hwaddr);

	case SIOCSIFHWBROADCAST:
		if (ifr->ifr_hwaddr.sa_family != dev->type)
			return -EINVAL;
		memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
		       min(sizeof(ifr->ifr_hwaddr.sa_data),
			   (size_t)dev->addr_len));
		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
		return 0;

	case SIOCSIFMAP:
		if (ops->ndo_set_config) {
			if (!netif_device_present(dev))
				return -ENODEV;
			return ops->ndo_set_config(dev, &ifr->ifr_map);
		}
		return -EOPNOTSUPP;

	case SIOCADDMULTI:
		if (!ops->ndo_set_rx_mode ||
		    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
			return -EINVAL;
		if (!netif_device_present(dev))
			return -ENODEV;
		return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);

	case SIOCDELMULTI:
		if (!ops->ndo_set_rx_mode ||
		    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
			return -EINVAL;
		if (!netif_device_present(dev))
			return -ENODEV;
		return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);

	case SIOCSIFTXQLEN:
		if (ifr->ifr_qlen < 0)
			return -EINVAL;
		return dev_change_tx_queue_len(dev, ifr->ifr_qlen);

	case SIOCSIFNAME:
		ifr->ifr_newname[IFNAMSIZ-1] = '\0';
		return dev_change_name(dev, ifr->ifr_newname);

	case SIOCSHWTSTAMP:
		err = net_hwtstamp_validate(ifr);
		if (err)
			return err;
		/* fall through */

	/*
	 *	Unknown or private ioctl
	 */
	default:
		if ((cmd >= SIOCDEVPRIVATE &&
		    cmd <= SIOCDEVPRIVATE + 15) ||
		    cmd == SIOCBONDENSLAVE ||
		    cmd == SIOCBONDRELEASE ||
		    cmd == SIOCBONDSETHWADDR ||
		    cmd == SIOCBONDSLAVEINFOQUERY ||
		    cmd == SIOCBONDINFOQUERY ||
		    cmd == SIOCBONDCHANGEACTIVE ||
		    cmd == SIOCGMIIPHY ||
		    cmd == SIOCGMIIREG ||
		    cmd == SIOCSMIIREG ||
		    cmd == SIOCBRADDIF ||
		    cmd == SIOCBRDELIF ||
		    cmd == SIOCSHWTSTAMP ||
		    cmd == SIOCGHWTSTAMP ||
		    cmd == SIOCWANDEV) {
			err = -EOPNOTSUPP;
			if (ops->ndo_do_ioctl) {
				if (netif_device_present(dev))
					err = ops->ndo_do_ioctl(dev, ifr, cmd);
				else
					err = -ENODEV;
			}
		} else
			err = -EINVAL;

	}
	return err;
}
static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
{
	struct net_device *dev = (struct net_device *)(ptr);
	struct vlan_group *grp = NULL;
	int i, flgs;
	struct net_device *vlandev = NULL;

	spin_lock_bh(&vlan_group_lock);
	grp = __vlan_find_group(dev->ifindex);
	spin_unlock_bh(&vlan_group_lock);

	if (!grp)
		goto out;

	/* It is OK that we do not hold the group lock right now,
	 * as we run under the RTNL lock.
	 */

	switch (event) {
	case NETDEV_CHANGEADDR:
	case NETDEV_GOING_DOWN:
		/* Ignore for now */
		break;

	case NETDEV_DOWN:
		/* Put all VLANs for this dev in the down state too.  */
		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
			vlandev = grp->vlan_devices[i];
			if (!vlandev)
				continue;

			flgs = vlandev->flags;
			if (!(flgs & IFF_UP))
				continue;

			dev_change_flags(vlandev, flgs & ~IFF_UP);
		}
		break;

	case NETDEV_UP:
		/* Put all VLANs for this dev in the up state too.  */
		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
			vlandev = grp->vlan_devices[i];
			if (!vlandev)
				continue;
				
			flgs = vlandev->flags;
			if (flgs & IFF_UP)
				continue;

			dev_change_flags(vlandev, flgs | IFF_UP);
		}
		break;
		
	case NETDEV_UNREGISTER:
		/* Delete all VLANs for this dev. */
		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
			int ret;

			vlandev = grp->vlan_devices[i];
			if (!vlandev)
				continue;

			ret = unregister_vlan_dev(dev,
						  VLAN_DEV_INFO(vlandev)->vlan_id);

			dev_put(vlandev);
			unregister_netdevice(vlandev);

			/* Group was destroyed? */
			if (ret == 1)
				break;
		}
		break;
	};

out:
	return NOTIFY_DONE;
}
Exemple #18
0
static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
{
	struct net_device *dev = ptr;
	struct vlan_group *grp = vlan_find_group(dev->ifindex);
	int i, flgs;
	struct net_device *vlandev;

	if (!grp)
		goto out;

	/* It is OK that we do not hold the group lock right now,
	 * as we run under the RTNL lock.
	 */

	switch (event) {
	case NETDEV_CHANGE:
		/* Propagate real device state to vlan devices */
		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			vlan_transfer_operstate(dev, vlandev);
		}
		break;

	case NETDEV_DOWN:
		/* Put all VLANs for this dev in the down state too.  */
		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			flgs = vlandev->flags;
			if (!(flgs & IFF_UP))
				continue;

			dev_change_flags(vlandev, flgs & ~IFF_UP);
		}
		break;

	case NETDEV_UP:
		/* Put all VLANs for this dev in the up state too.  */
		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			flgs = vlandev->flags;
			if (flgs & IFF_UP)
				continue;

			dev_change_flags(vlandev, flgs | IFF_UP);
		}
		break;

	case NETDEV_UNREGISTER:
		/* Delete all VLANs for this dev. */
		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
			int ret;

			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

                        flgs = vlandev->flags;
                        if (!(flgs & IFF_UP))
                                continue;

			ret = unregister_vlan_dev(dev,
						  VLAN_DEV_INFO(vlandev)->vlan_id);

			unregister_netdevice(vlandev);

			/* Group was destroyed? */
			if (ret == 1)
				break;
		}
		break;
	};

out:
	return NOTIFY_DONE;
}
Exemple #19
0
static int change_flags(struct net_device *dev, unsigned long new_flags)
{
	return dev_change_flags(dev, (unsigned int)new_flags, NULL);
}
static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
{
	struct net *net = ovs_dp_get_net(parms->dp);
	struct nlattr *options = parms->options;
	struct net_device *dev;
	struct vport *vport;
	struct nlattr *a;
	int err;
	struct vxlan_config conf = {
		.no_share = true,
		.flags = VXLAN_F_COLLECT_METADATA,
	};

	if (!options) {
		err = -EINVAL;
		goto error;
	}

	a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
	if (a && nla_len(a) == sizeof(u16)) {
		conf.dst_port = htons(nla_get_u16(a));
	} else {
		/* Require destination port from userspace. */
		err = -EINVAL;
		goto error;
	}

	vport = ovs_vport_alloc(0, &ovs_vxlan_netdev_vport_ops, parms);
	if (IS_ERR(vport))
		return vport;

	a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION);
	if (a) {
		err = vxlan_configure_exts(vport, a, &conf);
		if (err) {
			ovs_vport_free(vport);
			goto error;
		}
	}

	rtnl_lock();
	dev = vxlan_dev_create(net, parms->name, NET_NAME_USER, &conf);
	if (IS_ERR(dev)) {
		rtnl_unlock();
		ovs_vport_free(vport);
		return ERR_CAST(dev);
	}

	dev_change_flags(dev, dev->flags | IFF_UP);
	rtnl_unlock();
	return vport;
error:
	return ERR_PTR(err);
}

static struct vport *vxlan_create(const struct vport_parms *parms)
{
	struct vport *vport;

	vport = vxlan_tnl_create(parms);
	if (IS_ERR(vport))
		return vport;

	return ovs_netdev_link(vport, parms->name);
}

static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
				     struct dp_upcall_info *upcall)
{
	struct vxlan_dev *vxlan = netdev_priv(vport->dev);
	struct net *net = ovs_dp_get_net(vport->dp);
	unsigned short family = ip_tunnel_info_af(upcall->egress_tun_info);
	__be16 dst_port = vxlan_dev_dst_port(vxlan, family);
	__be16 src_port;
	int port_min;
	int port_max;

	inet_get_local_port_range(net, &port_min, &port_max);
	src_port = udp_flow_src_port(net, skb, 0, 0, true);

	return ovs_tunnel_get_egress_info(upcall, net,
					  skb, IPPROTO_UDP,
					  src_port, dst_port);
}

static struct vport_ops ovs_vxlan_netdev_vport_ops = {
	.type			= OVS_VPORT_TYPE_VXLAN,
	.create			= vxlan_create,
	.destroy		= ovs_netdev_tunnel_destroy,
	.get_options		= vxlan_get_options,
	.send			= ovs_netdev_send,
	.get_egress_tun_info	= vxlan_get_egress_tun_info,
};

static int __init ovs_vxlan_tnl_init(void)
{
	return ovs_vport_ops_register(&ovs_vxlan_netdev_vport_ops);
}

static void __exit ovs_vxlan_tnl_exit(void)
{
	ovs_vport_ops_unregister(&ovs_vxlan_netdev_vport_ops);
}
Exemple #21
0
static int vlan_device_event(struct notifier_block *unused, unsigned long event,
			     void *ptr)
{
	struct net_device *dev = ptr;
	struct vlan_group *grp;
	struct vlan_info *vlan_info;
	int i, flgs;
	struct net_device *vlandev;
	struct vlan_dev_priv *vlan;
	LIST_HEAD(list);

	if (is_vlan_dev(dev))
		__vlan_device_event(dev, event);

	if ((event == NETDEV_UP) &&
	    (dev->features & NETIF_F_HW_VLAN_FILTER)) {
		pr_info("adding VLAN 0 to HW filter on device %s\n",
			dev->name);
		vlan_vid_add(dev, 0);
	}

	vlan_info = rtnl_dereference(dev->vlan_info);
	if (!vlan_info)
		goto out;
	grp = &vlan_info->grp;

	/* It is OK that we do not hold the group lock right now,
	 * as we run under the RTNL lock.
	 */

	switch (event) {
	case NETDEV_CHANGE:
		/* Propagate real device state to vlan devices */
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			netif_stacked_transfer_operstate(dev, vlandev);
		}
		break;

	case NETDEV_CHANGEADDR:
		/* Adjust unicast filters on underlying device */
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			flgs = vlandev->flags;
			if (!(flgs & IFF_UP))
				continue;

			vlan_sync_address(dev, vlandev);
		}
		break;

	case NETDEV_CHANGEMTU:
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			if (vlandev->mtu <= dev->mtu)
				continue;

			dev_set_mtu(vlandev, dev->mtu);
		}
		break;

	case NETDEV_FEAT_CHANGE:
		/* Propagate device features to underlying device */
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			vlan_transfer_features(dev, vlandev);
		}

		break;

	case NETDEV_DOWN:
		if (dev->features & NETIF_F_HW_VLAN_FILTER)
			vlan_vid_del(dev, 0);

		/* Put all VLANs for this dev in the down state too.  */
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			flgs = vlandev->flags;
			if (!(flgs & IFF_UP))
				continue;

			vlan = vlan_dev_priv(vlandev);
			if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
				dev_change_flags(vlandev, flgs & ~IFF_UP);
			netif_stacked_transfer_operstate(dev, vlandev);
		}
		break;

	case NETDEV_UP:
		/* Put all VLANs for this dev in the up state too.  */
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			flgs = vlandev->flags;
			if (flgs & IFF_UP)
				continue;

			vlan = vlan_dev_priv(vlandev);
			if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
				dev_change_flags(vlandev, flgs | IFF_UP);
			netif_stacked_transfer_operstate(dev, vlandev);
		}
		break;

	case NETDEV_UNREGISTER:
		/* twiddle thumbs on netns device moves */
		if (dev->reg_state != NETREG_UNREGISTERING)
			break;

		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			/* removal of last vid destroys vlan_info, abort
			 * afterwards */
			if (vlan_info->nr_vids == 1)
				i = VLAN_N_VID;

			unregister_vlan_dev(vlandev, &list);
		}
		unregister_netdevice_many(&list);
		break;

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

	case NETDEV_NOTIFY_PEERS:
	case NETDEV_BONDING_FAILOVER:
		/* Propagate to vlan devices */
		for (i = 0; i < VLAN_N_VID; i++) {
			vlandev = vlan_group_get_device(grp, i);
			if (!vlandev)
				continue;

			call_netdevice_notifiers(event, vlandev);
		}
		break;
	}

out:
	return NOTIFY_DONE;
}
Exemple #22
0
static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
	struct ifinfomsg *ifm;
	struct net_device *dev;
	int err, send_addr_notify = 0, modified = 0;
	struct nlattr *tb[IFLA_MAX+1];
	char ifname[IFNAMSIZ];

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
	if (err < 0)
		goto errout;

	if (tb[IFLA_IFNAME])
		nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
	else
		ifname[0] = '\0';

	err = -EINVAL;
	ifm = nlmsg_data(nlh);
	if (ifm->ifi_index > 0)
		dev = dev_get_by_index(ifm->ifi_index);
	else if (tb[IFLA_IFNAME])
		dev = dev_get_by_name(ifname);
	else
		goto errout;

	if (dev == NULL) {
		err = -ENODEV;
		goto errout;
	}

	if (tb[IFLA_ADDRESS] &&
	    nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
		goto errout_dev;

	if (tb[IFLA_BROADCAST] &&
	    nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
		goto errout_dev;

	if (tb[IFLA_MAP]) {
		struct rtnl_link_ifmap *u_map;
		struct ifmap k_map;

		if (!dev->set_config) {
			err = -EOPNOTSUPP;
			goto errout_dev;
		}

		if (!netif_device_present(dev)) {
			err = -ENODEV;
			goto errout_dev;
		}

		u_map = nla_data(tb[IFLA_MAP]);
		k_map.mem_start = (unsigned long) u_map->mem_start;
		k_map.mem_end = (unsigned long) u_map->mem_end;
		k_map.base_addr = (unsigned short) u_map->base_addr;
		k_map.irq = (unsigned char) u_map->irq;
		k_map.dma = (unsigned char) u_map->dma;
		k_map.port = (unsigned char) u_map->port;

		err = dev->set_config(dev, &k_map);
		if (err < 0)
			goto errout_dev;

		modified = 1;
	}

	if (tb[IFLA_ADDRESS]) {
		struct sockaddr *sa;
		int len;

		if (!dev->set_mac_address) {
			err = -EOPNOTSUPP;
			goto errout_dev;
		}

		if (!netif_device_present(dev)) {
			err = -ENODEV;
			goto errout_dev;
		}

		len = sizeof(sa_family_t) + dev->addr_len;
		sa = kmalloc(len, GFP_KERNEL);
		if (!sa) {
			err = -ENOMEM;
			goto errout_dev;
		}
		sa->sa_family = dev->type;
		memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
		       dev->addr_len);
		err = dev->set_mac_address(dev, sa);
		kfree(sa);
		if (err)
			goto errout_dev;
		send_addr_notify = 1;
		modified = 1;
	}

	if (tb[IFLA_MTU]) {
		err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
		if (err < 0)
			goto errout_dev;
		modified = 1;
	}

	/*
	 * Interface selected by interface index but interface
	 * name provided implies that a name change has been
	 * requested.
	 */
	if (ifm->ifi_index > 0 && ifname[0]) {
		err = dev_change_name(dev, ifname);
		if (err < 0)
			goto errout_dev;
		modified = 1;
	}

	if (tb[IFLA_BROADCAST]) {
		nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len);
		send_addr_notify = 1;
	}


	if (ifm->ifi_flags || ifm->ifi_change) {
		unsigned int flags = ifm->ifi_flags;

		/* bugwards compatibility: ifi_change == 0 is treated as ~0 */
		if (ifm->ifi_change)
			flags = (flags & ifm->ifi_change) |
				(dev->flags & ~ifm->ifi_change);
		dev_change_flags(dev, flags);
	}

	if (tb[IFLA_TXQLEN])
		dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);

	if (tb[IFLA_WEIGHT])
		dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);

	if (tb[IFLA_OPERSTATE])
		set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));

	if (tb[IFLA_LINKMODE]) {
		write_lock_bh(&dev_base_lock);
		dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
		write_unlock_bh(&dev_base_lock);
	}

	err = 0;

errout_dev:
	if (err < 0 && modified && net_ratelimit())
		printk(KERN_WARNING "A link change request failed with "
		       "some changes comitted already. Interface %s may "
		       "have been left with an inconsistent configuration, "
		       "please check.\n", dev->name);

	if (send_addr_notify)
		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);

	dev_put(dev);
errout:
	return err;
}
static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
	struct ifinfomsg  *ifm = NLMSG_DATA(nlh);
	struct rtattr    **ida = arg;
	struct net_device *dev;
	int err, send_addr_notify = 0;

	if (ifm->ifi_index >= 0)
		dev = dev_get_by_index(ifm->ifi_index);
	else if (ida[IFLA_IFNAME - 1]) {
		char ifname[IFNAMSIZ];

		if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
		                   IFNAMSIZ) >= IFNAMSIZ)
			return -EINVAL;
		dev = dev_get_by_name(ifname);
	} else
		return -EINVAL;

	if (!dev)
		return -ENODEV;

	err = -EINVAL;

	if (ifm->ifi_flags)
		dev_change_flags(dev, ifm->ifi_flags);

	if (ida[IFLA_MAP - 1]) {
		struct rtnl_link_ifmap *u_map;
		struct ifmap k_map;

		if (!dev->set_config) {
			err = -EOPNOTSUPP;
			goto out;
		}

		if (!netif_device_present(dev)) {
			err = -ENODEV;
			goto out;
		}
		
		if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(*u_map)))
			goto out;

		u_map = RTA_DATA(ida[IFLA_MAP - 1]);

		k_map.mem_start = (unsigned long) u_map->mem_start;
		k_map.mem_end = (unsigned long) u_map->mem_end;
		k_map.base_addr = (unsigned short) u_map->base_addr;
		k_map.irq = (unsigned char) u_map->irq;
		k_map.dma = (unsigned char) u_map->dma;
		k_map.port = (unsigned char) u_map->port;

		err = dev->set_config(dev, &k_map);

		if (err)
			goto out;
	}

	if (ida[IFLA_ADDRESS - 1]) {
		if (!dev->set_mac_address) {
			err = -EOPNOTSUPP;
			goto out;
		}
		if (!netif_device_present(dev)) {
			err = -ENODEV;
			goto out;
		}
		if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len))
			goto out;

		err = dev->set_mac_address(dev, RTA_DATA(ida[IFLA_ADDRESS - 1]));
		if (err)
			goto out;
		send_addr_notify = 1;
	}

	if (ida[IFLA_BROADCAST - 1]) {
		if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len))
			goto out;
		memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]),
		       dev->addr_len);
		send_addr_notify = 1;
	}

	if (ida[IFLA_MTU - 1]) {
		if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
			goto out;
		err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1])));

		if (err)
			goto out;

	}

	if (ida[IFLA_TXQLEN - 1]) {
		if (ida[IFLA_TXQLEN - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
			goto out;

		dev->tx_queue_len = *((u32 *) RTA_DATA(ida[IFLA_TXQLEN - 1]));
	}

	if (ida[IFLA_WEIGHT - 1]) {
		if (ida[IFLA_WEIGHT - 1]->rta_len != RTA_LENGTH(sizeof(u32)))
			goto out;

		dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1]));
	}

	if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) {
		char ifname[IFNAMSIZ];

		if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
		                   IFNAMSIZ) >= IFNAMSIZ)
			goto out;
		err = dev_change_name(dev, ifname);
		if (err)
			goto out;
	}

	err = 0;

out:
	if (send_addr_notify)
		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);

	dev_put(dev);
	return err;
}
Exemple #24
0
static int vlan_device_event(struct notifier_block *unused, unsigned long event,
			     void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct vlan_group *grp;
	struct vlan_info *vlan_info;
	int i, flgs;
	struct net_device *vlandev;
	struct vlan_dev_priv *vlan;
	bool last = false;
	LIST_HEAD(list);

	if (is_vlan_dev(dev))
		__vlan_device_event(dev, event);

	if ((event == NETDEV_UP) &&
	    (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
		pr_info("adding VLAN 0 to HW filter on device %s\n",
			dev->name);
		vlan_vid_add(dev, htons(ETH_P_8021Q), 0);
	}

	vlan_info = rtnl_dereference(dev->vlan_info);
	if (!vlan_info)
		goto out;
	grp = &vlan_info->grp;

	/* It is OK that we do not hold the group lock right now,
	 * as we run under the RTNL lock.
	 */

	switch (event) {
	case NETDEV_CHANGE:
		/* Propagate real device state to vlan devices */
		vlan_group_for_each_dev(grp, i, vlandev)
			netif_stacked_transfer_operstate(dev, vlandev);
		break;

	case NETDEV_CHANGEADDR:
		/* Adjust unicast filters on underlying device */
		vlan_group_for_each_dev(grp, i, vlandev) {
			flgs = vlandev->flags;
			if (!(flgs & IFF_UP))
				continue;

			vlan_sync_address(dev, vlandev);
		}
		break;

	case NETDEV_CHANGEMTU:
		vlan_group_for_each_dev(grp, i, vlandev) {
			if (vlandev->mtu <= dev->mtu)
				continue;

			dev_set_mtu(vlandev, dev->mtu);
		}
		break;

	case NETDEV_FEAT_CHANGE:
		/* Propagate device features to underlying device */
		vlan_group_for_each_dev(grp, i, vlandev)
			vlan_transfer_features(dev, vlandev);
		break;

	case NETDEV_DOWN:
		if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
			vlan_vid_del(dev, htons(ETH_P_8021Q), 0);

		/* Put all VLANs for this dev in the down state too.  */
		vlan_group_for_each_dev(grp, i, vlandev) {
			flgs = vlandev->flags;
			if (!(flgs & IFF_UP))
				continue;

			vlan = vlan_dev_priv(vlandev);
			if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
				dev_change_flags(vlandev, flgs & ~IFF_UP);
			netif_stacked_transfer_operstate(dev, vlandev);
		}