diff options
-rw-r--r-- | include/linux/nl80211.h | 24 | ||||
-rw-r--r-- | include/net/cfg80211.h | 33 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 133 |
3 files changed, 190 insertions, 0 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 8dc807d9c29a..f1e455a8b4de 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -47,6 +47,15 @@ | |||
47 | * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX | 47 | * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX |
48 | * or %NL80211_ATTR_MAC. | 48 | * or %NL80211_ATTR_MAC. |
49 | * | 49 | * |
50 | * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a | ||
51 | * %NL80222_CMD_NEW_BEACON message) | ||
52 | * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface | ||
53 | * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, | ||
54 | * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes. | ||
55 | * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface, | ||
56 | * parameters are like for %NL80211_CMD_SET_BEACON. | ||
57 | * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it | ||
58 | * | ||
50 | * @NL80211_CMD_MAX: highest used command number | 59 | * @NL80211_CMD_MAX: highest used command number |
51 | * @__NL80211_CMD_AFTER_LAST: internal use | 60 | * @__NL80211_CMD_AFTER_LAST: internal use |
52 | */ | 61 | */ |
@@ -69,6 +78,11 @@ enum nl80211_commands { | |||
69 | NL80211_CMD_NEW_KEY, | 78 | NL80211_CMD_NEW_KEY, |
70 | NL80211_CMD_DEL_KEY, | 79 | NL80211_CMD_DEL_KEY, |
71 | 80 | ||
81 | NL80211_CMD_GET_BEACON, | ||
82 | NL80211_CMD_SET_BEACON, | ||
83 | NL80211_CMD_NEW_BEACON, | ||
84 | NL80211_CMD_DEL_BEACON, | ||
85 | |||
72 | /* add commands here */ | 86 | /* add commands here */ |
73 | 87 | ||
74 | /* used to define NL80211_CMD_MAX below */ | 88 | /* used to define NL80211_CMD_MAX below */ |
@@ -101,6 +115,11 @@ enum nl80211_commands { | |||
101 | * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and | 115 | * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and |
102 | * CCMP keys, each six bytes in little endian | 116 | * CCMP keys, each six bytes in little endian |
103 | * | 117 | * |
118 | * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU | ||
119 | * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing | ||
120 | * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE | ||
121 | * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE | ||
122 | * | ||
104 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 123 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
105 | * @__NL80211_ATTR_AFTER_LAST: internal use | 124 | * @__NL80211_ATTR_AFTER_LAST: internal use |
106 | */ | 125 | */ |
@@ -123,6 +142,11 @@ enum nl80211_attrs { | |||
123 | NL80211_ATTR_KEY_SEQ, | 142 | NL80211_ATTR_KEY_SEQ, |
124 | NL80211_ATTR_KEY_DEFAULT, | 143 | NL80211_ATTR_KEY_DEFAULT, |
125 | 144 | ||
145 | NL80211_ATTR_BEACON_INTERVAL, | ||
146 | NL80211_ATTR_DTIM_PERIOD, | ||
147 | NL80211_ATTR_BEACON_HEAD, | ||
148 | NL80211_ATTR_BEACON_TAIL, | ||
149 | |||
126 | /* add attributes here, update the policy in nl80211.c */ | 150 | /* add attributes here, update the policy in nl80211.c */ |
127 | 151 | ||
128 | __NL80211_ATTR_AFTER_LAST, | 152 | __NL80211_ATTR_AFTER_LAST, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3db7dfa53b6f..fc94852e967b 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -69,6 +69,26 @@ struct key_params { | |||
69 | u32 cipher; | 69 | u32 cipher; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | /** | ||
73 | * struct beacon_parameters - beacon parameters | ||
74 | * | ||
75 | * Used to configure the beacon for an interface. | ||
76 | * | ||
77 | * @head: head portion of beacon (before TIM IE) | ||
78 | * or %NULL if not changed | ||
79 | * @tail: tail portion of beacon (after TIM IE) | ||
80 | * or %NULL if not changed | ||
81 | * @interval: beacon interval or zero if not changed | ||
82 | * @dtim_period: DTIM period or zero if not changed | ||
83 | * @head_len: length of @head | ||
84 | * @tail_len: length of @tail | ||
85 | */ | ||
86 | struct beacon_parameters { | ||
87 | u8 *head, *tail; | ||
88 | int interval, dtim_period; | ||
89 | int head_len, tail_len; | ||
90 | }; | ||
91 | |||
72 | /* from net/wireless.h */ | 92 | /* from net/wireless.h */ |
73 | struct wiphy; | 93 | struct wiphy; |
74 | 94 | ||
@@ -103,6 +123,13 @@ struct wiphy; | |||
103 | * and @key_index | 123 | * and @key_index |
104 | * | 124 | * |
105 | * @set_default_key: set the default key on an interface | 125 | * @set_default_key: set the default key on an interface |
126 | * | ||
127 | * @add_beacon: Add a beacon with given parameters, @head, @interval | ||
128 | * and @dtim_period will be valid, @tail is optional. | ||
129 | * @set_beacon: Change the beacon parameters for an access point mode | ||
130 | * interface. This should reject the call when no beacon has been | ||
131 | * configured. | ||
132 | * @del_beacon: Remove beacon configuration and stop sending the beacon. | ||
106 | */ | 133 | */ |
107 | struct cfg80211_ops { | 134 | struct cfg80211_ops { |
108 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, | 135 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, |
@@ -122,6 +149,12 @@ struct cfg80211_ops { | |||
122 | int (*set_default_key)(struct wiphy *wiphy, | 149 | int (*set_default_key)(struct wiphy *wiphy, |
123 | struct net_device *netdev, | 150 | struct net_device *netdev, |
124 | u8 key_index); | 151 | u8 key_index); |
152 | |||
153 | int (*add_beacon)(struct wiphy *wiphy, struct net_device *dev, | ||
154 | struct beacon_parameters *info); | ||
155 | int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, | ||
156 | struct beacon_parameters *info); | ||
157 | int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); | ||
125 | }; | 158 | }; |
126 | 159 | ||
127 | #endif /* __NET_CFG80211_H */ | 160 | #endif /* __NET_CFG80211_H */ |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 090936388528..306ae019ea81 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -69,6 +69,13 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
69 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, | 69 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, |
70 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 70 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
71 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 71 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
72 | |||
73 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | ||
74 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | ||
75 | [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY, | ||
76 | .len = IEEE80211_MAX_DATA_LEN }, | ||
77 | [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, | ||
78 | .len = IEEE80211_MAX_DATA_LEN }, | ||
72 | }; | 79 | }; |
73 | 80 | ||
74 | /* message building helper */ | 81 | /* message building helper */ |
@@ -600,6 +607,114 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
600 | return err; | 607 | return err; |
601 | } | 608 | } |
602 | 609 | ||
610 | static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | ||
611 | { | ||
612 | int (*call)(struct wiphy *wiphy, struct net_device *dev, | ||
613 | struct beacon_parameters *info); | ||
614 | struct cfg80211_registered_device *drv; | ||
615 | int err; | ||
616 | struct net_device *dev; | ||
617 | struct beacon_parameters params; | ||
618 | int haveinfo = 0; | ||
619 | |||
620 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
621 | if (err) | ||
622 | return err; | ||
623 | |||
624 | switch (info->genlhdr->cmd) { | ||
625 | case NL80211_CMD_NEW_BEACON: | ||
626 | /* these are required for NEW_BEACON */ | ||
627 | if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || | ||
628 | !info->attrs[NL80211_ATTR_DTIM_PERIOD] || | ||
629 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) { | ||
630 | err = -EINVAL; | ||
631 | goto out; | ||
632 | } | ||
633 | |||
634 | call = drv->ops->add_beacon; | ||
635 | break; | ||
636 | case NL80211_CMD_SET_BEACON: | ||
637 | call = drv->ops->set_beacon; | ||
638 | break; | ||
639 | default: | ||
640 | WARN_ON(1); | ||
641 | err = -EOPNOTSUPP; | ||
642 | goto out; | ||
643 | } | ||
644 | |||
645 | if (!call) { | ||
646 | err = -EOPNOTSUPP; | ||
647 | goto out; | ||
648 | } | ||
649 | |||
650 | memset(¶ms, 0, sizeof(params)); | ||
651 | |||
652 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | ||
653 | params.interval = | ||
654 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | ||
655 | haveinfo = 1; | ||
656 | } | ||
657 | |||
658 | if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { | ||
659 | params.dtim_period = | ||
660 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); | ||
661 | haveinfo = 1; | ||
662 | } | ||
663 | |||
664 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { | ||
665 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); | ||
666 | params.head_len = | ||
667 | nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]); | ||
668 | haveinfo = 1; | ||
669 | } | ||
670 | |||
671 | if (info->attrs[NL80211_ATTR_BEACON_TAIL]) { | ||
672 | params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]); | ||
673 | params.tail_len = | ||
674 | nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]); | ||
675 | haveinfo = 1; | ||
676 | } | ||
677 | |||
678 | if (!haveinfo) { | ||
679 | err = -EINVAL; | ||
680 | goto out; | ||
681 | } | ||
682 | |||
683 | rtnl_lock(); | ||
684 | err = call(&drv->wiphy, dev, ¶ms); | ||
685 | rtnl_unlock(); | ||
686 | |||
687 | out: | ||
688 | cfg80211_put_dev(drv); | ||
689 | dev_put(dev); | ||
690 | return err; | ||
691 | } | ||
692 | |||
693 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | ||
694 | { | ||
695 | struct cfg80211_registered_device *drv; | ||
696 | int err; | ||
697 | struct net_device *dev; | ||
698 | |||
699 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
700 | if (err) | ||
701 | return err; | ||
702 | |||
703 | if (!drv->ops->del_beacon) { | ||
704 | err = -EOPNOTSUPP; | ||
705 | goto out; | ||
706 | } | ||
707 | |||
708 | rtnl_lock(); | ||
709 | err = drv->ops->del_beacon(&drv->wiphy, dev); | ||
710 | rtnl_unlock(); | ||
711 | |||
712 | out: | ||
713 | cfg80211_put_dev(drv); | ||
714 | dev_put(dev); | ||
715 | return err; | ||
716 | } | ||
717 | |||
603 | static struct genl_ops nl80211_ops[] = { | 718 | static struct genl_ops nl80211_ops[] = { |
604 | { | 719 | { |
605 | .cmd = NL80211_CMD_GET_WIPHY, | 720 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -663,6 +778,24 @@ static struct genl_ops nl80211_ops[] = { | |||
663 | .policy = nl80211_policy, | 778 | .policy = nl80211_policy, |
664 | .flags = GENL_ADMIN_PERM, | 779 | .flags = GENL_ADMIN_PERM, |
665 | }, | 780 | }, |
781 | { | ||
782 | .cmd = NL80211_CMD_SET_BEACON, | ||
783 | .policy = nl80211_policy, | ||
784 | .flags = GENL_ADMIN_PERM, | ||
785 | .doit = nl80211_addset_beacon, | ||
786 | }, | ||
787 | { | ||
788 | .cmd = NL80211_CMD_NEW_BEACON, | ||
789 | .policy = nl80211_policy, | ||
790 | .flags = GENL_ADMIN_PERM, | ||
791 | .doit = nl80211_addset_beacon, | ||
792 | }, | ||
793 | { | ||
794 | .cmd = NL80211_CMD_DEL_BEACON, | ||
795 | .policy = nl80211_policy, | ||
796 | .flags = GENL_ADMIN_PERM, | ||
797 | .doit = nl80211_del_beacon, | ||
798 | }, | ||
666 | }; | 799 | }; |
667 | 800 | ||
668 | /* multicast groups */ | 801 | /* multicast groups */ |