diff options
-rw-r--r-- | net/batman-adv/vis.c | 224 |
1 files changed, 81 insertions, 143 deletions
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index 6b7a1c05e45e..3095c41a67ad 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c | |||
@@ -140,72 +140,117 @@ static void batadv_vis_data_insert_interface(const uint8_t *interface, | |||
140 | hlist_add_head(&entry->list, if_list); | 140 | hlist_add_head(&entry->list, if_list); |
141 | } | 141 | } |
142 | 142 | ||
143 | static ssize_t batadv_vis_prim_sec(char *buff, const struct hlist_head *if_list) | 143 | static void batadv_vis_data_read_prim_sec(struct seq_file *seq, |
144 | const struct hlist_head *if_list) | ||
144 | { | 145 | { |
145 | struct if_list_entry *entry; | 146 | struct if_list_entry *entry; |
146 | struct hlist_node *pos; | 147 | struct hlist_node *pos; |
147 | size_t len = 0; | ||
148 | 148 | ||
149 | hlist_for_each_entry(entry, pos, if_list, list) { | 149 | hlist_for_each_entry(entry, pos, if_list, list) { |
150 | if (entry->primary) | 150 | if (entry->primary) |
151 | len += sprintf(buff + len, "PRIMARY, "); | 151 | seq_printf(seq, "PRIMARY, "); |
152 | else | 152 | else |
153 | len += sprintf(buff + len, "SEC %pM, ", entry->addr); | 153 | seq_printf(seq, "SEC %pM, ", entry->addr); |
154 | } | 154 | } |
155 | } | ||
156 | |||
157 | /* read an entry */ | ||
158 | static ssize_t batadv_vis_data_read_entry(struct seq_file *seq, | ||
159 | const struct vis_info_entry *entry, | ||
160 | const uint8_t *src, bool primary) | ||
161 | { | ||
162 | if (primary && entry->quality == 0) | ||
163 | return seq_printf(seq, "TT %pM, ", entry->dest); | ||
164 | else if (batadv_compare_eth(entry->src, src)) | ||
165 | return seq_printf(seq, "TQ %pM %d, ", entry->dest, | ||
166 | entry->quality); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static void batadv_vis_data_insert_interfaces(struct hlist_head *list, | ||
172 | struct vis_packet *packet, | ||
173 | struct vis_info_entry *entries) | ||
174 | { | ||
175 | int i; | ||
176 | |||
177 | for (i = 0; i < packet->entries; i++) { | ||
178 | if (entries[i].quality == 0) | ||
179 | continue; | ||
155 | 180 | ||
156 | return len; | 181 | if (batadv_compare_eth(entries[i].src, packet->vis_orig)) |
182 | continue; | ||
183 | |||
184 | batadv_vis_data_insert_interface(entries[i].src, list, false); | ||
185 | } | ||
157 | } | 186 | } |
158 | 187 | ||
159 | static size_t batadv_vis_cnt_prim_sec(struct hlist_head *if_list) | 188 | static void batadv_vis_data_read_entries(struct seq_file *seq, |
189 | struct hlist_head *list, | ||
190 | struct vis_packet *packet, | ||
191 | struct vis_info_entry *entries) | ||
160 | { | 192 | { |
193 | int i; | ||
161 | struct if_list_entry *entry; | 194 | struct if_list_entry *entry; |
162 | struct hlist_node *pos; | 195 | struct hlist_node *pos; |
163 | size_t count = 0; | ||
164 | 196 | ||
165 | hlist_for_each_entry(entry, pos, if_list, list) { | 197 | hlist_for_each_entry(entry, pos, list, list) { |
166 | if (entry->primary) | 198 | seq_printf(seq, "%pM,", entry->addr); |
167 | count += 9; | 199 | |
168 | else | 200 | for (i = 0; i < packet->entries; i++) |
169 | count += 23; | 201 | batadv_vis_data_read_entry(seq, &entries[i], |
170 | } | 202 | entry->addr, entry->primary); |
171 | 203 | ||
172 | return count; | 204 | /* add primary/secondary records */ |
205 | if (batadv_compare_eth(entry->addr, packet->vis_orig)) | ||
206 | batadv_vis_data_read_prim_sec(seq, list); | ||
207 | |||
208 | seq_printf(seq, "\n"); | ||
209 | } | ||
173 | } | 210 | } |
174 | 211 | ||
175 | /* read an entry */ | 212 | static void batadv_vis_seq_print_text_bucket(struct seq_file *seq, |
176 | static ssize_t batadv_vis_data_read_entry(char *buff, | 213 | const struct hlist_head *head) |
177 | const struct vis_info_entry *entry, | ||
178 | const uint8_t *src, bool primary) | ||
179 | { | 214 | { |
180 | /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ | 215 | struct hlist_node *node; |
181 | if (primary && entry->quality == 0) | 216 | struct vis_info *info; |
182 | return sprintf(buff, "TT %pM, ", entry->dest); | 217 | struct vis_packet *packet; |
183 | else if (batadv_compare_eth(entry->src, src)) | 218 | uint8_t *entries_pos; |
184 | return sprintf(buff, "TQ %pM %d, ", entry->dest, | 219 | struct vis_info_entry *entries; |
185 | entry->quality); | 220 | struct if_list_entry *entry; |
221 | struct hlist_node *pos, *n; | ||
186 | 222 | ||
187 | return 0; | 223 | HLIST_HEAD(vis_if_list); |
224 | |||
225 | hlist_for_each_entry_rcu(info, node, head, hash_entry) { | ||
226 | packet = (struct vis_packet *)info->skb_packet->data; | ||
227 | entries_pos = (uint8_t *)packet + sizeof(*packet); | ||
228 | entries = (struct vis_info_entry *)entries_pos; | ||
229 | |||
230 | batadv_vis_data_insert_interface(packet->vis_orig, &vis_if_list, | ||
231 | true); | ||
232 | batadv_vis_data_insert_interfaces(&vis_if_list, packet, | ||
233 | entries); | ||
234 | batadv_vis_data_read_entries(seq, &vis_if_list, packet, | ||
235 | entries); | ||
236 | |||
237 | hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) { | ||
238 | hlist_del(&entry->list); | ||
239 | kfree(entry); | ||
240 | } | ||
241 | } | ||
188 | } | 242 | } |
189 | 243 | ||
190 | int batadv_vis_seq_print_text(struct seq_file *seq, void *offset) | 244 | int batadv_vis_seq_print_text(struct seq_file *seq, void *offset) |
191 | { | 245 | { |
192 | struct hard_iface *primary_if; | 246 | struct hard_iface *primary_if; |
193 | struct hlist_node *node; | ||
194 | struct hlist_head *head; | 247 | struct hlist_head *head; |
195 | struct vis_info *info; | ||
196 | struct vis_packet *packet; | ||
197 | struct vis_info_entry *entries; | ||
198 | struct net_device *net_dev = (struct net_device *)seq->private; | 248 | struct net_device *net_dev = (struct net_device *)seq->private; |
199 | struct bat_priv *bat_priv = netdev_priv(net_dev); | 249 | struct bat_priv *bat_priv = netdev_priv(net_dev); |
200 | struct hashtable_t *hash = bat_priv->vis_hash; | 250 | struct hashtable_t *hash = bat_priv->vis_hash; |
201 | HLIST_HEAD(vis_if_list); | ||
202 | struct if_list_entry *entry; | ||
203 | struct hlist_node *pos, *n; | ||
204 | uint32_t i; | 251 | uint32_t i; |
205 | int j, ret = 0; | 252 | int ret = 0; |
206 | int vis_server = atomic_read(&bat_priv->vis_mode); | 253 | int vis_server = atomic_read(&bat_priv->vis_mode); |
207 | size_t buff_pos, buf_size; | ||
208 | char *buff; | ||
209 | 254 | ||
210 | primary_if = batadv_primary_if_get_selected(bat_priv); | 255 | primary_if = batadv_primary_if_get_selected(bat_priv); |
211 | if (!primary_if) | 256 | if (!primary_if) |
@@ -214,120 +259,13 @@ int batadv_vis_seq_print_text(struct seq_file *seq, void *offset) | |||
214 | if (vis_server == VIS_TYPE_CLIENT_UPDATE) | 259 | if (vis_server == VIS_TYPE_CLIENT_UPDATE) |
215 | goto out; | 260 | goto out; |
216 | 261 | ||
217 | buf_size = 1; | ||
218 | /* Estimate length */ | ||
219 | spin_lock_bh(&bat_priv->vis_hash_lock); | 262 | spin_lock_bh(&bat_priv->vis_hash_lock); |
220 | for (i = 0; i < hash->size; i++) { | 263 | for (i = 0; i < hash->size; i++) { |
221 | head = &hash->table[i]; | 264 | head = &hash->table[i]; |
222 | 265 | batadv_vis_seq_print_text_bucket(seq, head); | |
223 | rcu_read_lock(); | ||
224 | hlist_for_each_entry_rcu(info, node, head, hash_entry) { | ||
225 | packet = (struct vis_packet *)info->skb_packet->data; | ||
226 | entries = (struct vis_info_entry *) | ||
227 | ((char *)packet + sizeof(*packet)); | ||
228 | |||
229 | batadv_vis_data_insert_interface(packet->vis_orig, | ||
230 | &vis_if_list, true); | ||
231 | |||
232 | for (j = 0; j < packet->entries; j++) { | ||
233 | if (entries[j].quality == 0) | ||
234 | continue; | ||
235 | if (batadv_compare_eth(entries[j].src, | ||
236 | packet->vis_orig)) | ||
237 | continue; | ||
238 | batadv_vis_data_insert_interface(entries[j].src, | ||
239 | &vis_if_list, | ||
240 | false); | ||
241 | } | ||
242 | |||
243 | hlist_for_each_entry(entry, pos, &vis_if_list, list) { | ||
244 | buf_size += 18 + 26 * packet->entries; | ||
245 | |||
246 | /* add primary/secondary records */ | ||
247 | if (batadv_compare_eth(entry->addr, | ||
248 | packet->vis_orig)) | ||
249 | buf_size += | ||
250 | batadv_vis_cnt_prim_sec(&vis_if_list); | ||
251 | |||
252 | buf_size += 1; | ||
253 | } | ||
254 | |||
255 | hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, | ||
256 | list) { | ||
257 | hlist_del(&entry->list); | ||
258 | kfree(entry); | ||
259 | } | ||
260 | } | ||
261 | rcu_read_unlock(); | ||
262 | } | 266 | } |
263 | |||
264 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
265 | if (!buff) { | ||
266 | spin_unlock_bh(&bat_priv->vis_hash_lock); | ||
267 | ret = -ENOMEM; | ||
268 | goto out; | ||
269 | } | ||
270 | buff[0] = '\0'; | ||
271 | buff_pos = 0; | ||
272 | |||
273 | for (i = 0; i < hash->size; i++) { | ||
274 | head = &hash->table[i]; | ||
275 | |||
276 | rcu_read_lock(); | ||
277 | hlist_for_each_entry_rcu(info, node, head, hash_entry) { | ||
278 | packet = (struct vis_packet *)info->skb_packet->data; | ||
279 | entries = (struct vis_info_entry *) | ||
280 | ((char *)packet + sizeof(*packet)); | ||
281 | |||
282 | batadv_vis_data_insert_interface(packet->vis_orig, | ||
283 | &vis_if_list, true); | ||
284 | |||
285 | for (j = 0; j < packet->entries; j++) { | ||
286 | if (entries[j].quality == 0) | ||
287 | continue; | ||
288 | if (batadv_compare_eth(entries[j].src, | ||
289 | packet->vis_orig)) | ||
290 | continue; | ||
291 | batadv_vis_data_insert_interface(entries[j].src, | ||
292 | &vis_if_list, | ||
293 | false); | ||
294 | } | ||
295 | |||
296 | hlist_for_each_entry(entry, pos, &vis_if_list, list) { | ||
297 | buff_pos += sprintf(buff + buff_pos, "%pM,", | ||
298 | entry->addr); | ||
299 | |||
300 | for (j = 0; j < packet->entries; j++) | ||
301 | buff_pos += batadv_vis_data_read_entry( | ||
302 | buff + buff_pos, | ||
303 | &entries[j], | ||
304 | entry->addr, | ||
305 | entry->primary); | ||
306 | |||
307 | /* add primary/secondary records */ | ||
308 | if (batadv_compare_eth(entry->addr, | ||
309 | packet->vis_orig)) | ||
310 | buff_pos += | ||
311 | batadv_vis_prim_sec(buff + buff_pos, | ||
312 | &vis_if_list); | ||
313 | |||
314 | buff_pos += sprintf(buff + buff_pos, "\n"); | ||
315 | } | ||
316 | |||
317 | hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, | ||
318 | list) { | ||
319 | hlist_del(&entry->list); | ||
320 | kfree(entry); | ||
321 | } | ||
322 | } | ||
323 | rcu_read_unlock(); | ||
324 | } | ||
325 | |||
326 | spin_unlock_bh(&bat_priv->vis_hash_lock); | 267 | spin_unlock_bh(&bat_priv->vis_hash_lock); |
327 | 268 | ||
328 | seq_printf(seq, "%s", buff); | ||
329 | kfree(buff); | ||
330 | |||
331 | out: | 269 | out: |
332 | if (primary_if) | 270 | if (primary_if) |
333 | batadv_hardif_free_ref(primary_if); | 271 | batadv_hardif_free_ref(primary_if); |