diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/nl80211.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c034c2418cb3..9e1318d1d4bb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -111,6 +111,11 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
111 | .len = IEEE80211_MAX_DATA_LEN }, | 111 | .len = IEEE80211_MAX_DATA_LEN }, |
112 | [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, | 112 | [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, |
113 | [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, | 113 | [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, |
114 | |||
115 | [NL80211_ATTR_SSID] = { .type = NLA_BINARY, | ||
116 | .len = IEEE80211_MAX_SSID_LEN }, | ||
117 | [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, | ||
118 | [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, | ||
114 | }; | 119 | }; |
115 | 120 | ||
116 | /* message building helper */ | 121 | /* message building helper */ |
@@ -265,6 +270,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
265 | CMD(set_mesh_params, SET_MESH_PARAMS); | 270 | CMD(set_mesh_params, SET_MESH_PARAMS); |
266 | CMD(change_bss, SET_BSS); | 271 | CMD(change_bss, SET_BSS); |
267 | CMD(set_mgmt_extra_ie, SET_MGMT_EXTRA_IE); | 272 | CMD(set_mgmt_extra_ie, SET_MGMT_EXTRA_IE); |
273 | CMD(auth, AUTHENTICATE); | ||
274 | CMD(assoc, ASSOCIATE); | ||
275 | CMD(deauth, DEAUTHENTICATE); | ||
276 | CMD(disassoc, DISASSOCIATE); | ||
268 | 277 | ||
269 | #undef CMD | 278 | #undef CMD |
270 | nla_nest_end(msg, nl_cmds); | 279 | nla_nest_end(msg, nl_cmds); |
@@ -2646,6 +2655,228 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
2646 | return err; | 2655 | return err; |
2647 | } | 2656 | } |
2648 | 2657 | ||
2658 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | ||
2659 | { | ||
2660 | struct cfg80211_registered_device *drv; | ||
2661 | struct net_device *dev; | ||
2662 | struct cfg80211_auth_request req; | ||
2663 | struct wiphy *wiphy; | ||
2664 | int err; | ||
2665 | |||
2666 | rtnl_lock(); | ||
2667 | |||
2668 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2669 | if (err) | ||
2670 | goto unlock_rtnl; | ||
2671 | |||
2672 | if (!drv->ops->auth) { | ||
2673 | err = -EOPNOTSUPP; | ||
2674 | goto out; | ||
2675 | } | ||
2676 | |||
2677 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2678 | err = -EINVAL; | ||
2679 | goto out; | ||
2680 | } | ||
2681 | |||
2682 | wiphy = &drv->wiphy; | ||
2683 | memset(&req, 0, sizeof(req)); | ||
2684 | |||
2685 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2686 | |||
2687 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2688 | req.chan = ieee80211_get_channel( | ||
2689 | wiphy, | ||
2690 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
2691 | if (!req.chan) { | ||
2692 | err = -EINVAL; | ||
2693 | goto out; | ||
2694 | } | ||
2695 | } | ||
2696 | |||
2697 | if (info->attrs[NL80211_ATTR_SSID]) { | ||
2698 | req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
2699 | req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
2700 | } | ||
2701 | |||
2702 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2703 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2704 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2705 | } | ||
2706 | |||
2707 | if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { | ||
2708 | req.auth_type = | ||
2709 | nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | ||
2710 | } | ||
2711 | |||
2712 | err = drv->ops->auth(&drv->wiphy, dev, &req); | ||
2713 | |||
2714 | out: | ||
2715 | cfg80211_put_dev(drv); | ||
2716 | dev_put(dev); | ||
2717 | unlock_rtnl: | ||
2718 | rtnl_unlock(); | ||
2719 | return err; | ||
2720 | } | ||
2721 | |||
2722 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | ||
2723 | { | ||
2724 | struct cfg80211_registered_device *drv; | ||
2725 | struct net_device *dev; | ||
2726 | struct cfg80211_assoc_request req; | ||
2727 | struct wiphy *wiphy; | ||
2728 | int err; | ||
2729 | |||
2730 | rtnl_lock(); | ||
2731 | |||
2732 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2733 | if (err) | ||
2734 | goto unlock_rtnl; | ||
2735 | |||
2736 | if (!drv->ops->assoc) { | ||
2737 | err = -EOPNOTSUPP; | ||
2738 | goto out; | ||
2739 | } | ||
2740 | |||
2741 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
2742 | !info->attrs[NL80211_ATTR_SSID]) { | ||
2743 | err = -EINVAL; | ||
2744 | goto out; | ||
2745 | } | ||
2746 | |||
2747 | wiphy = &drv->wiphy; | ||
2748 | memset(&req, 0, sizeof(req)); | ||
2749 | |||
2750 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2751 | |||
2752 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2753 | req.chan = ieee80211_get_channel( | ||
2754 | wiphy, | ||
2755 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
2756 | if (!req.chan) { | ||
2757 | err = -EINVAL; | ||
2758 | goto out; | ||
2759 | } | ||
2760 | } | ||
2761 | |||
2762 | if (nla_len(info->attrs[NL80211_ATTR_SSID]) > IEEE80211_MAX_SSID_LEN) { | ||
2763 | err = -EINVAL; | ||
2764 | goto out; | ||
2765 | } | ||
2766 | req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
2767 | req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
2768 | |||
2769 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2770 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2771 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2772 | } | ||
2773 | |||
2774 | err = drv->ops->assoc(&drv->wiphy, dev, &req); | ||
2775 | |||
2776 | out: | ||
2777 | cfg80211_put_dev(drv); | ||
2778 | dev_put(dev); | ||
2779 | unlock_rtnl: | ||
2780 | rtnl_unlock(); | ||
2781 | return err; | ||
2782 | } | ||
2783 | |||
2784 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | ||
2785 | { | ||
2786 | struct cfg80211_registered_device *drv; | ||
2787 | struct net_device *dev; | ||
2788 | struct cfg80211_deauth_request req; | ||
2789 | struct wiphy *wiphy; | ||
2790 | int err; | ||
2791 | |||
2792 | rtnl_lock(); | ||
2793 | |||
2794 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2795 | if (err) | ||
2796 | goto unlock_rtnl; | ||
2797 | |||
2798 | if (!drv->ops->deauth) { | ||
2799 | err = -EOPNOTSUPP; | ||
2800 | goto out; | ||
2801 | } | ||
2802 | |||
2803 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2804 | err = -EINVAL; | ||
2805 | goto out; | ||
2806 | } | ||
2807 | |||
2808 | wiphy = &drv->wiphy; | ||
2809 | memset(&req, 0, sizeof(req)); | ||
2810 | |||
2811 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2812 | |||
2813 | if (info->attrs[NL80211_ATTR_REASON_CODE]) | ||
2814 | req.reason_code = | ||
2815 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | ||
2816 | |||
2817 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2818 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2819 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2820 | } | ||
2821 | |||
2822 | err = drv->ops->deauth(&drv->wiphy, dev, &req); | ||
2823 | |||
2824 | out: | ||
2825 | cfg80211_put_dev(drv); | ||
2826 | dev_put(dev); | ||
2827 | unlock_rtnl: | ||
2828 | rtnl_unlock(); | ||
2829 | return err; | ||
2830 | } | ||
2831 | |||
2832 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | ||
2833 | { | ||
2834 | struct cfg80211_registered_device *drv; | ||
2835 | struct net_device *dev; | ||
2836 | struct cfg80211_disassoc_request req; | ||
2837 | struct wiphy *wiphy; | ||
2838 | int err; | ||
2839 | |||
2840 | rtnl_lock(); | ||
2841 | |||
2842 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2843 | if (err) | ||
2844 | goto unlock_rtnl; | ||
2845 | |||
2846 | if (!drv->ops->disassoc) { | ||
2847 | err = -EOPNOTSUPP; | ||
2848 | goto out; | ||
2849 | } | ||
2850 | |||
2851 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2852 | err = -EINVAL; | ||
2853 | goto out; | ||
2854 | } | ||
2855 | |||
2856 | wiphy = &drv->wiphy; | ||
2857 | memset(&req, 0, sizeof(req)); | ||
2858 | |||
2859 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2860 | |||
2861 | if (info->attrs[NL80211_ATTR_REASON_CODE]) | ||
2862 | req.reason_code = | ||
2863 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | ||
2864 | |||
2865 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2866 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2867 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2868 | } | ||
2869 | |||
2870 | err = drv->ops->disassoc(&drv->wiphy, dev, &req); | ||
2871 | |||
2872 | out: | ||
2873 | cfg80211_put_dev(drv); | ||
2874 | dev_put(dev); | ||
2875 | unlock_rtnl: | ||
2876 | rtnl_unlock(); | ||
2877 | return err; | ||
2878 | } | ||
2879 | |||
2649 | static struct genl_ops nl80211_ops[] = { | 2880 | static struct genl_ops nl80211_ops[] = { |
2650 | { | 2881 | { |
2651 | .cmd = NL80211_CMD_GET_WIPHY, | 2882 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -2829,6 +3060,30 @@ static struct genl_ops nl80211_ops[] = { | |||
2829 | .policy = nl80211_policy, | 3060 | .policy = nl80211_policy, |
2830 | .dumpit = nl80211_dump_scan, | 3061 | .dumpit = nl80211_dump_scan, |
2831 | }, | 3062 | }, |
3063 | { | ||
3064 | .cmd = NL80211_CMD_AUTHENTICATE, | ||
3065 | .doit = nl80211_authenticate, | ||
3066 | .policy = nl80211_policy, | ||
3067 | .flags = GENL_ADMIN_PERM, | ||
3068 | }, | ||
3069 | { | ||
3070 | .cmd = NL80211_CMD_ASSOCIATE, | ||
3071 | .doit = nl80211_associate, | ||
3072 | .policy = nl80211_policy, | ||
3073 | .flags = GENL_ADMIN_PERM, | ||
3074 | }, | ||
3075 | { | ||
3076 | .cmd = NL80211_CMD_DEAUTHENTICATE, | ||
3077 | .doit = nl80211_deauthenticate, | ||
3078 | .policy = nl80211_policy, | ||
3079 | .flags = GENL_ADMIN_PERM, | ||
3080 | }, | ||
3081 | { | ||
3082 | .cmd = NL80211_CMD_DISASSOCIATE, | ||
3083 | .doit = nl80211_disassociate, | ||
3084 | .policy = nl80211_policy, | ||
3085 | .flags = GENL_ADMIN_PERM, | ||
3086 | }, | ||
2832 | }; | 3087 | }; |
2833 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 3088 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
2834 | .name = "mlme", | 3089 | .name = "mlme", |