aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-04-19 15:24:32 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-04-22 16:57:17 -0400
commit04a773ade0680d862b479d7219973df60f7a3834 (patch)
treefc759eb79099fefd7f1329bcb2b703008cb0adfe /net/wireless/nl80211.c
parent691597cb26f236ac7471f1adf925a134c86799d6 (diff)
cfg80211/nl80211: add IBSS API
This adds IBSS API along with (preliminary) wext handlers. The wext handlers can only do IBSS so you need to call them from your own wext handlers if the mode is IBSS. The nl80211 API requires * an SSID * a channel (frequency) for the case that a new IBSS has to be created It optionally supports * a flag to fix the channel * a fixed BSSID The cfg80211 code also takes care to leave the IBSS before the netdev is set down. If wireless extensions are used, it also caches values when the interface is down and instructs the driver to join when the interface is set up. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c182
1 files changed, 170 insertions, 12 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d2cfde659e76..16f86356ac97 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -116,6 +116,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
116 .len = IEEE80211_MAX_SSID_LEN }, 116 .len = IEEE80211_MAX_SSID_LEN },
117 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, 117 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
118 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, 118 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
119 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
119}; 120};
120 121
121/* IE validation */ 122/* IE validation */
@@ -322,6 +323,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
322 CMD(assoc, ASSOCIATE); 323 CMD(assoc, ASSOCIATE);
323 CMD(deauth, DEAUTHENTICATE); 324 CMD(deauth, DEAUTHENTICATE);
324 CMD(disassoc, DISASSOCIATE); 325 CMD(disassoc, DISASSOCIATE);
326 CMD(join_ibss, JOIN_IBSS);
325 327
326#undef CMD 328#undef CMD
327 nla_nest_end(msg, nl_cmds); 329 nla_nest_end(msg, nl_cmds);
@@ -668,7 +670,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
668 struct cfg80211_registered_device *drv; 670 struct cfg80211_registered_device *drv;
669 struct vif_params params; 671 struct vif_params params;
670 int err, ifindex; 672 int err, ifindex;
671 enum nl80211_iftype type; 673 enum nl80211_iftype otype, ntype;
672 struct net_device *dev; 674 struct net_device *dev;
673 u32 _flags, *flags = NULL; 675 u32 _flags, *flags = NULL;
674 bool change = false; 676 bool change = false;
@@ -682,30 +684,27 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
682 goto unlock_rtnl; 684 goto unlock_rtnl;
683 685
684 ifindex = dev->ifindex; 686 ifindex = dev->ifindex;
685 type = dev->ieee80211_ptr->iftype; 687 otype = ntype = dev->ieee80211_ptr->iftype;
686 dev_put(dev); 688 dev_put(dev);
687 689
688 if (info->attrs[NL80211_ATTR_IFTYPE]) { 690 if (info->attrs[NL80211_ATTR_IFTYPE]) {
689 enum nl80211_iftype ntype;
690
691 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); 691 ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
692 if (type != ntype) 692 if (otype != ntype)
693 change = true; 693 change = true;
694 type = ntype; 694 if (ntype > NL80211_IFTYPE_MAX) {
695 if (type > NL80211_IFTYPE_MAX) {
696 err = -EINVAL; 695 err = -EINVAL;
697 goto unlock; 696 goto unlock;
698 } 697 }
699 } 698 }
700 699
701 if (!drv->ops->change_virtual_intf || 700 if (!drv->ops->change_virtual_intf ||
702 !(drv->wiphy.interface_modes & (1 << type))) { 701 !(drv->wiphy.interface_modes & (1 << ntype))) {
703 err = -EOPNOTSUPP; 702 err = -EOPNOTSUPP;
704 goto unlock; 703 goto unlock;
705 } 704 }
706 705
707 if (info->attrs[NL80211_ATTR_MESH_ID]) { 706 if (info->attrs[NL80211_ATTR_MESH_ID]) {
708 if (type != NL80211_IFTYPE_MESH_POINT) { 707 if (ntype != NL80211_IFTYPE_MESH_POINT) {
709 err = -EINVAL; 708 err = -EINVAL;
710 goto unlock; 709 goto unlock;
711 } 710 }
@@ -715,7 +714,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
715 } 714 }
716 715
717 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { 716 if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
718 if (type != NL80211_IFTYPE_MONITOR) { 717 if (ntype != NL80211_IFTYPE_MONITOR) {
719 err = -EINVAL; 718 err = -EINVAL;
720 goto unlock; 719 goto unlock;
721 } 720 }
@@ -730,12 +729,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
730 729
731 if (change) 730 if (change)
732 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, 731 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
733 type, flags, &params); 732 ntype, flags, &params);
734 else 733 else
735 err = 0; 734 err = 0;
736 735
737 dev = __dev_get_by_index(&init_net, ifindex); 736 dev = __dev_get_by_index(&init_net, ifindex);
738 WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); 737 WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype));
738
739 if (dev && !err && (ntype != otype)) {
740 if (otype == NL80211_IFTYPE_ADHOC)
741 cfg80211_clear_ibss(dev);
742 }
739 743
740 unlock: 744 unlock:
741 cfg80211_put_dev(drv); 745 cfg80211_put_dev(drv);
@@ -3052,6 +3056,114 @@ unlock_rtnl:
3052 return err; 3056 return err;
3053} 3057}
3054 3058
3059static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
3060{
3061 struct cfg80211_registered_device *drv;
3062 struct net_device *dev;
3063 struct cfg80211_ibss_params ibss;
3064 struct wiphy *wiphy;
3065 int err;
3066
3067 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3068 return -EINVAL;
3069
3070 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
3071 !info->attrs[NL80211_ATTR_SSID] ||
3072 !nla_len(info->attrs[NL80211_ATTR_SSID]))
3073 return -EINVAL;
3074
3075 rtnl_lock();
3076
3077 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
3078 if (err)
3079 goto unlock_rtnl;
3080
3081 if (!drv->ops->join_ibss) {
3082 err = -EOPNOTSUPP;
3083 goto out;
3084 }
3085
3086 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
3087 err = -EOPNOTSUPP;
3088 goto out;
3089 }
3090
3091 if (!netif_running(dev)) {
3092 err = -ENETDOWN;
3093 goto out;
3094 }
3095
3096 wiphy = &drv->wiphy;
3097 memset(&ibss, 0, sizeof(ibss));
3098
3099 if (info->attrs[NL80211_ATTR_MAC])
3100 ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
3101 ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3102 ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3103
3104 if (info->attrs[NL80211_ATTR_IE]) {
3105 ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
3106 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3107 }
3108
3109 ibss.channel = ieee80211_get_channel(wiphy,
3110 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
3111 if (!ibss.channel ||
3112 ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
3113 ibss.channel->flags & IEEE80211_CHAN_DISABLED) {
3114 err = -EINVAL;
3115 goto out;
3116 }
3117
3118 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
3119
3120 err = cfg80211_join_ibss(drv, dev, &ibss);
3121
3122out:
3123 cfg80211_put_dev(drv);
3124 dev_put(dev);
3125unlock_rtnl:
3126 rtnl_unlock();
3127 return err;
3128}
3129
3130static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
3131{
3132 struct cfg80211_registered_device *drv;
3133 struct net_device *dev;
3134 int err;
3135
3136 rtnl_lock();
3137
3138 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
3139 if (err)
3140 goto unlock_rtnl;
3141
3142 if (!drv->ops->leave_ibss) {
3143 err = -EOPNOTSUPP;
3144 goto out;
3145 }
3146
3147 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
3148 err = -EOPNOTSUPP;
3149 goto out;
3150 }
3151
3152 if (!netif_running(dev)) {
3153 err = -ENETDOWN;
3154 goto out;
3155 }
3156
3157 err = cfg80211_leave_ibss(drv, dev);
3158
3159out:
3160 cfg80211_put_dev(drv);
3161 dev_put(dev);
3162unlock_rtnl:
3163 rtnl_unlock();
3164 return err;
3165}
3166
3055static struct genl_ops nl80211_ops[] = { 3167static struct genl_ops nl80211_ops[] = {
3056 { 3168 {
3057 .cmd = NL80211_CMD_GET_WIPHY, 3169 .cmd = NL80211_CMD_GET_WIPHY,
@@ -3253,6 +3365,18 @@ static struct genl_ops nl80211_ops[] = {
3253 .policy = nl80211_policy, 3365 .policy = nl80211_policy,
3254 .flags = GENL_ADMIN_PERM, 3366 .flags = GENL_ADMIN_PERM,
3255 }, 3367 },
3368 {
3369 .cmd = NL80211_CMD_JOIN_IBSS,
3370 .doit = nl80211_join_ibss,
3371 .policy = nl80211_policy,
3372 .flags = GENL_ADMIN_PERM,
3373 },
3374 {
3375 .cmd = NL80211_CMD_LEAVE_IBSS,
3376 .doit = nl80211_leave_ibss,
3377 .policy = nl80211_policy,
3378 .flags = GENL_ADMIN_PERM,
3379 },
3256}; 3380};
3257static struct genl_multicast_group nl80211_mlme_mcgrp = { 3381static struct genl_multicast_group nl80211_mlme_mcgrp = {
3258 .name = "mlme", 3382 .name = "mlme",
@@ -3466,6 +3590,40 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
3466 NL80211_CMD_DISASSOCIATE); 3590 NL80211_CMD_DISASSOCIATE);
3467} 3591}
3468 3592
3593void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
3594 struct net_device *netdev, const u8 *bssid,
3595 gfp_t gfp)
3596{
3597 struct sk_buff *msg;
3598 void *hdr;
3599
3600 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
3601 if (!msg)
3602 return;
3603
3604 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS);
3605 if (!hdr) {
3606 nlmsg_free(msg);
3607 return;
3608 }
3609
3610 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
3611 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
3612 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
3613
3614 if (genlmsg_end(msg, hdr) < 0) {
3615 nlmsg_free(msg);
3616 return;
3617 }
3618
3619 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
3620 return;
3621
3622 nla_put_failure:
3623 genlmsg_cancel(msg, hdr);
3624 nlmsg_free(msg);
3625}
3626
3469void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, 3627void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
3470 struct net_device *netdev, const u8 *addr, 3628 struct net_device *netdev, const u8 *addr,
3471 enum nl80211_key_type key_type, int key_id, 3629 enum nl80211_key_type key_type, int key_id,