mwifiex: add custom IE framework
[deliverable/linux.git] / drivers / net / wireless / mwifiex / ie.c
CommitLineData
ede98bfa
AP
1/*
2 * Marvell Wireless LAN device driver: management IE handling- setting and
3 * deleting IE.
4 *
5 * Copyright (C) 2012, Marvell International Ltd.
6 *
7 * This software file (the "File") is distributed by Marvell International
8 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
9 * (the "License"). You may use, redistribute and/or modify this File in
10 * accordance with the terms and conditions of the License, a copy of which
11 * is available by writing to the Free Software Foundation, Inc.,
12 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
13 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14 *
15 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
18 * this warranty disclaimer.
19 */
20
21#include "main.h"
22
23/* This function checks if current IE index is used by any on other interface.
24 * Return: -1: yes, current IE index is used by someone else.
25 * 0: no, current IE index is NOT used by other interface.
26 */
27static int
28mwifiex_ie_index_used_by_other_intf(struct mwifiex_private *priv, u16 idx)
29{
30 int i;
31 struct mwifiex_adapter *adapter = priv->adapter;
32 struct mwifiex_ie *ie;
33
34 for (i = 0; i < adapter->priv_num; i++) {
35 if (adapter->priv[i] != priv) {
36 ie = &adapter->priv[i]->mgmt_ie[idx];
37 if (ie->mgmt_subtype_mask && ie->ie_length)
38 return -1;
39 }
40 }
41
42 return 0;
43}
44
45/* Get unused IE index. This index will be used for setting new IE */
46static int
47mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask,
48 struct mwifiex_ie *ie, u16 *index)
49{
50 u16 mask, len, i;
51
52 for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) {
53 mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask);
54 len = le16_to_cpu(priv->mgmt_ie[i].ie_length) +
55 le16_to_cpu(ie->ie_length);
56
57 if (mask == MWIFIEX_AUTO_IDX_MASK)
58 continue;
59
60 if (mask == subtype_mask) {
61 if (len > IEEE_MAX_IE_SIZE)
62 continue;
63
64 *index = i;
65 return 0;
66 }
67
68 if (!priv->mgmt_ie[i].ie_length) {
69 if (mwifiex_ie_index_used_by_other_intf(priv, i))
70 continue;
71
72 *index = i;
73 return 0;
74 }
75 }
76
77 return -1;
78}
79
80/* This function prepares IE data buffer for command to be sent to FW */
81static int
82mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
83 struct mwifiex_ie_list *ie_list)
84{
85 u16 travel_len, index, mask;
86 s16 input_len;
87 struct mwifiex_ie *ie;
88 u8 *tmp;
89
90 input_len = le16_to_cpu(ie_list->len);
91 travel_len = sizeof(struct host_cmd_tlv);
92
93 ie_list->len = 0;
94
95 while (input_len > 0) {
96 ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len);
97 input_len -= le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
98 travel_len += le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
99
100 index = le16_to_cpu(ie->ie_index);
101 mask = le16_to_cpu(ie->mgmt_subtype_mask);
102
103 if (index == MWIFIEX_AUTO_IDX_MASK) {
104 /* automatic addition */
105 if (mwifiex_ie_get_autoidx(priv, mask, ie, &index))
106 return -1;
107 if (index == MWIFIEX_AUTO_IDX_MASK)
108 return -1;
109
110 tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer;
111 tmp += le16_to_cpu(priv->mgmt_ie[index].ie_length);
112 memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length));
113 le16_add_cpu(&priv->mgmt_ie[index].ie_length,
114 le16_to_cpu(ie->ie_length));
115 priv->mgmt_ie[index].ie_index = cpu_to_le16(index);
116 priv->mgmt_ie[index].mgmt_subtype_mask =
117 cpu_to_le16(mask);
118
119 ie->ie_index = cpu_to_le16(index);
120 ie->ie_length = priv->mgmt_ie[index].ie_length;
121 memcpy(&ie->ie_buffer, &priv->mgmt_ie[index].ie_buffer,
122 le16_to_cpu(priv->mgmt_ie[index].ie_length));
123 } else {
124 if (mask != MWIFIEX_DELETE_MASK)
125 return -1;
126 /*
127 * Check if this index is being used on any
128 * other interface.
129 */
130 if (mwifiex_ie_index_used_by_other_intf(priv, index))
131 return -1;
132
133 ie->ie_length = 0;
134 memcpy(&priv->mgmt_ie[index], ie,
135 sizeof(struct mwifiex_ie));
136 }
137
138 le16_add_cpu(&ie_list->len,
139 le16_to_cpu(priv->mgmt_ie[index].ie_length) +
140 MWIFIEX_IE_HDR_SIZE);
141 }
142
143 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
144 return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
145 HostCmd_ACT_GEN_SET,
146 UAP_CUSTOM_IE_I, ie_list);
147
148 return 0;
149}
This page took 0.029377 seconds and 5 git commands to generate.