aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2009-07-01 15:26:54 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:01:51 -0400
commitb23aa676ab9d54469cda9f7151f51a2851c6f36e (patch)
treedd4af5fa38dbfec362ded1d655ed584bbcf60a53 /net/wireless/nl80211.c
parent6a669e65c5ec393a650362874e13f7d3365a7827 (diff)
cfg80211: connect/disconnect API
This patch introduces the cfg80211 connect/disconnect API. The goal here is to run the AUTH and ASSOC steps in one call. This is needed for some fullmac cards that run both steps directly from the target, after the host driver sends a connect command. Additionally, all the new crypto parameters for connect() are now also valid for associate() -- although associate requires the IEs to be used, the information can be useful for drivers and should be given. Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com> 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.c368
1 files changed, 361 insertions, 7 deletions
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)