aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c2
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/core.c16
-rw-r--r--net/wireless/core.h7
-rw-r--r--net/wireless/nl80211.c368
-rw-r--r--net/wireless/nl80211.h13
-rw-r--r--net/wireless/sme.c224
7 files changed, 620 insertions, 12 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c34c1a41019a..03de4024597a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1262,7 +1262,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
1262 sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; 1262 sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
1263 } 1263 }
1264 1264
1265 if (req->control_port) 1265 if (req->crypto.control_port)
1266 sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; 1266 sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT;
1267 else 1267 else
1268 sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; 1268 sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index f78c4832a9ca..750c08e31b10 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o 5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o 6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
7 7
8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o 8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o
9cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o 9cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
10cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o 10cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
11 11
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d41b7412b212..314e00f70e3b 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -546,6 +546,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
546 "symlink to netdev!\n"); 546 "symlink to netdev!\n");
547 } 547 }
548 wdev->netdev = dev; 548 wdev->netdev = dev;
549 wdev->sme_state = CFG80211_SME_IDLE;
549#ifdef CONFIG_WIRELESS_EXT 550#ifdef CONFIG_WIRELESS_EXT
550 wdev->wext.default_key = -1; 551 wdev->wext.default_key = -1;
551 wdev->wext.default_mgmt_key = -1; 552 wdev->wext.default_mgmt_key = -1;
@@ -553,11 +554,20 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
553 mutex_unlock(&rdev->devlist_mtx); 554 mutex_unlock(&rdev->devlist_mtx);
554 break; 555 break;
555 case NETDEV_GOING_DOWN: 556 case NETDEV_GOING_DOWN:
556 if (wdev->iftype != NL80211_IFTYPE_ADHOC)
557 break;
558 if (!wdev->ssid_len) 557 if (!wdev->ssid_len)
559 break; 558 break;
560 cfg80211_leave_ibss(rdev, dev, true); 559
560 switch (wdev->iftype) {
561 case NL80211_IFTYPE_ADHOC:
562 cfg80211_leave_ibss(rdev, dev, true);
563 break;
564 case NL80211_IFTYPE_STATION:
565 cfg80211_disconnect(rdev, dev,
566 WLAN_REASON_DEAUTH_LEAVING);
567 break;
568 default:
569 break;
570 }
561 break; 571 break;
562 case NETDEV_UP: 572 case NETDEV_UP:
563#ifdef CONFIG_WIRELESS_EXT 573#ifdef CONFIG_WIRELESS_EXT
diff --git a/net/wireless/core.h b/net/wireless/core.h
index bc084b68865c..f93f96f85d2b 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -174,6 +174,13 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
174int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 174int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
175 struct net_device *dev, bool nowext); 175 struct net_device *dev, bool nowext);
176 176
177/* SME */
178int cfg80211_connect(struct cfg80211_registered_device *rdev,
179 struct net_device *dev,
180 struct cfg80211_connect_params *connect);
181int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
182 struct net_device *dev, u16 reason);
183
177/* internal helpers */ 184/* internal helpers */
178int cfg80211_validate_key_settings(struct key_params *params, int key_idx, 185int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
179 const u8 *mac_addr); 186 const u8 *mac_addr);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index bb8de268a6bf..89dd3793e03c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -128,6 +128,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
128 .len = sizeof(struct nl80211_sta_flag_update), 128 .len = sizeof(struct nl80211_sta_flag_update),
129 }, 129 },
130 [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, 130 [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
131 [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
132 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
133 [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
131}; 134};
132 135
133/* IE validation */ 136/* IE validation */
@@ -347,6 +350,17 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
347 CMD(join_ibss, JOIN_IBSS); 350 CMD(join_ibss, JOIN_IBSS);
348 351
349#undef CMD 352#undef CMD
353
354 if (dev->ops->connect) {
355 i++;
356 NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT);
357 }
358
359 if (dev->ops->disconnect) {
360 i++;
361 NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT);
362 }
363
350 nla_nest_end(msg, nl_cmds); 364 nla_nest_end(msg, nl_cmds);
351 365
352 return genlmsg_end(msg, hdr); 366 return genlmsg_end(msg, hdr);
@@ -3001,12 +3015,31 @@ static int nl80211_dump_scan(struct sk_buff *skb,
3001 3015
3002static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) 3016static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
3003{ 3017{
3004 return auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM || 3018 return auth_type <= NL80211_AUTHTYPE_MAX;
3005 auth_type == NL80211_AUTHTYPE_SHARED_KEY || 3019}
3006 auth_type == NL80211_AUTHTYPE_FT || 3020
3007 auth_type == NL80211_AUTHTYPE_NETWORK_EAP; 3021static bool nl80211_valid_wpa_versions(u32 wpa_versions)
3022{
3023 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
3024 NL80211_WPA_VERSION_2));
3025}
3026
3027static bool nl80211_valid_akm_suite(u32 akm)
3028{
3029 return akm == WLAN_AKM_SUITE_8021X ||
3030 akm == WLAN_AKM_SUITE_PSK;
3031}
3032
3033static bool nl80211_valid_cipher_suite(u32 cipher)
3034{
3035 return cipher == WLAN_CIPHER_SUITE_WEP40 ||
3036 cipher == WLAN_CIPHER_SUITE_WEP104 ||
3037 cipher == WLAN_CIPHER_SUITE_TKIP ||
3038 cipher == WLAN_CIPHER_SUITE_CCMP ||
3039 cipher == WLAN_CIPHER_SUITE_AES_CMAC;
3008} 3040}
3009 3041
3042
3010static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) 3043static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3011{ 3044{
3012 struct cfg80211_registered_device *drv; 3045 struct cfg80211_registered_device *drv;
@@ -3086,6 +3119,68 @@ unlock_rtnl:
3086 return err; 3119 return err;
3087} 3120}
3088 3121
3122static int nl80211_crypto_settings(struct genl_info *info,
3123 struct cfg80211_crypto_settings *settings)
3124{
3125 settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
3126
3127 if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) {
3128 void *data;
3129 int len, i;
3130
3131 data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
3132 len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]);
3133 settings->n_ciphers_pairwise = len / sizeof(u32);
3134
3135 if (len % sizeof(u32))
3136 return -EINVAL;
3137
3138 if (settings->n_ciphers_pairwise > NL80211_MAX_NR_CIPHER_SUITES)
3139 return -EINVAL;
3140
3141 memcpy(settings->ciphers_pairwise, data, len);
3142
3143 for (i = 0; i < settings->n_ciphers_pairwise; i++)
3144 if (!nl80211_valid_cipher_suite(
3145 settings->ciphers_pairwise[i]))
3146 return -EINVAL;
3147 }
3148
3149 if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
3150 settings->cipher_group =
3151 nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
3152 if (!nl80211_valid_cipher_suite(settings->cipher_group))
3153 return -EINVAL;
3154 }
3155
3156 if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) {
3157 settings->wpa_versions =
3158 nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]);
3159 if (!nl80211_valid_wpa_versions(settings->wpa_versions))
3160 return -EINVAL;
3161 }
3162
3163 if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
3164 void *data;
3165 int len, i;
3166
3167 data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
3168 len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
3169 settings->n_akm_suites = len / sizeof(u32);
3170
3171 if (len % sizeof(u32))
3172 return -EINVAL;
3173
3174 memcpy(settings->akm_suites, data, len);
3175
3176 for (i = 0; i < settings->n_ciphers_pairwise; i++)
3177 if (!nl80211_valid_akm_suite(settings->akm_suites[i]))
3178 return -EINVAL;
3179 }
3180
3181 return 0;
3182}
3183
3089static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) 3184static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3090{ 3185{
3091 struct cfg80211_registered_device *drv; 3186 struct cfg80211_registered_device *drv;
@@ -3156,9 +3251,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
3156 } 3251 }
3157 } 3252 }
3158 3253
3159 req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; 3254 err = nl80211_crypto_settings(info, &req.crypto);
3160 3255 if (!err)
3161 err = drv->ops->assoc(&drv->wiphy, dev, &req); 3256 err = drv->ops->assoc(&drv->wiphy, dev, &req);
3162 3257
3163out: 3258out:
3164 cfg80211_put_dev(drv); 3259 cfg80211_put_dev(drv);
@@ -3538,6 +3633,130 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
3538EXPORT_SYMBOL(cfg80211_testmode_event); 3633EXPORT_SYMBOL(cfg80211_testmode_event);
3539#endif 3634#endif
3540 3635
3636static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
3637{
3638 struct cfg80211_registered_device *drv;
3639 struct net_device *dev;
3640 struct cfg80211_connect_params connect;
3641 struct wiphy *wiphy;
3642 int err;
3643
3644 memset(&connect, 0, sizeof(connect));
3645
3646 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3647 return -EINVAL;
3648
3649 if (!info->attrs[NL80211_ATTR_SSID] ||
3650 !nla_len(info->attrs[NL80211_ATTR_SSID]))
3651 return -EINVAL;
3652
3653 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
3654 connect.auth_type =
3655 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
3656 if (!nl80211_valid_auth_type(connect.auth_type))
3657 return -EINVAL;
3658 } else
3659 connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
3660
3661 connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];
3662
3663 err = nl80211_crypto_settings(info, &connect.crypto);
3664 if (err)
3665 return err;
3666 rtnl_lock();
3667
3668 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
3669 if (err)
3670 goto unlock_rtnl;
3671
3672 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
3673 err = -EOPNOTSUPP;
3674 goto out;
3675 }
3676
3677 if (!netif_running(dev)) {
3678 err = -ENETDOWN;
3679 goto out;
3680 }
3681
3682 wiphy = &drv->wiphy;
3683
3684 connect.bssid = NULL;
3685 connect.channel = NULL;
3686 connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
3687
3688 if (info->attrs[NL80211_ATTR_MAC])
3689 connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
3690 connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
3691 connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
3692
3693 if (info->attrs[NL80211_ATTR_IE]) {
3694 connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
3695 connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3696 }
3697
3698 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
3699 connect.channel =
3700 ieee80211_get_channel(wiphy,
3701 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
3702 if (!connect.channel ||
3703 connect.channel->flags & IEEE80211_CHAN_DISABLED) {
3704 err = -EINVAL;
3705 goto out;
3706 }
3707 }
3708
3709 err = cfg80211_connect(drv, dev, &connect);
3710
3711out:
3712 cfg80211_put_dev(drv);
3713 dev_put(dev);
3714unlock_rtnl:
3715 rtnl_unlock();
3716 return err;
3717}
3718
3719static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
3720{
3721 struct cfg80211_registered_device *drv;
3722 struct net_device *dev;
3723 int err;
3724 u16 reason;
3725
3726 if (!info->attrs[NL80211_ATTR_REASON_CODE])
3727 reason = WLAN_REASON_DEAUTH_LEAVING;
3728 else
3729 reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
3730
3731 if (reason == 0)
3732 return -EINVAL;
3733
3734 rtnl_lock();
3735
3736 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
3737 if (err)
3738 goto unlock_rtnl;
3739
3740 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
3741 err = -EOPNOTSUPP;
3742 goto out;
3743 }
3744
3745 if (!netif_running(dev)) {
3746 err = -ENETDOWN;
3747 goto out;
3748 }
3749
3750 err = cfg80211_disconnect(drv, dev, reason);
3751
3752out:
3753 cfg80211_put_dev(drv);
3754 dev_put(dev);
3755unlock_rtnl:
3756 rtnl_unlock();
3757 return err;
3758}
3759
3541static struct genl_ops nl80211_ops[] = { 3760static struct genl_ops nl80211_ops[] = {
3542 { 3761 {
3543 .cmd = NL80211_CMD_GET_WIPHY, 3762 .cmd = NL80211_CMD_GET_WIPHY,
@@ -3759,6 +3978,18 @@ static struct genl_ops nl80211_ops[] = {
3759 .flags = GENL_ADMIN_PERM, 3978 .flags = GENL_ADMIN_PERM,
3760 }, 3979 },
3761#endif 3980#endif
3981 {
3982 .cmd = NL80211_CMD_CONNECT,
3983 .doit = nl80211_connect,
3984 .policy = nl80211_policy,
3985 .flags = GENL_ADMIN_PERM,
3986 },
3987 {
3988 .cmd = NL80211_CMD_DISCONNECT,
3989 .doit = nl80211_disconnect,
3990 .policy = nl80211_policy,
3991 .flags = GENL_ADMIN_PERM,
3992 },
3762}; 3993};
3763static struct genl_multicast_group nl80211_mlme_mcgrp = { 3994static struct genl_multicast_group nl80211_mlme_mcgrp = {
3764 .name = "mlme", 3995 .name = "mlme",
@@ -4077,6 +4308,129 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
4077 addr, gfp); 4308 addr, gfp);
4078} 4309}
4079 4310
4311void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
4312 struct net_device *netdev, const u8 *bssid,
4313 const u8 *req_ie, size_t req_ie_len,
4314 const u8 *resp_ie, size_t resp_ie_len,
4315 u16 status, gfp_t gfp)
4316{
4317 struct sk_buff *msg;
4318 void *hdr;
4319
4320 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
4321 if (!msg)
4322 return;
4323
4324 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT);
4325 if (!hdr) {
4326 nlmsg_free(msg);
4327 return;
4328 }
4329
4330 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
4331 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
4332 if (bssid)
4333 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
4334 NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status);
4335 if (req_ie)
4336 NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie);
4337 if (resp_ie)
4338 NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
4339
4340 if (genlmsg_end(msg, hdr) < 0) {
4341 nlmsg_free(msg);
4342 return;
4343 }
4344
4345 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
4346 return;
4347
4348 nla_put_failure:
4349 genlmsg_cancel(msg, hdr);
4350 nlmsg_free(msg);
4351
4352}
4353
4354void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
4355 struct net_device *netdev, const u8 *bssid,
4356 const u8 *req_ie, size_t req_ie_len,
4357 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
4358{
4359 struct sk_buff *msg;
4360 void *hdr;
4361
4362 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
4363 if (!msg)
4364 return;
4365
4366 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM);
4367 if (!hdr) {
4368 nlmsg_free(msg);
4369 return;
4370 }
4371
4372 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
4373 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
4374 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
4375 if (req_ie)
4376 NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie);
4377 if (resp_ie)
4378 NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
4379
4380 if (genlmsg_end(msg, hdr) < 0) {
4381 nlmsg_free(msg);
4382 return;
4383 }
4384
4385 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
4386 return;
4387
4388 nla_put_failure:
4389 genlmsg_cancel(msg, hdr);
4390 nlmsg_free(msg);
4391
4392}
4393
4394void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
4395 struct net_device *netdev, u16 reason,
4396 u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp)
4397{
4398 struct sk_buff *msg;
4399 void *hdr;
4400
4401 msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
4402 if (!msg)
4403 return;
4404
4405 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT);
4406 if (!hdr) {
4407 nlmsg_free(msg);
4408 return;
4409 }
4410
4411 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
4412 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
4413 if (from_ap && reason)
4414 NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason);
4415 if (from_ap)
4416 NLA_PUT_FLAG(msg, NL80211_ATTR_DISCONNECTED_BY_AP);
4417 if (ie)
4418 NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie);
4419
4420 if (genlmsg_end(msg, hdr) < 0) {
4421 nlmsg_free(msg);
4422 return;
4423 }
4424
4425 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
4426 return;
4427
4428 nla_put_failure:
4429 genlmsg_cancel(msg, hdr);
4430 nlmsg_free(msg);
4431
4432}
4433
4080void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, 4434void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
4081 struct net_device *netdev, const u8 *bssid, 4435 struct net_device *netdev, const u8 *bssid,
4082 gfp_t gfp) 4436 gfp_t gfp)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 662c216e8d4f..cf3708b48c29 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -31,6 +31,19 @@ void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
31void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, 31void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev,
32 struct net_device *netdev, 32 struct net_device *netdev,
33 const u8 *addr, gfp_t gfp); 33 const u8 *addr, gfp_t gfp);
34void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
35 struct net_device *netdev, const u8 *bssid,
36 const u8 *req_ie, size_t req_ie_len,
37 const u8 *resp_ie, size_t resp_ie_len,
38 u16 status, gfp_t gfp);
39void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
40 struct net_device *netdev, const u8 *bssid,
41 const u8 *req_ie, size_t req_ie_len,
42 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
43void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
44 struct net_device *netdev, u16 reason,
45 u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp);
46
34void 47void
35nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, 48nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
36 struct net_device *netdev, const u8 *addr, 49 struct net_device *netdev, const u8 *addr,
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
new file mode 100644
index 000000000000..fc117031d0bb
--- /dev/null
+++ b/net/wireless/sme.c
@@ -0,0 +1,224 @@
1/*
2 * SME code for cfg80211's connect emulation.
3 *
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 */
7
8#include <linux/etherdevice.h>
9#include <linux/if_arp.h>
10#include <linux/workqueue.h>
11#include <net/cfg80211.h>
12#include <net/rtnetlink.h>
13#include "nl80211.h"
14
15
16void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
17 const u8 *req_ie, size_t req_ie_len,
18 const u8 *resp_ie, size_t resp_ie_len,
19 u16 status, gfp_t gfp)
20{
21 struct wireless_dev *wdev = dev->ieee80211_ptr;
22 struct cfg80211_bss *bss;
23#ifdef CONFIG_WIRELESS_EXT
24 union iwreq_data wrqu;
25#endif
26
27 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
28 return;
29
30 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING))
31 return;
32
33 if (wdev->current_bss) {
34 cfg80211_unhold_bss(wdev->current_bss);
35 cfg80211_put_bss(wdev->current_bss);
36 wdev->current_bss = NULL;
37 }
38
39 if (status == WLAN_STATUS_SUCCESS) {
40 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
41 wdev->ssid, wdev->ssid_len,
42 WLAN_CAPABILITY_ESS,
43 WLAN_CAPABILITY_ESS);
44
45 if (WARN_ON(!bss))
46 return;
47
48 cfg80211_hold_bss(bss);
49 wdev->current_bss = bss;
50
51 wdev->sme_state = CFG80211_SME_CONNECTED;
52 } else {
53 wdev->sme_state = CFG80211_SME_IDLE;
54 }
55
56 nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid,
57 req_ie, req_ie_len, resp_ie, resp_ie_len,
58 status, gfp);
59
60#ifdef CONFIG_WIRELESS_EXT
61 if (req_ie && status == WLAN_STATUS_SUCCESS) {
62 memset(&wrqu, 0, sizeof(wrqu));
63 wrqu.data.length = req_ie_len;
64 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
65 }
66
67 if (resp_ie && status == WLAN_STATUS_SUCCESS) {
68 memset(&wrqu, 0, sizeof(wrqu));
69 wrqu.data.length = resp_ie_len;
70 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
71 }
72
73 memset(&wrqu, 0, sizeof(wrqu));
74 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
75 if (bssid)
76 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
77 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
78#endif
79}
80EXPORT_SYMBOL(cfg80211_connect_result);
81
82void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
83 const u8 *req_ie, size_t req_ie_len,
84 const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
85{
86 struct wireless_dev *wdev = dev->ieee80211_ptr;
87 struct cfg80211_bss *bss;
88#ifdef CONFIG_WIRELESS_EXT
89 union iwreq_data wrqu;
90#endif
91
92 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
93 return;
94
95 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
96 return;
97
98 /* internal error -- how did we get to CONNECTED w/o BSS? */
99 if (WARN_ON(!wdev->current_bss)) {
100 return;
101 }
102
103 cfg80211_unhold_bss(wdev->current_bss);
104 cfg80211_put_bss(wdev->current_bss);
105 wdev->current_bss = NULL;
106
107 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
108 wdev->ssid, wdev->ssid_len,
109 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
110
111 if (WARN_ON(!bss))
112 return;
113
114 cfg80211_hold_bss(bss);
115 wdev->current_bss = bss;
116
117 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid,
118 req_ie, req_ie_len, resp_ie, resp_ie_len, gfp);
119
120#ifdef CONFIG_WIRELESS_EXT
121 if (req_ie) {
122 memset(&wrqu, 0, sizeof(wrqu));
123 wrqu.data.length = req_ie_len;
124 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
125 }
126
127 if (resp_ie) {
128 memset(&wrqu, 0, sizeof(wrqu));
129 wrqu.data.length = resp_ie_len;
130 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
131 }
132
133 memset(&wrqu, 0, sizeof(wrqu));
134 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
135 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
136 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
137#endif
138}
139EXPORT_SYMBOL(cfg80211_roamed);
140
141static void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp,
142 u8 *ie, size_t ie_len, u16 reason,
143 bool from_ap)
144{
145 struct wireless_dev *wdev = dev->ieee80211_ptr;
146#ifdef CONFIG_WIRELESS_EXT
147 union iwreq_data wrqu;
148#endif
149
150 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
151 return;
152
153 if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED))
154 return;
155
156 if (wdev->current_bss) {
157 cfg80211_unhold_bss(wdev->current_bss);
158 cfg80211_put_bss(wdev->current_bss);
159 }
160
161 wdev->current_bss = NULL;
162 wdev->sme_state = CFG80211_SME_IDLE;
163
164 nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
165 reason, ie, ie_len, from_ap, gfp);
166
167#ifdef CONFIG_WIRELESS_EXT
168 memset(&wrqu, 0, sizeof(wrqu));
169 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
170 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
171#endif
172}
173
174void cfg80211_disconnected(struct net_device *dev, u16 reason,
175 u8 *ie, size_t ie_len, gfp_t gfp)
176{
177 __cfg80211_disconnected(dev, reason, ie, ie_len, true, gfp);
178}
179EXPORT_SYMBOL(cfg80211_disconnected);
180
181int cfg80211_connect(struct cfg80211_registered_device *rdev,
182 struct net_device *dev,
183 struct cfg80211_connect_params *connect)
184{
185 int err;
186 struct wireless_dev *wdev = dev->ieee80211_ptr;
187
188 if (wdev->sme_state != CFG80211_SME_IDLE)
189 return -EALREADY;
190
191 if (!rdev->ops->connect) {
192 return -EOPNOTSUPP;
193 } else {
194 wdev->sme_state = CFG80211_SME_CONNECTING;
195 err = rdev->ops->connect(&rdev->wiphy, dev, connect);
196 if (err) {
197 wdev->sme_state = CFG80211_SME_IDLE;
198 return err;
199 }
200 }
201
202 memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
203 wdev->ssid_len = connect->ssid_len;
204
205 return 0;
206}
207
208int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
209 struct net_device *dev, u16 reason)
210{
211 int err;
212
213 if (!rdev->ops->disconnect) {
214 return -EOPNOTSUPP;
215 } else {
216 err = rdev->ops->disconnect(&rdev->wiphy, dev, reason);
217 if (err)
218 return err;
219 }
220
221 __cfg80211_disconnected(dev, 0, NULL, 0, false, GFP_KERNEL);
222
223 return 0;
224}