aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
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,