1 /* 2 * This is the new netlink-based wireless configuration interface. 3 * 4 * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> 5 */ 6 7 #include <linux/if.h> 8 #include <linux/module.h> 9 #include <linux/err.h> 10 #include <linux/mutex.h> 11 #include <linux/list.h> 12 #include <linux/if_ether.h> 13 #include <linux/ieee80211.h> 14 #include <linux/nl80211.h> 15 #include <linux/rtnetlink.h> 16 #include <linux/netlink.h> 17 #include <net/genetlink.h> 18 #include <net/cfg80211.h> 19 #include "core.h" 20 #include "nl80211.h" 21 22 /* the netlink family */ 23 static struct genl_family nl80211_fam = { 24 .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */ 25 .name = "nl80211", /* have users key off the name instead */ 26 .hdrsize = 0, /* no private header */ 27 .version = 1, /* no particular meaning now */ 28 .maxattr = NL80211_ATTR_MAX, 29 }; 30 31 /* internal helper: get drv and dev */ 32 static int get_drv_dev_by_info_ifindex(struct genl_info *info, 33 struct cfg80211_registered_device **drv, 34 struct net_device **dev) 35 { 36 int ifindex; 37 38 if (!info->attrs[NL80211_ATTR_IFINDEX]) 39 return -EINVAL; 40 41 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); 42 *dev = dev_get_by_index(&init_net, ifindex); 43 if (!*dev) 44 return -ENODEV; 45 46 *drv = cfg80211_get_dev_from_ifindex(ifindex); 47 if (IS_ERR(*drv)) { 48 dev_put(*dev); 49 return PTR_ERR(*drv); 50 } 51 52 return 0; 53 } 54 55 /* policy for the attributes */ 56 static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { 57 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, 58 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, 59 .len = BUS_ID_SIZE-1 }, 60 61 [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, 62 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, 63 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, 64 }; 65 66 /* message building helper */ 67 static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, 68 int flags, u8 cmd) 69 { 70 /* since there is no private header just add the generic one */ 71 return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); 72 } 73 74 /* netlink command implementations */ 75 76 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, 77 struct cfg80211_registered_device *dev) 78 { 79 void *hdr; 80 81 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); 82 if (!hdr) 83 return -1; 84 85 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); 86 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); 87 return genlmsg_end(msg, hdr); 88 89 nla_put_failure: 90 return genlmsg_cancel(msg, hdr); 91 } 92 93 static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) 94 { 95 int idx = 0; 96 int start = cb->args[0]; 97 struct cfg80211_registered_device *dev; 98 99 mutex_lock(&cfg80211_drv_mutex); 100 list_for_each_entry(dev, &cfg80211_drv_list, list) { 101 if (++idx < start) 102 continue; 103 if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid, 104 cb->nlh->nlmsg_seq, NLM_F_MULTI, 105 dev) < 0) 106 break; 107 } 108 mutex_unlock(&cfg80211_drv_mutex); 109 110 cb->args[0] = idx; 111 112 return skb->len; 113 } 114 115 static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) 116 { 117 struct sk_buff *msg; 118 struct cfg80211_registered_device *dev; 119 120 dev = cfg80211_get_dev_from_info(info); 121 if (IS_ERR(dev)) 122 return PTR_ERR(dev); 123 124 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 125 if (!msg) 126 goto out_err; 127 128 if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0) 129 goto out_free; 130 131 cfg80211_put_dev(dev); 132 133 return genlmsg_unicast(msg, info->snd_pid); 134 135 out_free: 136 nlmsg_free(msg); 137 out_err: 138 cfg80211_put_dev(dev); 139 return -ENOBUFS; 140 } 141 142 static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) 143 { 144 struct cfg80211_registered_device *rdev; 145 int result; 146 147 if (!info->attrs[NL80211_ATTR_WIPHY_NAME]) 148 return -EINVAL; 149 150 rdev = cfg80211_get_dev_from_info(info); 151 if (IS_ERR(rdev)) 152 return PTR_ERR(rdev); 153 154 result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); 155 156 cfg80211_put_dev(rdev); 157 return result; 158 } 159 160 161 static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, 162 struct net_device *dev) 163 { 164 void *hdr; 165 166 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); 167 if (!hdr) 168 return -1; 169 170 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); 171 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); 172 /* TODO: interface type */ 173 return genlmsg_end(msg, hdr); 174 175 nla_put_failure: 176 return genlmsg_cancel(msg, hdr); 177 } 178 179 static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb) 180 { 181 int wp_idx = 0; 182 int if_idx = 0; 183 int wp_start = cb->args[0]; 184 int if_start = cb->args[1]; 185 struct cfg80211_registered_device *dev; 186 struct wireless_dev *wdev; 187 188 mutex_lock(&cfg80211_drv_mutex); 189 list_for_each_entry(dev, &cfg80211_drv_list, list) { 190 if (++wp_idx < wp_start) 191 continue; 192 if_idx = 0; 193 194 mutex_lock(&dev->devlist_mtx); 195 list_for_each_entry(wdev, &dev->netdev_list, list) { 196 if (++if_idx < if_start) 197 continue; 198 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, 199 cb->nlh->nlmsg_seq, NLM_F_MULTI, 200 wdev->netdev) < 0) 201 break; 202 } 203 mutex_unlock(&dev->devlist_mtx); 204 } 205 mutex_unlock(&cfg80211_drv_mutex); 206 207 cb->args[0] = wp_idx; 208 cb->args[1] = if_idx; 209 210 return skb->len; 211 } 212 213 static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) 214 { 215 struct sk_buff *msg; 216 struct cfg80211_registered_device *dev; 217 struct net_device *netdev; 218 int err; 219 220 err = get_drv_dev_by_info_ifindex(info, &dev, &netdev); 221 if (err) 222 return err; 223 224 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 225 if (!msg) 226 goto out_err; 227 228 if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0) 229 goto out_free; 230 231 dev_put(netdev); 232 cfg80211_put_dev(dev); 233 234 return genlmsg_unicast(msg, info->snd_pid); 235 236 out_free: 237 nlmsg_free(msg); 238 out_err: 239 dev_put(netdev); 240 cfg80211_put_dev(dev); 241 return -ENOBUFS; 242 } 243 244 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) 245 { 246 struct cfg80211_registered_device *drv; 247 int err, ifindex; 248 enum nl80211_iftype type; 249 struct net_device *dev; 250 251 if (info->attrs[NL80211_ATTR_IFTYPE]) { 252 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); 253 if (type > NL80211_IFTYPE_MAX) 254 return -EINVAL; 255 } else 256 return -EINVAL; 257 258 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 259 if (err) 260 return err; 261 ifindex = dev->ifindex; 262 dev_put(dev); 263 264 if (!drv->ops->change_virtual_intf) { 265 err = -EOPNOTSUPP; 266 goto unlock; 267 } 268 269 rtnl_lock(); 270 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type); 271 rtnl_unlock(); 272 273 unlock: 274 cfg80211_put_dev(drv); 275 return err; 276 } 277 278 static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) 279 { 280 struct cfg80211_registered_device *drv; 281 int err; 282 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; 283 284 if (!info->attrs[NL80211_ATTR_IFNAME]) 285 return -EINVAL; 286 287 if (info->attrs[NL80211_ATTR_IFTYPE]) { 288 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); 289 if (type > NL80211_IFTYPE_MAX) 290 return -EINVAL; 291 } 292 293 drv = cfg80211_get_dev_from_info(info); 294 if (IS_ERR(drv)) 295 return PTR_ERR(drv); 296 297 if (!drv->ops->add_virtual_intf) { 298 err = -EOPNOTSUPP; 299 goto unlock; 300 } 301 302 rtnl_lock(); 303 err = drv->ops->add_virtual_intf(&drv->wiphy, 304 nla_data(info->attrs[NL80211_ATTR_IFNAME]), type); 305 rtnl_unlock(); 306 307 unlock: 308 cfg80211_put_dev(drv); 309 return err; 310 } 311 312 static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) 313 { 314 struct cfg80211_registered_device *drv; 315 int ifindex, err; 316 struct net_device *dev; 317 318 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 319 if (err) 320 return err; 321 ifindex = dev->ifindex; 322 dev_put(dev); 323 324 if (!drv->ops->del_virtual_intf) { 325 err = -EOPNOTSUPP; 326 goto out; 327 } 328 329 rtnl_lock(); 330 err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); 331 rtnl_unlock(); 332 333 out: 334 cfg80211_put_dev(drv); 335 return err; 336 } 337 338 static struct genl_ops nl80211_ops[] = { 339 { 340 .cmd = NL80211_CMD_GET_WIPHY, 341 .doit = nl80211_get_wiphy, 342 .dumpit = nl80211_dump_wiphy, 343 .policy = nl80211_policy, 344 /* can be retrieved by unprivileged users */ 345 }, 346 { 347 .cmd = NL80211_CMD_SET_WIPHY, 348 .doit = nl80211_set_wiphy, 349 .policy = nl80211_policy, 350 .flags = GENL_ADMIN_PERM, 351 }, 352 { 353 .cmd = NL80211_CMD_GET_INTERFACE, 354 .doit = nl80211_get_interface, 355 .dumpit = nl80211_dump_interface, 356 .policy = nl80211_policy, 357 /* can be retrieved by unprivileged users */ 358 }, 359 { 360 .cmd = NL80211_CMD_SET_INTERFACE, 361 .doit = nl80211_set_interface, 362 .policy = nl80211_policy, 363 .flags = GENL_ADMIN_PERM, 364 }, 365 { 366 .cmd = NL80211_CMD_NEW_INTERFACE, 367 .doit = nl80211_new_interface, 368 .policy = nl80211_policy, 369 .flags = GENL_ADMIN_PERM, 370 }, 371 { 372 .cmd = NL80211_CMD_DEL_INTERFACE, 373 .doit = nl80211_del_interface, 374 .policy = nl80211_policy, 375 .flags = GENL_ADMIN_PERM, 376 }, 377 }; 378 379 /* multicast groups */ 380 static struct genl_multicast_group nl80211_config_mcgrp = { 381 .name = "config", 382 }; 383 384 /* notification functions */ 385 386 void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) 387 { 388 struct sk_buff *msg; 389 390 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 391 if (!msg) 392 return; 393 394 if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) { 395 nlmsg_free(msg); 396 return; 397 } 398 399 genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); 400 } 401 402 /* initialisation/exit functions */ 403 404 int nl80211_init(void) 405 { 406 int err, i; 407 408 err = genl_register_family(&nl80211_fam); 409 if (err) 410 return err; 411 412 for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) { 413 err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]); 414 if (err) 415 goto err_out; 416 } 417 418 err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); 419 if (err) 420 goto err_out; 421 422 return 0; 423 err_out: 424 genl_unregister_family(&nl80211_fam); 425 return err; 426 } 427 428 void nl80211_exit(void) 429 { 430 genl_unregister_family(&nl80211_fam); 431 } 432