Blame view

net/batman-adv/distributed-arp-table.c 52.1 KB
7db7d9f36   Sven Eckelmann   batman-adv: Add S...
1
  // SPDX-License-Identifier: GPL-2.0
7a79d717e   Sven Eckelmann   batman-adv: Updat...
2
  /* Copyright (C) 2011-2019  B.A.T.M.A.N. contributors:
785ea1144   Antonio Quartulli   batman-adv: Distr...
3
4
   *
   * Antonio Quartulli
785ea1144   Antonio Quartulli   batman-adv: Distr...
5
   */
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
6
7
  #include "distributed-arp-table.h"
  #include "main.h"
b61ec31c8   Linus Lüssing   batman-adv: Snoop...
8
  #include <asm/unaligned.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
9
  #include <linux/atomic.h>
65d7d4605   Linus Lüssing   batman-adv: Make ...
10
  #include <linux/bitops.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
11
12
13
  #include <linux/byteorder/generic.h>
  #include <linux/errno.h>
  #include <linux/etherdevice.h>
b92b94ac7   Sven Eckelmann   batman-adv: inclu...
14
  #include <linux/gfp.h>
785ea1144   Antonio Quartulli   batman-adv: Distr...
15
  #include <linux/if_arp.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
16
  #include <linux/if_ether.h>
be1db4f66   Antonio Quartulli   batman-adv: make ...
17
  #include <linux/if_vlan.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
18
  #include <linux/in.h>
b61ec31c8   Linus Lüssing   batman-adv: Snoop...
19
  #include <linux/ip.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
20
21
  #include <linux/jiffies.h>
  #include <linux/kernel.h>
68a6722cc   Sven Eckelmann   batman-adv: Conve...
22
  #include <linux/kref.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
23
  #include <linux/list.h>
41aeefcc3   Linus Lüssing   batman-adv: add D...
24
  #include <linux/netlink.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
25
26
27
28
29
30
31
32
  #include <linux/rculist.h>
  #include <linux/rcupdate.h>
  #include <linux/seq_file.h>
  #include <linux/skbuff.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <linux/stddef.h>
  #include <linux/string.h>
b61ec31c8   Linus Lüssing   batman-adv: Snoop...
33
  #include <linux/udp.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
34
  #include <linux/workqueue.h>
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
35
  #include <net/arp.h>
41aeefcc3   Linus Lüssing   batman-adv: add D...
36
37
38
39
  #include <net/genetlink.h>
  #include <net/netlink.h>
  #include <net/sock.h>
  #include <uapi/linux/batman_adv.h>
785ea1144   Antonio Quartulli   batman-adv: Distr...
40

00311de5f   Andreas Pape   batman-adv: preve...
41
  #include "bridge_loop_avoidance.h"
785ea1144   Antonio Quartulli   batman-adv: Distr...
42
  #include "hard-interface.h"
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
43
  #include "hash.h"
ba412080f   Sven Eckelmann   batman-adv: Conso...
44
  #include "log.h"
41aeefcc3   Linus Lüssing   batman-adv: add D...
45
  #include "netlink.h"
785ea1144   Antonio Quartulli   batman-adv: Distr...
46
47
  #include "originator.h"
  #include "send.h"
41aeefcc3   Linus Lüssing   batman-adv: add D...
48
  #include "soft-interface.h"
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
49
  #include "translation-table.h"
1f8dce499   Markus Pargmann   batman-adv: split...
50
  #include "tvlv.h"
785ea1144   Antonio Quartulli   batman-adv: Distr...
51

b61ec31c8   Linus Lüssing   batman-adv: Snoop...
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  enum batadv_bootpop {
  	BATADV_BOOTREPLY	= 2,
  };
  
  enum batadv_boothtype {
  	BATADV_HTYPE_ETHERNET	= 1,
  };
  
  enum batadv_dhcpoptioncode {
  	BATADV_DHCP_OPT_PAD		= 0,
  	BATADV_DHCP_OPT_MSG_TYPE	= 53,
  	BATADV_DHCP_OPT_END		= 255,
  };
  
  enum batadv_dhcptype {
  	BATADV_DHCPACK		= 5,
  };
  
  /* { 99, 130, 83, 99 } */
  #define BATADV_DHCP_MAGIC 1669485411
  
  struct batadv_dhcp_packet {
  	__u8 op;
  	__u8 htype;
  	__u8 hlen;
  	__u8 hops;
  	__be32 xid;
  	__be16 secs;
  	__be16 flags;
  	__be32 ciaddr;
  	__be32 yiaddr;
  	__be32 siaddr;
  	__be32 giaddr;
  	__u8 chaddr[16];
  	__u8 sname[64];
  	__u8 file[128];
  	__be32 magic;
  	__u8 options[0];
  };
  
  #define BATADV_DHCP_YIADDR_LEN sizeof(((struct batadv_dhcp_packet *)0)->yiaddr)
  #define BATADV_DHCP_CHADDR_LEN sizeof(((struct batadv_dhcp_packet *)0)->chaddr)
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
94
95
96
  static void batadv_dat_purge(struct work_struct *work);
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
97
   * batadv_dat_start_timer() - initialise the DAT periodic worker
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
98
99
100
101
102
103
104
105
106
107
   * @bat_priv: the bat priv with all the soft interface information
   */
  static void batadv_dat_start_timer(struct batadv_priv *bat_priv)
  {
  	INIT_DELAYED_WORK(&bat_priv->dat.work, batadv_dat_purge);
  	queue_delayed_work(batadv_event_workqueue, &bat_priv->dat.work,
  			   msecs_to_jiffies(10000));
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
108
   * batadv_dat_entry_release() - release dat_entry from lists and queue for free
68a6722cc   Sven Eckelmann   batman-adv: Conve...
109
110
111
112
113
114
115
116
117
118
119
120
121
   *  after rcu grace period
   * @ref: kref pointer of the dat_entry
   */
  static void batadv_dat_entry_release(struct kref *ref)
  {
  	struct batadv_dat_entry *dat_entry;
  
  	dat_entry = container_of(ref, struct batadv_dat_entry, refcount);
  
  	kfree_rcu(dat_entry, rcu);
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
122
   * batadv_dat_entry_put() - decrement the dat_entry refcounter and possibly
68a6722cc   Sven Eckelmann   batman-adv: Conve...
123
124
   *  release it
   * @dat_entry: dat_entry to be free'd
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
125
   */
a6416f9ff   Sven Eckelmann   batman-adv: Renam...
126
  static void batadv_dat_entry_put(struct batadv_dat_entry *dat_entry)
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
127
  {
68a6722cc   Sven Eckelmann   batman-adv: Conve...
128
  	kref_put(&dat_entry->refcount, batadv_dat_entry_release);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
129
130
131
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
132
   * batadv_dat_to_purge() - check whether a dat_entry has to be purged or not
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
133
134
   * @dat_entry: the entry to check
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
135
   * Return: true if the entry has to be purged now, false otherwise.
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
136
137
138
139
140
141
142
143
   */
  static bool batadv_dat_to_purge(struct batadv_dat_entry *dat_entry)
  {
  	return batadv_has_timed_out(dat_entry->last_update,
  				    BATADV_DAT_ENTRY_TIMEOUT);
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
144
   * __batadv_dat_purge() - delete entries from the DAT local storage
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
145
146
147
148
149
150
   * @bat_priv: the bat priv with all the soft interface information
   * @to_purge: function in charge to decide whether an entry has to be purged or
   *	      not. This function takes the dat_entry as argument and has to
   *	      returns a boolean value: true is the entry has to be deleted,
   *	      false otherwise
   *
93178018e   Marek Lindner   batman-adv: fix t...
151
152
   * Loops over each entry in the DAT local storage and deletes it if and only if
   * the to_purge function passed as argument returns true.
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
153
154
155
156
157
158
   */
  static void __batadv_dat_purge(struct batadv_priv *bat_priv,
  			       bool (*to_purge)(struct batadv_dat_entry *))
  {
  	spinlock_t *list_lock; /* protects write access to the hash lists */
  	struct batadv_dat_entry *dat_entry;
b67bfe0d4   Sasha Levin   hlist: drop the n...
159
  	struct hlist_node *node_tmp;
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
160
  	struct hlist_head *head;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
161
  	u32 i;
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
162
163
164
165
166
167
168
169
170
  
  	if (!bat_priv->dat.hash)
  		return;
  
  	for (i = 0; i < bat_priv->dat.hash->size; i++) {
  		head = &bat_priv->dat.hash->table[i];
  		list_lock = &bat_priv->dat.hash->list_locks[i];
  
  		spin_lock_bh(list_lock);
b67bfe0d4   Sasha Levin   hlist: drop the n...
171
  		hlist_for_each_entry_safe(dat_entry, node_tmp, head,
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
172
  					  hash_entry) {
93178018e   Marek Lindner   batman-adv: fix t...
173
  			/* if a helper function has been passed as parameter,
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
174
175
176
177
  			 * ask it if the entry has to be purged or not
  			 */
  			if (to_purge && !to_purge(dat_entry))
  				continue;
b67bfe0d4   Sasha Levin   hlist: drop the n...
178
  			hlist_del_rcu(&dat_entry->hash_entry);
a6416f9ff   Sven Eckelmann   batman-adv: Renam...
179
  			batadv_dat_entry_put(dat_entry);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
180
181
182
183
184
185
  		}
  		spin_unlock_bh(list_lock);
  	}
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
186
187
   * batadv_dat_purge() - periodic task that deletes old entries from the local
   *  DAT hash table
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
188
189
190
191
192
193
194
   * @work: kernel work struct
   */
  static void batadv_dat_purge(struct work_struct *work)
  {
  	struct delayed_work *delayed_work;
  	struct batadv_priv_dat *priv_dat;
  	struct batadv_priv *bat_priv;
4ba4bc0f7   Geliang Tang   batman-adv: use t...
195
  	delayed_work = to_delayed_work(work);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
196
197
198
199
200
201
202
203
  	priv_dat = container_of(delayed_work, struct batadv_priv_dat, work);
  	bat_priv = container_of(priv_dat, struct batadv_priv, dat);
  
  	__batadv_dat_purge(bat_priv, batadv_dat_to_purge);
  	batadv_dat_start_timer(bat_priv);
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
204
   * batadv_compare_dat() - comparing function used in the local DAT hash table
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
205
206
207
   * @node: node in the local table
   * @data2: second object to compare the node to
   *
4b426b108   Sven Eckelmann   batman-adv: Use b...
208
   * Return: true if the two entries are the same, false otherwise.
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
209
   */
4b426b108   Sven Eckelmann   batman-adv: Use b...
210
  static bool batadv_compare_dat(const struct hlist_node *node, const void *data2)
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
211
212
213
  {
  	const void *data1 = container_of(node, struct batadv_dat_entry,
  					 hash_entry);
4b426b108   Sven Eckelmann   batman-adv: Use b...
214
  	return memcmp(data1, data2, sizeof(__be32)) == 0;
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
215
  }
785ea1144   Antonio Quartulli   batman-adv: Distr...
216
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
217
   * batadv_arp_hw_src() - extract the hw_src field from an ARP packet
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
218
219
220
   * @skb: ARP packet
   * @hdr_size: size of the possible header before the ARP packet
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
221
   * Return: the value of the hw_src field in the ARP packet.
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
222
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
223
  static u8 *batadv_arp_hw_src(struct sk_buff *skb, int hdr_size)
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
224
  {
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
225
  	u8 *addr;
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
226

6b5e971a2   Sven Eckelmann   batman-adv: Repla...
227
  	addr = (u8 *)(skb->data + hdr_size);
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
228
229
230
231
232
233
  	addr += ETH_HLEN + sizeof(struct arphdr);
  
  	return addr;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
234
   * batadv_arp_ip_src() - extract the ip_src field from an ARP packet
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
235
236
237
   * @skb: ARP packet
   * @hdr_size: size of the possible header before the ARP packet
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
238
   * Return: the value of the ip_src field in the ARP packet.
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
239
240
241
242
243
244
245
   */
  static __be32 batadv_arp_ip_src(struct sk_buff *skb, int hdr_size)
  {
  	return *(__be32 *)(batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN);
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
246
   * batadv_arp_hw_dst() - extract the hw_dst field from an ARP packet
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
247
248
249
   * @skb: ARP packet
   * @hdr_size: size of the possible header before the ARP packet
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
250
   * Return: the value of the hw_dst field in the ARP packet.
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
251
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
252
  static u8 *batadv_arp_hw_dst(struct sk_buff *skb, int hdr_size)
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
253
254
255
256
257
  {
  	return batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN + 4;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
258
   * batadv_arp_ip_dst() - extract the ip_dst field from an ARP packet
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
259
260
261
   * @skb: ARP packet
   * @hdr_size: size of the possible header before the ARP packet
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
262
   * Return: the value of the ip_dst field in the ARP packet.
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
263
264
265
266
267
268
269
   */
  static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size)
  {
  	return *(__be32 *)(batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN * 2 + 4);
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
270
   * batadv_hash_dat() - compute the hash value for an IP address
785ea1144   Antonio Quartulli   batman-adv: Distr...
271
272
273
   * @data: data to hash
   * @size: size of the hash table
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
274
   * Return: the selected index in the hash table for the given data.
785ea1144   Antonio Quartulli   batman-adv: Distr...
275
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
276
  static u32 batadv_hash_dat(const void *data, u32 size)
785ea1144   Antonio Quartulli   batman-adv: Distr...
277
  {
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
278
  	u32 hash = 0;
be1db4f66   Antonio Quartulli   batman-adv: make ...
279
  	const struct batadv_dat_entry *dat = data;
36fd61cb8   Sven Eckelmann   batman-adv: Use c...
280
  	const unsigned char *key;
7c69f6a22   Sven Eckelmann   batman-adv: Fix D...
281
  	__be16 vid;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
282
  	u32 i;
36fd61cb8   Sven Eckelmann   batman-adv: Use c...
283
284
285
286
287
288
289
  
  	key = (const unsigned char *)&dat->ip;
  	for (i = 0; i < sizeof(dat->ip); i++) {
  		hash += key[i];
  		hash += (hash << 10);
  		hash ^= (hash >> 6);
  	}
785ea1144   Antonio Quartulli   batman-adv: Distr...
290

7c69f6a22   Sven Eckelmann   batman-adv: Fix D...
291
292
  	vid = htons(dat->vid);
  	key = (__force const unsigned char *)&vid;
36fd61cb8   Sven Eckelmann   batman-adv: Use c...
293
294
295
296
297
  	for (i = 0; i < sizeof(dat->vid); i++) {
  		hash += key[i];
  		hash += (hash << 10);
  		hash ^= (hash >> 6);
  	}
785ea1144   Antonio Quartulli   batman-adv: Distr...
298
299
300
301
302
303
304
305
306
  
  	hash += (hash << 3);
  	hash ^= (hash >> 11);
  	hash += (hash << 15);
  
  	return hash % size;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
307
   * batadv_dat_entry_hash_find() - look for a given dat_entry in the local hash
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
308
309
310
   * table
   * @bat_priv: the bat priv with all the soft interface information
   * @ip: search key
be1db4f66   Antonio Quartulli   batman-adv: make ...
311
   * @vid: VLAN identifier
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
312
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
313
   * Return: the dat_entry if found, NULL otherwise.
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
314
315
   */
  static struct batadv_dat_entry *
be1db4f66   Antonio Quartulli   batman-adv: make ...
316
317
  batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,
  			   unsigned short vid)
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
318
319
  {
  	struct hlist_head *head;
be1db4f66   Antonio Quartulli   batman-adv: make ...
320
  	struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL;
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
321
  	struct batadv_hashtable *hash = bat_priv->dat.hash;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
322
  	u32 index;
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
323
324
325
  
  	if (!hash)
  		return NULL;
be1db4f66   Antonio Quartulli   batman-adv: make ...
326
327
328
329
  	to_find.ip = ip;
  	to_find.vid = vid;
  
  	index = batadv_hash_dat(&to_find, hash->size);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
330
331
332
  	head = &hash->table[index];
  
  	rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
333
  	hlist_for_each_entry_rcu(dat_entry, head, hash_entry) {
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
334
335
  		if (dat_entry->ip != ip)
  			continue;
68a6722cc   Sven Eckelmann   batman-adv: Conve...
336
  		if (!kref_get_unless_zero(&dat_entry->refcount))
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
337
338
339
340
341
342
343
344
345
346
347
  			continue;
  
  		dat_entry_tmp = dat_entry;
  		break;
  	}
  	rcu_read_unlock();
  
  	return dat_entry_tmp;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
348
   * batadv_dat_entry_add() - add a new dat entry or update it if already exists
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
349
350
351
   * @bat_priv: the bat priv with all the soft interface information
   * @ip: ipv4 to add/edit
   * @mac_addr: mac address to assign to the given ipv4
be1db4f66   Antonio Quartulli   batman-adv: make ...
352
   * @vid: VLAN identifier
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
353
354
   */
  static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
355
  				 u8 *mac_addr, unsigned short vid)
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
356
357
358
  {
  	struct batadv_dat_entry *dat_entry;
  	int hash_added;
be1db4f66   Antonio Quartulli   batman-adv: make ...
359
  	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
360
361
362
  	/* if this entry is already known, just update it */
  	if (dat_entry) {
  		if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
8fdd01530   Antonio Quartulli   batman-adv: prefe...
363
  			ether_addr_copy(dat_entry->mac_addr, mac_addr);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
364
365
  		dat_entry->last_update = jiffies;
  		batadv_dbg(BATADV_DBG_DAT, bat_priv,
be1db4f66   Antonio Quartulli   batman-adv: make ...
366
367
368
  			   "Entry updated: %pI4 %pM (vid: %d)
  ",
  			   &dat_entry->ip, dat_entry->mac_addr,
f7a2bd654   Sven Eckelmann   batman-adv: Conve...
369
  			   batadv_print_vid(vid));
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
370
371
372
373
374
375
376
377
  		goto out;
  	}
  
  	dat_entry = kmalloc(sizeof(*dat_entry), GFP_ATOMIC);
  	if (!dat_entry)
  		goto out;
  
  	dat_entry->ip = ip;
be1db4f66   Antonio Quartulli   batman-adv: make ...
378
  	dat_entry->vid = vid;
8fdd01530   Antonio Quartulli   batman-adv: prefe...
379
  	ether_addr_copy(dat_entry->mac_addr, mac_addr);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
380
  	dat_entry->last_update = jiffies;
68a6722cc   Sven Eckelmann   batman-adv: Conve...
381
  	kref_init(&dat_entry->refcount);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
382

6a51e09d8   Sven Eckelmann   batman-adv: Place...
383
  	kref_get(&dat_entry->refcount);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
384
  	hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat,
be1db4f66   Antonio Quartulli   batman-adv: make ...
385
  				     batadv_hash_dat, dat_entry,
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
386
387
388
389
  				     &dat_entry->hash_entry);
  
  	if (unlikely(hash_added != 0)) {
  		/* remove the reference for the hash */
a6416f9ff   Sven Eckelmann   batman-adv: Renam...
390
  		batadv_dat_entry_put(dat_entry);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
391
392
  		goto out;
  	}
be1db4f66   Antonio Quartulli   batman-adv: make ...
393
394
  	batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)
  ",
f7a2bd654   Sven Eckelmann   batman-adv: Conve...
395
  		   &dat_entry->ip, dat_entry->mac_addr, batadv_print_vid(vid));
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
396
397
398
  
  out:
  	if (dat_entry)
a6416f9ff   Sven Eckelmann   batman-adv: Renam...
399
  		batadv_dat_entry_put(dat_entry);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
400
  }
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
401
402
403
  #ifdef CONFIG_BATMAN_ADV_DEBUG
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
404
405
   * batadv_dbg_arp() - print a debug message containing all the ARP packet
   *  details
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
406
407
   * @bat_priv: the bat priv with all the soft interface information
   * @skb: ARP packet
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
408
409
410
411
   * @hdr_size: size of the possible header before the ARP packet
   * @msg: message to print together with the debugging information
   */
  static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,
843314c97   Antonio Quartulli   batman-adv: remov...
412
  			   int hdr_size, char *msg)
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
413
414
415
  {
  	struct batadv_unicast_4addr_packet *unicast_4addr_packet;
  	struct batadv_bcast_packet *bcast_pkt;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
416
  	u8 *orig_addr;
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
417
418
419
420
421
422
423
424
425
426
427
428
429
  	__be32 ip_src, ip_dst;
  
  	if (msg)
  		batadv_dbg(BATADV_DBG_DAT, bat_priv, "%s
  ", msg);
  
  	ip_src = batadv_arp_ip_src(skb, hdr_size);
  	ip_dst = batadv_arp_ip_dst(skb, hdr_size);
  	batadv_dbg(BATADV_DBG_DAT, bat_priv,
  		   "ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]
  ",
  		   batadv_arp_hw_src(skb, hdr_size), &ip_src,
  		   batadv_arp_hw_dst(skb, hdr_size), &ip_dst);
6f27d2c2a   Matthias Schiffer   batman-adv: fix h...
430
  	if (hdr_size < sizeof(struct batadv_unicast_packet))
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
431
  		return;
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
432
  	unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data;
a40d9b075   Simon Wunderlich   batman-adv: fix h...
433
  	switch (unicast_4addr_packet->u.packet_type) {
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  	case BATADV_UNICAST:
  		batadv_dbg(BATADV_DBG_DAT, bat_priv,
  			   "* encapsulated within a UNICAST packet
  ");
  		break;
  	case BATADV_UNICAST_4ADDR:
  		batadv_dbg(BATADV_DBG_DAT, bat_priv,
  			   "* encapsulated within a UNICAST_4ADDR packet (src: %pM)
  ",
  			   unicast_4addr_packet->src);
  		switch (unicast_4addr_packet->subtype) {
  		case BATADV_P_DAT_DHT_PUT:
  			batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: DAT_DHT_PUT
  ");
  			break;
  		case BATADV_P_DAT_DHT_GET:
  			batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: DAT_DHT_GET
  ");
  			break;
  		case BATADV_P_DAT_CACHE_REPLY:
  			batadv_dbg(BATADV_DBG_DAT, bat_priv,
  				   "* type: DAT_CACHE_REPLY
  ");
  			break;
  		case BATADV_P_DATA:
  			batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: DATA
  ");
  			break;
  		default:
  			batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: Unknown (%u)!
  ",
a40d9b075   Simon Wunderlich   batman-adv: fix h...
465
  				   unicast_4addr_packet->u.packet_type);
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  		}
  		break;
  	case BATADV_BCAST:
  		bcast_pkt = (struct batadv_bcast_packet *)unicast_4addr_packet;
  		orig_addr = bcast_pkt->orig;
  		batadv_dbg(BATADV_DBG_DAT, bat_priv,
  			   "* encapsulated within a BCAST packet (src: %pM)
  ",
  			   orig_addr);
  		break;
  	default:
  		batadv_dbg(BATADV_DBG_DAT, bat_priv,
  			   "* encapsulated within an unknown packet type (0x%x)
  ",
a40d9b075   Simon Wunderlich   batman-adv: fix h...
480
  			   unicast_4addr_packet->u.packet_type);
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
481
482
483
484
485
486
  	}
  }
  
  #else
  
  static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,
843314c97   Antonio Quartulli   batman-adv: remov...
487
  			   int hdr_size, char *msg)
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
488
489
490
491
  {
  }
  
  #endif /* CONFIG_BATMAN_ADV_DEBUG */
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
492
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
493
   * batadv_is_orig_node_eligible() - check whether a node can be a DHT candidate
785ea1144   Antonio Quartulli   batman-adv: Distr...
494
495
496
497
498
499
500
501
   * @res: the array with the already selected candidates
   * @select: number of already selected candidates
   * @tmp_max: address of the currently evaluated node
   * @max: current round max address
   * @last_max: address of the last selected candidate
   * @candidate: orig_node under evaluation
   * @max_orig_node: last selected candidate
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
502
   * Return: true if the node has been elected as next candidate or false
93178018e   Marek Lindner   batman-adv: fix t...
503
   * otherwise.
785ea1144   Antonio Quartulli   batman-adv: Distr...
504
505
506
507
508
509
510
511
512
513
   */
  static bool batadv_is_orig_node_eligible(struct batadv_dat_candidate *res,
  					 int select, batadv_dat_addr_t tmp_max,
  					 batadv_dat_addr_t max,
  					 batadv_dat_addr_t last_max,
  					 struct batadv_orig_node *candidate,
  					 struct batadv_orig_node *max_orig_node)
  {
  	bool ret = false;
  	int j;
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
514
  	/* check if orig node candidate is running DAT */
65d7d4605   Linus Lüssing   batman-adv: Make ...
515
  	if (!test_bit(BATADV_ORIG_CAPA_HAS_DAT, &candidate->capabilities))
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
516
  		goto out;
785ea1144   Antonio Quartulli   batman-adv: Distr...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
  	/* Check if this node has already been selected... */
  	for (j = 0; j < select; j++)
  		if (res[j].orig_node == candidate)
  			break;
  	/* ..and possibly skip it */
  	if (j < select)
  		goto out;
  	/* sanity check: has it already been selected? This should not happen */
  	if (tmp_max > last_max)
  		goto out;
  	/* check if during this iteration an originator with a closer dht
  	 * address has already been found
  	 */
  	if (tmp_max < max)
  		goto out;
  	/* this is an hash collision with the temporary selected node. Choose
  	 * the one with the lowest address
  	 */
825ffe1f7   Sven Eckelmann   batman-adv: Remov...
535
  	if (tmp_max == max && max_orig_node &&
d7625f9f7   Sven Eckelmann   batman-adv: Avoid...
536
  	    batadv_compare_eth(candidate->orig, max_orig_node->orig))
785ea1144   Antonio Quartulli   batman-adv: Distr...
537
538
539
540
541
542
543
544
  		goto out;
  
  	ret = true;
  out:
  	return ret;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
545
   * batadv_choose_next_candidate() - select the next DHT candidate
785ea1144   Antonio Quartulli   batman-adv: Distr...
546
547
548
549
550
551
552
553
554
555
556
   * @bat_priv: the bat priv with all the soft interface information
   * @cands: candidates array
   * @select: number of candidates already present in the array
   * @ip_key: key to look up in the DHT
   * @last_max: pointer where the address of the selected candidate will be saved
   */
  static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
  					 struct batadv_dat_candidate *cands,
  					 int select, batadv_dat_addr_t ip_key,
  					 batadv_dat_addr_t *last_max)
  {
4f248cff9   Sven Eckelmann   batman-adv: Remov...
557
558
  	batadv_dat_addr_t max = 0;
  	batadv_dat_addr_t tmp_max = 0;
785ea1144   Antonio Quartulli   batman-adv: Distr...
559
560
  	struct batadv_orig_node *orig_node, *max_orig_node = NULL;
  	struct batadv_hashtable *hash = bat_priv->orig_hash;
785ea1144   Antonio Quartulli   batman-adv: Distr...
561
562
563
564
565
566
567
  	struct hlist_head *head;
  	int i;
  
  	/* if no node is eligible as candidate, leave the candidate type as
  	 * NOT_FOUND
  	 */
  	cands[select].type = BATADV_DAT_CANDIDATE_NOT_FOUND;
93178018e   Marek Lindner   batman-adv: fix t...
568
  	/* iterate over the originator list and find the node with the closest
785ea1144   Antonio Quartulli   batman-adv: Distr...
569
570
571
572
573
574
  	 * dat_address which has not been selected yet
  	 */
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  
  		rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
575
  		hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
93178018e   Marek Lindner   batman-adv: fix t...
576
  			/* the dht space is a ring using unsigned addresses */
785ea1144   Antonio Quartulli   batman-adv: Distr...
577
578
579
580
581
582
583
584
  			tmp_max = BATADV_DAT_ADDR_MAX - orig_node->dat_addr +
  				  ip_key;
  
  			if (!batadv_is_orig_node_eligible(cands, select,
  							  tmp_max, max,
  							  *last_max, orig_node,
  							  max_orig_node))
  				continue;
7c1243911   Sven Eckelmann   batman-adv: Conve...
585
  			if (!kref_get_unless_zero(&orig_node->refcount))
785ea1144   Antonio Quartulli   batman-adv: Distr...
586
587
588
589
  				continue;
  
  			max = tmp_max;
  			if (max_orig_node)
5d9673109   Sven Eckelmann   batman-adv: Renam...
590
  				batadv_orig_node_put(max_orig_node);
785ea1144   Antonio Quartulli   batman-adv: Distr...
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
  			max_orig_node = orig_node;
  		}
  		rcu_read_unlock();
  	}
  	if (max_orig_node) {
  		cands[select].type = BATADV_DAT_CANDIDATE_ORIG;
  		cands[select].orig_node = max_orig_node;
  		batadv_dbg(BATADV_DBG_DAT, bat_priv,
  			   "dat_select_candidates() %d: selected %pM addr=%u dist=%u
  ",
  			   select, max_orig_node->orig, max_orig_node->dat_addr,
  			   max);
  	}
  	*last_max = max;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
608
609
   * batadv_dat_select_candidates() - select the nodes which the DHT message has
   *  to be sent to
785ea1144   Antonio Quartulli   batman-adv: Distr...
610
611
   * @bat_priv: the bat priv with all the soft interface information
   * @ip_dst: ipv4 to look up in the DHT
2871734e8   Antonio Quartulli   batman-adv: fix D...
612
   * @vid: VLAN identifier
785ea1144   Antonio Quartulli   batman-adv: Distr...
613
614
615
616
617
   *
   * An originator O is selected if and only if its DHT_ID value is one of three
   * closest values (from the LEFT, with wrap around if needed) then the hash
   * value of the key. ip_dst is the key.
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
618
   * Return: the candidate array of size BATADV_DAT_CANDIDATE_NUM.
785ea1144   Antonio Quartulli   batman-adv: Distr...
619
620
   */
  static struct batadv_dat_candidate *
2871734e8   Antonio Quartulli   batman-adv: fix D...
621
622
  batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst,
  			     unsigned short vid)
785ea1144   Antonio Quartulli   batman-adv: Distr...
623
624
625
626
  {
  	int select;
  	batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, ip_key;
  	struct batadv_dat_candidate *res;
b7fe3d4f4   Sven Eckelmann   batman-adv: Fix i...
627
  	struct batadv_dat_entry dat;
785ea1144   Antonio Quartulli   batman-adv: Distr...
628
629
630
  
  	if (!bat_priv->orig_hash)
  		return NULL;
0185dda64   Antonio Quartulli   batman-adv: prefe...
631
632
  	res = kmalloc_array(BATADV_DAT_CANDIDATES_NUM, sizeof(*res),
  			    GFP_ATOMIC);
785ea1144   Antonio Quartulli   batman-adv: Distr...
633
634
  	if (!res)
  		return NULL;
b7fe3d4f4   Sven Eckelmann   batman-adv: Fix i...
635
  	dat.ip = ip_dst;
2871734e8   Antonio Quartulli   batman-adv: fix D...
636
  	dat.vid = vid;
b7fe3d4f4   Sven Eckelmann   batman-adv: Fix i...
637
  	ip_key = (batadv_dat_addr_t)batadv_hash_dat(&dat,
785ea1144   Antonio Quartulli   batman-adv: Distr...
638
639
640
  						    BATADV_DAT_ADDR_MAX);
  
  	batadv_dbg(BATADV_DBG_DAT, bat_priv,
22f0502ed   Sven Eckelmann   batman-adv: Print...
641
642
  		   "%s(): IP=%pI4 hash(IP)=%u
  ", __func__, &ip_dst,
785ea1144   Antonio Quartulli   batman-adv: Distr...
643
644
645
646
647
648
649
650
651
652
  		   ip_key);
  
  	for (select = 0; select < BATADV_DAT_CANDIDATES_NUM; select++)
  		batadv_choose_next_candidate(bat_priv, res, select, ip_key,
  					     &last_max);
  
  	return res;
  }
  
  /**
c2d8b9a6c   Sven Eckelmann   batman-adv: Adjus...
653
   * batadv_dat_forward_data() - copy and send payload to the selected candidates
785ea1144   Antonio Quartulli   batman-adv: Distr...
654
655
656
   * @bat_priv: the bat priv with all the soft interface information
   * @skb: payload to send
   * @ip: the DHT key
2871734e8   Antonio Quartulli   batman-adv: fix D...
657
   * @vid: VLAN identifier
785ea1144   Antonio Quartulli   batman-adv: Distr...
658
659
   * @packet_subtype: unicast4addr packet subtype to use
   *
93178018e   Marek Lindner   batman-adv: fix t...
660
661
   * This function copies the skb with pskb_copy() and is sent as unicast packet
   * to each of the selected candidates.
785ea1144   Antonio Quartulli   batman-adv: Distr...
662
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
663
   * Return: true if the packet is sent to at least one candidate, false
93178018e   Marek Lindner   batman-adv: fix t...
664
   * otherwise.
785ea1144   Antonio Quartulli   batman-adv: Distr...
665
   */
c2d8b9a6c   Sven Eckelmann   batman-adv: Adjus...
666
667
668
  static bool batadv_dat_forward_data(struct batadv_priv *bat_priv,
  				    struct sk_buff *skb, __be32 ip,
  				    unsigned short vid, int packet_subtype)
785ea1144   Antonio Quartulli   batman-adv: Distr...
669
670
671
672
673
674
675
  {
  	int i;
  	bool ret = false;
  	int send_status;
  	struct batadv_neigh_node *neigh_node = NULL;
  	struct sk_buff *tmp_skb;
  	struct batadv_dat_candidate *cand;
2871734e8   Antonio Quartulli   batman-adv: fix D...
676
  	cand = batadv_dat_select_candidates(bat_priv, ip, vid);
785ea1144   Antonio Quartulli   batman-adv: Distr...
677
678
679
680
681
682
683
684
685
  	if (!cand)
  		goto out;
  
  	batadv_dbg(BATADV_DBG_DAT, bat_priv, "DHT_SEND for %pI4
  ", &ip);
  
  	for (i = 0; i < BATADV_DAT_CANDIDATES_NUM; i++) {
  		if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND)
  			continue;
7351a4822   Simon Wunderlich   batman-adv: split...
686
687
  		neigh_node = batadv_orig_router_get(cand[i].orig_node,
  						    BATADV_IF_DEFAULT);
785ea1144   Antonio Quartulli   batman-adv: Distr...
688
689
  		if (!neigh_node)
  			goto free_orig;
bad93e9d4   Octavian Purdila   net: add __pskb_c...
690
  		tmp_skb = pskb_copy_for_clone(skb, GFP_ATOMIC);
f097e25db   Martin Hundebøll   batman-adv: Remov...
691
692
693
  		if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, tmp_skb,
  							   cand[i].orig_node,
  							   packet_subtype)) {
785ea1144   Antonio Quartulli   batman-adv: Distr...
694
695
696
  			kfree_skb(tmp_skb);
  			goto free_neigh;
  		}
95d392784   Antonio Quartulli   batman-adv: keep ...
697
  		send_status = batadv_send_unicast_skb(tmp_skb, neigh_node);
4046b24af   Martin Hundebøll   batman-adv: Add g...
698
699
700
701
702
703
704
705
706
707
708
709
  		if (send_status == NET_XMIT_SUCCESS) {
  			/* count the sent packet */
  			switch (packet_subtype) {
  			case BATADV_P_DAT_DHT_GET:
  				batadv_inc_counter(bat_priv,
  						   BATADV_CNT_DAT_GET_TX);
  				break;
  			case BATADV_P_DAT_DHT_PUT:
  				batadv_inc_counter(bat_priv,
  						   BATADV_CNT_DAT_PUT_TX);
  				break;
  			}
785ea1144   Antonio Quartulli   batman-adv: Distr...
710
711
  			/* packet sent to a candidate: return true */
  			ret = true;
4046b24af   Martin Hundebøll   batman-adv: Add g...
712
  		}
785ea1144   Antonio Quartulli   batman-adv: Distr...
713
  free_neigh:
25bb25099   Sven Eckelmann   batman-adv: Renam...
714
  		batadv_neigh_node_put(neigh_node);
785ea1144   Antonio Quartulli   batman-adv: Distr...
715
  free_orig:
5d9673109   Sven Eckelmann   batman-adv: Renam...
716
  		batadv_orig_node_put(cand[i].orig_node);
785ea1144   Antonio Quartulli   batman-adv: Distr...
717
718
719
720
721
722
  	}
  
  out:
  	kfree(cand);
  	return ret;
  }
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
723
724
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
725
   * batadv_dat_tvlv_container_update() - update the dat tvlv container after dat
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
   *  setting change
   * @bat_priv: the bat priv with all the soft interface information
   */
  static void batadv_dat_tvlv_container_update(struct batadv_priv *bat_priv)
  {
  	char dat_mode;
  
  	dat_mode = atomic_read(&bat_priv->distributed_arp_table);
  
  	switch (dat_mode) {
  	case 0:
  		batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_DAT, 1);
  		break;
  	case 1:
  		batadv_tvlv_container_register(bat_priv, BATADV_TVLV_DAT, 1,
  					       NULL, 0);
  		break;
  	}
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
747
   * batadv_dat_status_update() - update the dat tvlv container after dat
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
748
749
750
751
752
753
   *  setting change
   * @net_dev: the soft interface net device
   */
  void batadv_dat_status_update(struct net_device *net_dev)
  {
  	struct batadv_priv *bat_priv = netdev_priv(net_dev);
f138694b1   Antonio Quartulli   batman-adv: add b...
754

17cf0ea45   Marek Lindner   batman-adv: tvlv ...
755
756
757
758
  	batadv_dat_tvlv_container_update(bat_priv);
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
759
   * batadv_dat_tvlv_ogm_handler_v1() - process incoming dat tvlv container
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
760
761
762
763
764
765
766
767
   * @bat_priv: the bat priv with all the soft interface information
   * @orig: the orig_node of the ogm
   * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
   * @tvlv_value: tvlv buffer containing the gateway data
   * @tvlv_value_len: tvlv buffer length
   */
  static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
  					   struct batadv_orig_node *orig,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
768
769
  					   u8 flags,
  					   void *tvlv_value, u16 tvlv_value_len)
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
770
771
  {
  	if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND)
65d7d4605   Linus Lüssing   batman-adv: Make ...
772
  		clear_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities);
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
773
  	else
65d7d4605   Linus Lüssing   batman-adv: Make ...
774
  		set_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities);
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
775
776
777
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
778
   * batadv_dat_hash_free() - free the local DAT hash table
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
779
780
781
782
   * @bat_priv: the bat priv with all the soft interface information
   */
  static void batadv_dat_hash_free(struct batadv_priv *bat_priv)
  {
33af49ad8   Antonio Quartulli   batman-adv: Distr...
783
784
  	if (!bat_priv->dat.hash)
  		return;
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
785
786
787
788
789
790
791
792
  	__batadv_dat_purge(bat_priv, NULL);
  
  	batadv_hash_destroy(bat_priv->dat.hash);
  
  	bat_priv->dat.hash = NULL;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
793
   * batadv_dat_init() - initialise the DAT internals
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
794
   * @bat_priv: the bat priv with all the soft interface information
fe13c2aad   Antonio Quartulli   batman-adv: fix k...
795
796
   *
   * Return: 0 in case of success, a negative error code otherwise
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
797
798
799
800
801
802
803
804
805
806
807
808
   */
  int batadv_dat_init(struct batadv_priv *bat_priv)
  {
  	if (bat_priv->dat.hash)
  		return 0;
  
  	bat_priv->dat.hash = batadv_hash_new(1024);
  
  	if (!bat_priv->dat.hash)
  		return -ENOMEM;
  
  	batadv_dat_start_timer(bat_priv);
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
809
810
811
812
  	batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1,
  				     NULL, BATADV_TVLV_DAT, 1,
  				     BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
  	batadv_dat_tvlv_container_update(bat_priv);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
813
814
815
816
  	return 0;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
817
   * batadv_dat_free() - free the DAT internals
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
818
819
820
821
   * @bat_priv: the bat priv with all the soft interface information
   */
  void batadv_dat_free(struct batadv_priv *bat_priv)
  {
17cf0ea45   Marek Lindner   batman-adv: tvlv ...
822
823
  	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_DAT, 1);
  	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_DAT, 1);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
824
825
826
827
  	cancel_delayed_work_sync(&bat_priv->dat.work);
  
  	batadv_dat_hash_free(bat_priv);
  }
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
828
  #ifdef CONFIG_BATMAN_ADV_DEBUGFS
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
829
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
830
   * batadv_dat_cache_seq_print_text() - print the local DAT hash table
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
831
832
   * @seq: seq file to print on
   * @offset: not used
fe13c2aad   Antonio Quartulli   batman-adv: fix k...
833
834
   *
   * Return: always 0
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
835
836
837
838
839
840
841
842
   */
  int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset)
  {
  	struct net_device *net_dev = (struct net_device *)seq->private;
  	struct batadv_priv *bat_priv = netdev_priv(net_dev);
  	struct batadv_hashtable *hash = bat_priv->dat.hash;
  	struct batadv_dat_entry *dat_entry;
  	struct batadv_hard_iface *primary_if;
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
843
844
845
  	struct hlist_head *head;
  	unsigned long last_seen_jiffies;
  	int last_seen_msecs, last_seen_secs, last_seen_mins;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
846
  	u32 i;
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
847
848
849
850
851
852
853
  
  	primary_if = batadv_seq_print_text_primary_if_get(seq);
  	if (!primary_if)
  		goto out;
  
  	seq_printf(seq, "Distributed ARP Table (%s):
  ", net_dev->name);
925a6f379   Antonio Quartulli   batman-adv: use s...
854
855
856
  	seq_puts(seq,
  		 "          IPv4             MAC        VID   last-seen
  ");
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
857
858
859
860
861
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
  
  		rcu_read_lock();
b67bfe0d4   Sasha Levin   hlist: drop the n...
862
  		hlist_for_each_entry_rcu(dat_entry, head, hash_entry) {
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
863
864
865
866
867
  			last_seen_jiffies = jiffies - dat_entry->last_update;
  			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
  			last_seen_mins = last_seen_msecs / 60000;
  			last_seen_msecs = last_seen_msecs % 60000;
  			last_seen_secs = last_seen_msecs / 1000;
cd0edf3ad   Joe Perches   batman-adv: Remov...
868
869
  			seq_printf(seq, " * %15pI4 %pM %4i %6i:%02i
  ",
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
870
  				   &dat_entry->ip, dat_entry->mac_addr,
f7a2bd654   Sven Eckelmann   batman-adv: Conve...
871
  				   batadv_print_vid(dat_entry->vid),
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
872
873
874
875
876
877
878
  				   last_seen_mins, last_seen_secs);
  		}
  		rcu_read_unlock();
  	}
  
  out:
  	if (primary_if)
82047ad7f   Sven Eckelmann   batman-adv: Renam...
879
  		batadv_hardif_put(primary_if);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
880
881
  	return 0;
  }
dc1cbd145   Sven Eckelmann   batman-adv: Allow...
882
  #endif
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
883
884
  
  /**
41aeefcc3   Linus Lüssing   batman-adv: add D...
885
886
887
888
   * batadv_dat_cache_dump_entry() - dump one entry of the DAT cache table to a
   *  netlink socket
   * @msg: buffer for the message
   * @portid: netlink port
6f81652a4   Sven Eckelmann   batman-adv: Add i...
889
   * @cb: Control block containing additional options
41aeefcc3   Linus Lüssing   batman-adv: add D...
890
891
892
893
894
   * @dat_entry: entry to dump
   *
   * Return: 0 or error code.
   */
  static int
6f81652a4   Sven Eckelmann   batman-adv: Add i...
895
896
  batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,
  			    struct netlink_callback *cb,
41aeefcc3   Linus Lüssing   batman-adv: add D...
897
898
899
900
  			    struct batadv_dat_entry *dat_entry)
  {
  	int msecs;
  	void *hdr;
6f81652a4   Sven Eckelmann   batman-adv: Add i...
901
902
903
  	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
  			  &batadv_netlink_family, NLM_F_MULTI,
  			  BATADV_CMD_GET_DAT_CACHE);
41aeefcc3   Linus Lüssing   batman-adv: add D...
904
905
  	if (!hdr)
  		return -ENOBUFS;
6f81652a4   Sven Eckelmann   batman-adv: Add i...
906
  	genl_dump_check_consistent(cb, hdr);
41aeefcc3   Linus Lüssing   batman-adv: add D...
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
  	msecs = jiffies_to_msecs(jiffies - dat_entry->last_update);
  
  	if (nla_put_in_addr(msg, BATADV_ATTR_DAT_CACHE_IP4ADDRESS,
  			    dat_entry->ip) ||
  	    nla_put(msg, BATADV_ATTR_DAT_CACHE_HWADDRESS, ETH_ALEN,
  		    dat_entry->mac_addr) ||
  	    nla_put_u16(msg, BATADV_ATTR_DAT_CACHE_VID, dat_entry->vid) ||
  	    nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) {
  		genlmsg_cancel(msg, hdr);
  		return -EMSGSIZE;
  	}
  
  	genlmsg_end(msg, hdr);
  	return 0;
  }
  
  /**
   * batadv_dat_cache_dump_bucket() - dump one bucket of the DAT cache table to
   *  a netlink socket
   * @msg: buffer for the message
   * @portid: netlink port
6f81652a4   Sven Eckelmann   batman-adv: Add i...
928
929
930
   * @cb: Control block containing additional options
   * @hash: hash to dump
   * @bucket: bucket index to dump
41aeefcc3   Linus Lüssing   batman-adv: add D...
931
932
933
934
935
   * @idx_skip: How many entries to skip
   *
   * Return: 0 or error code.
   */
  static int
6f81652a4   Sven Eckelmann   batman-adv: Add i...
936
937
938
939
  batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid,
  			     struct netlink_callback *cb,
  			     struct batadv_hashtable *hash, unsigned int bucket,
  			     int *idx_skip)
41aeefcc3   Linus Lüssing   batman-adv: add D...
940
941
942
  {
  	struct batadv_dat_entry *dat_entry;
  	int idx = 0;
6f81652a4   Sven Eckelmann   batman-adv: Add i...
943
944
945
946
  	spin_lock_bh(&hash->list_locks[bucket]);
  	cb->seq = atomic_read(&hash->generation) << 1 | 1;
  
  	hlist_for_each_entry(dat_entry, &hash->table[bucket], hash_entry) {
41aeefcc3   Linus Lüssing   batman-adv: add D...
947
948
  		if (idx < *idx_skip)
  			goto skip;
6f81652a4   Sven Eckelmann   batman-adv: Add i...
949
950
  		if (batadv_dat_cache_dump_entry(msg, portid, cb, dat_entry)) {
  			spin_unlock_bh(&hash->list_locks[bucket]);
41aeefcc3   Linus Lüssing   batman-adv: add D...
951
952
953
954
955
956
957
958
  			*idx_skip = idx;
  
  			return -EMSGSIZE;
  		}
  
  skip:
  		idx++;
  	}
6f81652a4   Sven Eckelmann   batman-adv: Add i...
959
  	spin_unlock_bh(&hash->list_locks[bucket]);
41aeefcc3   Linus Lüssing   batman-adv: add D...
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
  
  	return 0;
  }
  
  /**
   * batadv_dat_cache_dump() - dump DAT cache table to a netlink socket
   * @msg: buffer for the message
   * @cb: callback structure containing arguments
   *
   * Return: message length.
   */
  int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)
  {
  	struct batadv_hard_iface *primary_if = NULL;
  	int portid = NETLINK_CB(cb->skb).portid;
  	struct net *net = sock_net(cb->skb->sk);
  	struct net_device *soft_iface;
  	struct batadv_hashtable *hash;
  	struct batadv_priv *bat_priv;
  	int bucket = cb->args[0];
41aeefcc3   Linus Lüssing   batman-adv: add D...
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  	int idx = cb->args[1];
  	int ifindex;
  	int ret = 0;
  
  	ifindex = batadv_netlink_get_ifindex(cb->nlh,
  					     BATADV_ATTR_MESH_IFINDEX);
  	if (!ifindex)
  		return -EINVAL;
  
  	soft_iface = dev_get_by_index(net, ifindex);
  	if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
  		ret = -ENODEV;
  		goto out;
  	}
  
  	bat_priv = netdev_priv(soft_iface);
  	hash = bat_priv->dat.hash;
  
  	primary_if = batadv_primary_if_get_selected(bat_priv);
  	if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
  		ret = -ENOENT;
  		goto out;
  	}
  
  	while (bucket < hash->size) {
6f81652a4   Sven Eckelmann   batman-adv: Add i...
1005
  		if (batadv_dat_cache_dump_bucket(msg, portid, cb, hash, bucket,
41aeefcc3   Linus Lüssing   batman-adv: add D...
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
  						 &idx))
  			break;
  
  		bucket++;
  		idx = 0;
  	}
  
  	cb->args[0] = bucket;
  	cb->args[1] = idx;
  
  	ret = msg->len;
  
  out:
  	if (primary_if)
  		batadv_hardif_put(primary_if);
  
  	if (soft_iface)
  		dev_put(soft_iface);
  
  	return ret;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
1029
   * batadv_arp_get_type() - parse an ARP packet and gets the type
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
1030
1031
1032
1033
   * @bat_priv: the bat priv with all the soft interface information
   * @skb: packet to analyse
   * @hdr_size: size of the possible header before the ARP packet in the skb
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
1034
   * Return: the ARP type if the skb contains a valid ARP packet, 0 otherwise.
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
1035
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1036
1037
  static u16 batadv_arp_get_type(struct batadv_priv *bat_priv,
  			       struct sk_buff *skb, int hdr_size)
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
1038
1039
1040
1041
  {
  	struct arphdr *arphdr;
  	struct ethhdr *ethhdr;
  	__be32 ip_src, ip_dst;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1042
1043
  	u8 *hw_src, *hw_dst;
  	u16 type = 0;
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
  
  	/* pull the ethernet header */
  	if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN)))
  		goto out;
  
  	ethhdr = (struct ethhdr *)(skb->data + hdr_size);
  
  	if (ethhdr->h_proto != htons(ETH_P_ARP))
  		goto out;
  
  	/* pull the ARP payload */
  	if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN +
  				    arp_hdr_len(skb->dev))))
  		goto out;
  
  	arphdr = (struct arphdr *)(skb->data + hdr_size + ETH_HLEN);
93178018e   Marek Lindner   batman-adv: fix t...
1060
  	/* check whether the ARP packet carries a valid IP information */
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
  	if (arphdr->ar_hrd != htons(ARPHRD_ETHER))
  		goto out;
  
  	if (arphdr->ar_pro != htons(ETH_P_IP))
  		goto out;
  
  	if (arphdr->ar_hln != ETH_ALEN)
  		goto out;
  
  	if (arphdr->ar_pln != 4)
  		goto out;
  
  	/* Check for bad reply/request. If the ARP message is not sane, DAT
  	 * will simply ignore it
  	 */
  	ip_src = batadv_arp_ip_src(skb, hdr_size);
  	ip_dst = batadv_arp_ip_dst(skb, hdr_size);
  	if (ipv4_is_loopback(ip_src) || ipv4_is_multicast(ip_src) ||
757dd82ea   Matthias Schiffer   batman-adv: check...
1079
1080
1081
  	    ipv4_is_loopback(ip_dst) || ipv4_is_multicast(ip_dst) ||
  	    ipv4_is_zeronet(ip_src) || ipv4_is_lbcast(ip_src) ||
  	    ipv4_is_zeronet(ip_dst) || ipv4_is_lbcast(ip_dst))
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
1082
  		goto out;
b618ad110   Matthias Schiffer   batman-adv: filte...
1083
1084
1085
  	hw_src = batadv_arp_hw_src(skb, hdr_size);
  	if (is_zero_ether_addr(hw_src) || is_multicast_ether_addr(hw_src))
  		goto out;
93178018e   Marek Lindner   batman-adv: fix t...
1086
  	/* don't care about the destination MAC address in ARP requests */
b618ad110   Matthias Schiffer   batman-adv: filte...
1087
1088
1089
1090
1091
1092
  	if (arphdr->ar_op != htons(ARPOP_REQUEST)) {
  		hw_dst = batadv_arp_hw_dst(skb, hdr_size);
  		if (is_zero_ether_addr(hw_dst) ||
  		    is_multicast_ether_addr(hw_dst))
  			goto out;
  	}
5c3a0e553   Antonio Quartulli   batman-adv: Distr...
1093
1094
1095
1096
  	type = ntohs(arphdr->ar_op);
  out:
  	return type;
  }
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1097
1098
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
1099
   * batadv_dat_get_vid() - extract the VLAN identifier from skb if any
be1db4f66   Antonio Quartulli   batman-adv: make ...
1100
1101
1102
   * @skb: the buffer containing the packet to extract the VID from
   * @hdr_size: the size of the batman-adv header encapsulating the packet
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
1103
1104
1105
   * Return: If the packet embedded in the skb is vlan tagged this function
   * returns the VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS
   * is returned.
be1db4f66   Antonio Quartulli   batman-adv: make ...
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
   */
  static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size)
  {
  	unsigned short vid;
  
  	vid = batadv_get_vid(skb, *hdr_size);
  
  	/* ARP parsing functions jump forward of hdr_size + ETH_HLEN.
  	 * If the header contained in the packet is a VLAN one (which is longer)
  	 * hdr_size is updated so that the functions will still skip the
  	 * correct amount of bytes.
  	 */
  	if (vid & BATADV_VLAN_HAS_TAG)
  		*hdr_size += VLAN_HLEN;
  
  	return vid;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
1125
   * batadv_dat_arp_create_reply() - create an ARP Reply
cbfc16de3   Linus Lüssing   batman-adv: Add w...
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
   * @bat_priv: the bat priv with all the soft interface information
   * @ip_src: ARP sender IP
   * @ip_dst: ARP target IP
   * @hw_src: Ethernet source and ARP sender MAC
   * @hw_dst: Ethernet destination and ARP target MAC
   * @vid: VLAN identifier (optional, set to zero otherwise)
   *
   * Creates an ARP Reply from the given values, optionally encapsulated in a
   * VLAN header.
   *
   * Return: An skb containing an ARP Reply.
   */
  static struct sk_buff *
  batadv_dat_arp_create_reply(struct batadv_priv *bat_priv, __be32 ip_src,
  			    __be32 ip_dst, u8 *hw_src, u8 *hw_dst,
  			    unsigned short vid)
  {
  	struct sk_buff *skb;
  
  	skb = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_dst, bat_priv->soft_iface,
  			 ip_src, hw_dst, hw_src, hw_dst);
  	if (!skb)
  		return NULL;
  
  	skb_reset_mac_header(skb);
  
  	if (vid & BATADV_VLAN_HAS_TAG)
  		skb = vlan_insert_tag(skb, htons(ETH_P_8021Q),
  				      vid & VLAN_VID_MASK);
  
  	return skb;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
1160
   * batadv_dat_snoop_outgoing_arp_request() - snoop the ARP request and try to
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1161
1162
1163
1164
   * answer using DAT
   * @bat_priv: the bat priv with all the soft interface information
   * @skb: packet to check
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
1165
   * Return: true if the message has been sent to the dht candidates, false
93178018e   Marek Lindner   batman-adv: fix t...
1166
1167
   * otherwise. In case of a positive return value the message has to be enqueued
   * to permit the fallback.
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1168
1169
1170
1171
   */
  bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
  					   struct sk_buff *skb)
  {
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1172
  	u16 type = 0;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1173
  	__be32 ip_dst, ip_src;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1174
  	u8 *hw_src;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1175
1176
1177
  	bool ret = false;
  	struct batadv_dat_entry *dat_entry = NULL;
  	struct sk_buff *skb_new;
ab044f8e3   Tobias Klauser   batman-adv: Use n...
1178
  	struct net_device *soft_iface = bat_priv->soft_iface;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1179
1180
  	int hdr_size = 0;
  	unsigned short vid;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1181

33af49ad8   Antonio Quartulli   batman-adv: Distr...
1182
1183
  	if (!atomic_read(&bat_priv->distributed_arp_table))
  		goto out;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1184
1185
1186
  	vid = batadv_dat_get_vid(skb, &hdr_size);
  
  	type = batadv_arp_get_type(bat_priv, skb, hdr_size);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1187
1188
1189
1190
1191
  	/* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast
  	 * message to the selected DHT candidates
  	 */
  	if (type != ARPOP_REQUEST)
  		goto out;
843314c97   Antonio Quartulli   batman-adv: remov...
1192
  	batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing outgoing ARP REQUEST");
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1193

be1db4f66   Antonio Quartulli   batman-adv: make ...
1194
1195
1196
  	ip_src = batadv_arp_ip_src(skb, hdr_size);
  	hw_src = batadv_arp_hw_src(skb, hdr_size);
  	ip_dst = batadv_arp_ip_dst(skb, hdr_size);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1197

be1db4f66   Antonio Quartulli   batman-adv: make ...
1198
  	batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1199

be1db4f66   Antonio Quartulli   batman-adv: make ...
1200
  	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1201
  	if (dat_entry) {
88e48d7b3   Antonio Quartulli   batman-adv: make ...
1202
1203
1204
1205
1206
1207
1208
1209
  		/* If the ARP request is destined for a local client the local
  		 * client will answer itself. DAT would only generate a
  		 * duplicate packet.
  		 *
  		 * Moreover, if the soft-interface is enslaved into a bridge, an
  		 * additional DAT answer may trigger kernel warnings about
  		 * a packet coming from the wrong port.
  		 */
cc2f33860   Antonio Quartulli   batman-adv: fix l...
1210
  		if (batadv_is_my_client(bat_priv, dat_entry->mac_addr, vid)) {
88e48d7b3   Antonio Quartulli   batman-adv: make ...
1211
1212
1213
  			ret = true;
  			goto out;
  		}
00311de5f   Andreas Pape   batman-adv: preve...
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
  		/* If BLA is enabled, only send ARP replies if we have claimed
  		 * the destination for the ARP request or if no one else of
  		 * the backbone gws belonging to our backbone has claimed the
  		 * destination.
  		 */
  		if (!batadv_bla_check_claim(bat_priv,
  					    dat_entry->mac_addr, vid)) {
  			batadv_dbg(BATADV_DBG_DAT, bat_priv,
  				   "Device %pM claimed by another backbone gw. Don't send ARP reply!",
  				   dat_entry->mac_addr);
  			ret = true;
  			goto out;
  		}
cbfc16de3   Linus Lüssing   batman-adv: Add w...
1227
1228
1229
  		skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
  						      dat_entry->mac_addr,
  						      hw_src, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1230
1231
  		if (!skb_new)
  			goto out;
ab044f8e3   Tobias Klauser   batman-adv: Use n...
1232
  		skb_new->protocol = eth_type_trans(skb_new, soft_iface);
36d4d68cd   Sven Eckelmann   batman-adv: Fix r...
1233
1234
1235
  		batadv_inc_counter(bat_priv, BATADV_CNT_RX);
  		batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
  				   skb->len + ETH_HLEN + hdr_size);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1236
1237
1238
1239
1240
1241
  
  		netif_rx(skb_new);
  		batadv_dbg(BATADV_DBG_DAT, bat_priv, "ARP request replied locally
  ");
  		ret = true;
  	} else {
93178018e   Marek Lindner   batman-adv: fix t...
1242
  		/* Send the request to the DHT */
c2d8b9a6c   Sven Eckelmann   batman-adv: Adjus...
1243
1244
  		ret = batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,
  					      BATADV_P_DAT_DHT_GET);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1245
1246
1247
  	}
  out:
  	if (dat_entry)
a6416f9ff   Sven Eckelmann   batman-adv: Renam...
1248
  		batadv_dat_entry_put(dat_entry);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1249
1250
1251
1252
  	return ret;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
1253
   * batadv_dat_snoop_incoming_arp_request() - snoop the ARP request and try to
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1254
1255
1256
1257
1258
   * answer using the local DAT storage
   * @bat_priv: the bat priv with all the soft interface information
   * @skb: packet to check
   * @hdr_size: size of the encapsulation header
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
1259
   * Return: true if the request has been answered, false otherwise.
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1260
1261
1262
1263
   */
  bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
  					   struct sk_buff *skb, int hdr_size)
  {
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1264
  	u16 type;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1265
  	__be32 ip_src, ip_dst;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1266
  	u8 *hw_src;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1267
  	struct sk_buff *skb_new;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1268
1269
  	struct batadv_dat_entry *dat_entry = NULL;
  	bool ret = false;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1270
  	unsigned short vid;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1271
  	int err;
33af49ad8   Antonio Quartulli   batman-adv: Distr...
1272
1273
  	if (!atomic_read(&bat_priv->distributed_arp_table))
  		goto out;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1274
  	vid = batadv_dat_get_vid(skb, &hdr_size);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1275
1276
1277
1278
1279
1280
1281
  	type = batadv_arp_get_type(bat_priv, skb, hdr_size);
  	if (type != ARPOP_REQUEST)
  		goto out;
  
  	hw_src = batadv_arp_hw_src(skb, hdr_size);
  	ip_src = batadv_arp_ip_src(skb, hdr_size);
  	ip_dst = batadv_arp_ip_dst(skb, hdr_size);
843314c97   Antonio Quartulli   batman-adv: remov...
1282
  	batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing incoming ARP REQUEST");
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1283

be1db4f66   Antonio Quartulli   batman-adv: make ...
1284
  	batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1285

be1db4f66   Antonio Quartulli   batman-adv: make ...
1286
  	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1287
1288
  	if (!dat_entry)
  		goto out;
cbfc16de3   Linus Lüssing   batman-adv: Add w...
1289
1290
  	skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
  					      dat_entry->mac_addr, hw_src, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1291
1292
  	if (!skb_new)
  		goto out;
93178018e   Marek Lindner   batman-adv: fix t...
1293
1294
1295
  	/* To preserve backwards compatibility, the node has choose the outgoing
  	 * format based on the incoming request packet type. The assumption is
  	 * that a node not using the 4addr packet format doesn't support it.
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1296
1297
  	 */
  	if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
e300d3146   Linus Lüssing   batman-adv: refin...
1298
1299
  		err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new,
  						   BATADV_P_DAT_CACHE_REPLY,
6c413b1c2   Antonio Quartulli   batman-adv: send ...
1300
  						   NULL, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1301
  	else
6c413b1c2   Antonio Quartulli   batman-adv: send ...
1302
  		err = batadv_send_skb_via_tt(bat_priv, skb_new, NULL, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1303

e300d3146   Linus Lüssing   batman-adv: refin...
1304
  	if (err != NET_XMIT_DROP) {
4046b24af   Martin Hundebøll   batman-adv: Add g...
1305
  		batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1306
  		ret = true;
4046b24af   Martin Hundebøll   batman-adv: Add g...
1307
  	}
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1308
1309
  out:
  	if (dat_entry)
a6416f9ff   Sven Eckelmann   batman-adv: Renam...
1310
  		batadv_dat_entry_put(dat_entry);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1311
1312
1313
1314
1315
1316
  	if (ret)
  		kfree_skb(skb);
  	return ret;
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
1317
   * batadv_dat_snoop_outgoing_arp_reply() - snoop the ARP reply and fill the DHT
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1318
1319
1320
1321
1322
1323
   * @bat_priv: the bat priv with all the soft interface information
   * @skb: packet to check
   */
  void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
  					 struct sk_buff *skb)
  {
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1324
  	u16 type;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1325
  	__be32 ip_src, ip_dst;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1326
  	u8 *hw_src, *hw_dst;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1327
1328
  	int hdr_size = 0;
  	unsigned short vid;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1329

33af49ad8   Antonio Quartulli   batman-adv: Distr...
1330
1331
  	if (!atomic_read(&bat_priv->distributed_arp_table))
  		return;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1332
1333
1334
  	vid = batadv_dat_get_vid(skb, &hdr_size);
  
  	type = batadv_arp_get_type(bat_priv, skb, hdr_size);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1335
1336
  	if (type != ARPOP_REPLY)
  		return;
843314c97   Antonio Quartulli   batman-adv: remov...
1337
  	batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing outgoing ARP REPLY");
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1338

be1db4f66   Antonio Quartulli   batman-adv: make ...
1339
1340
1341
1342
  	hw_src = batadv_arp_hw_src(skb, hdr_size);
  	ip_src = batadv_arp_ip_src(skb, hdr_size);
  	hw_dst = batadv_arp_hw_dst(skb, hdr_size);
  	ip_dst = batadv_arp_ip_dst(skb, hdr_size);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1343

be1db4f66   Antonio Quartulli   batman-adv: make ...
1344
1345
  	batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
  	batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1346
1347
  
  	/* Send the ARP reply to the candidates for both the IP addresses that
93178018e   Marek Lindner   batman-adv: fix t...
1348
  	 * the node obtained from the ARP reply
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1349
  	 */
c2d8b9a6c   Sven Eckelmann   batman-adv: Adjus...
1350
1351
1352
1353
  	batadv_dat_forward_data(bat_priv, skb, ip_src, vid,
  				BATADV_P_DAT_DHT_PUT);
  	batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,
  				BATADV_P_DAT_DHT_PUT);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1354
  }
aa143d283   Antonio Quartulli   batman-adv: check...
1355

c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1356
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
1357
1358
   * batadv_dat_snoop_incoming_arp_reply() - snoop the ARP reply and fill the
   *  local DAT storage only
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1359
1360
   * @bat_priv: the bat priv with all the soft interface information
   * @skb: packet to check
93178018e   Marek Lindner   batman-adv: fix t...
1361
   * @hdr_size: size of the encapsulation header
f202a666e   Antonio Quartulli   batman-adv: avoid...
1362
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
1363
   * Return: true if the packet was snooped and consumed by DAT. False if the
f202a666e   Antonio Quartulli   batman-adv: avoid...
1364
   * packet has to be delivered to the interface
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1365
1366
1367
1368
   */
  bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
  					 struct sk_buff *skb, int hdr_size)
  {
9aa5cd79b   Andreas Pape   batman-adv: preve...
1369
  	struct batadv_dat_entry *dat_entry = NULL;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1370
  	u16 type;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1371
  	__be32 ip_src, ip_dst;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1372
  	u8 *hw_src, *hw_dst;
f202a666e   Antonio Quartulli   batman-adv: avoid...
1373
  	bool dropped = false;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1374
  	unsigned short vid;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1375

33af49ad8   Antonio Quartulli   batman-adv: Distr...
1376
1377
  	if (!atomic_read(&bat_priv->distributed_arp_table))
  		goto out;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1378
  	vid = batadv_dat_get_vid(skb, &hdr_size);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1379
1380
1381
  	type = batadv_arp_get_type(bat_priv, skb, hdr_size);
  	if (type != ARPOP_REPLY)
  		goto out;
843314c97   Antonio Quartulli   batman-adv: remov...
1382
  	batadv_dbg_arp(bat_priv, skb, hdr_size, "Parsing incoming ARP REPLY");
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1383
1384
1385
1386
1387
  
  	hw_src = batadv_arp_hw_src(skb, hdr_size);
  	ip_src = batadv_arp_ip_src(skb, hdr_size);
  	hw_dst = batadv_arp_hw_dst(skb, hdr_size);
  	ip_dst = batadv_arp_ip_dst(skb, hdr_size);
9aa5cd79b   Andreas Pape   batman-adv: preve...
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
  	/* If ip_dst is already in cache and has the right mac address,
  	 * drop this frame if this ARP reply is destined for us because it's
  	 * most probably an ARP reply generated by another node of the DHT.
  	 * We have most probably received already a reply earlier. Delivering
  	 * this frame would lead to doubled receive of an ARP reply.
  	 */
  	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_src, vid);
  	if (dat_entry && batadv_compare_eth(hw_src, dat_entry->mac_addr)) {
  		batadv_dbg(BATADV_DBG_DAT, bat_priv, "Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4
  ",
  			   hw_src, &ip_src, hw_dst, &ip_dst,
  			   dat_entry->mac_addr,	&dat_entry->ip);
  		dropped = true;
9aa5cd79b   Andreas Pape   batman-adv: preve...
1401
  	}
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1402
1403
1404
  	/* Update our internal cache with both the IP addresses the node got
  	 * within the ARP reply
  	 */
be1db4f66   Antonio Quartulli   batman-adv: make ...
1405
1406
  	batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
  	batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1407

099e6cc15   Linus Lüssing   batman-adv: allow...
1408
1409
  	if (dropped)
  		goto out;
9aa5cd79b   Andreas Pape   batman-adv: preve...
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
  	/* If BLA is enabled, only forward ARP replies if we have claimed the
  	 * source of the ARP reply or if no one else of the same backbone has
  	 * already claimed that client. This prevents that different gateways
  	 * to the same backbone all forward the ARP reply leading to multiple
  	 * replies in the backbone.
  	 */
  	if (!batadv_bla_check_claim(bat_priv, hw_src, vid)) {
  		batadv_dbg(BATADV_DBG_DAT, bat_priv,
  			   "Device %pM claimed by another backbone gw. Drop ARP reply.
  ",
  			   hw_src);
  		dropped = true;
  		goto out;
  	}
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1424
1425
1426
  	/* if this REPLY is directed to a client of mine, let's deliver the
  	 * packet to the interface
  	 */
f202a666e   Antonio Quartulli   batman-adv: avoid...
1427
1428
1429
1430
1431
1432
  	dropped = !batadv_is_my_client(bat_priv, hw_dst, vid);
  
  	/* if this REPLY is sent on behalf of a client of mine, let's drop the
  	 * packet because the client will reply by itself
  	 */
  	dropped |= batadv_is_my_client(bat_priv, hw_src, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1433
  out:
f202a666e   Antonio Quartulli   batman-adv: avoid...
1434
  	if (dropped)
0d15becee   Matthias Schiffer   batman-adv: fix s...
1435
  		kfree_skb(skb);
9aa5cd79b   Andreas Pape   batman-adv: preve...
1436
1437
  	if (dat_entry)
  		batadv_dat_entry_put(dat_entry);
f202a666e   Antonio Quartulli   batman-adv: avoid...
1438
1439
  	/* if dropped == false -> deliver to the interface */
  	return dropped;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1440
1441
1442
  }
  
  /**
b61ec31c8   Linus Lüssing   batman-adv: Snoop...
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
   * batadv_dat_check_dhcp_ipudp() - check skb for IP+UDP headers valid for DHCP
   * @skb: the packet to check
   * @ip_src: a buffer to store the IPv4 source address in
   *
   * Checks whether the given skb has an IP and UDP header valid for a DHCP
   * message from a DHCP server. And if so, stores the IPv4 source address in
   * the provided buffer.
   *
   * Return: True if valid, false otherwise.
   */
  static bool
  batadv_dat_check_dhcp_ipudp(struct sk_buff *skb, __be32 *ip_src)
  {
  	unsigned int offset = skb_network_offset(skb);
  	struct udphdr *udphdr, _udphdr;
  	struct iphdr *iphdr, _iphdr;
  
  	iphdr = skb_header_pointer(skb, offset, sizeof(_iphdr), &_iphdr);
  	if (!iphdr || iphdr->version != 4 || iphdr->ihl * 4 < sizeof(_iphdr))
  		return false;
  
  	if (iphdr->protocol != IPPROTO_UDP)
  		return false;
  
  	offset += iphdr->ihl * 4;
  	skb_set_transport_header(skb, offset);
  
  	udphdr = skb_header_pointer(skb, offset, sizeof(_udphdr), &_udphdr);
  	if (!udphdr || udphdr->source != htons(67))
  		return false;
  
  	*ip_src = get_unaligned(&iphdr->saddr);
  
  	return true;
  }
  
  /**
   * batadv_dat_check_dhcp() - examine packet for valid DHCP message
   * @skb: the packet to check
   * @proto: ethernet protocol hint (behind a potential vlan)
   * @ip_src: a buffer to store the IPv4 source address in
   *
   * Checks whether the given skb is a valid DHCP packet. And if so, stores the
   * IPv4 source address in the provided buffer.
   *
   * Caller needs to ensure that the skb network header is set correctly.
   *
   * Return: If skb is a valid DHCP packet, then returns its op code
   * (e.g. BOOTREPLY vs. BOOTREQUEST). Otherwise returns -EINVAL.
   */
  static int
  batadv_dat_check_dhcp(struct sk_buff *skb, __be16 proto, __be32 *ip_src)
  {
  	__be32 *magic, _magic;
  	unsigned int offset;
  	struct {
  		__u8 op;
  		__u8 htype;
  		__u8 hlen;
  		__u8 hops;
  	} *dhcp_h, _dhcp_h;
  
  	if (proto != htons(ETH_P_IP))
  		return -EINVAL;
  
  	if (!batadv_dat_check_dhcp_ipudp(skb, ip_src))
  		return -EINVAL;
  
  	offset = skb_transport_offset(skb) + sizeof(struct udphdr);
  	if (skb->len < offset + sizeof(struct batadv_dhcp_packet))
  		return -EINVAL;
  
  	dhcp_h = skb_header_pointer(skb, offset, sizeof(_dhcp_h), &_dhcp_h);
  	if (!dhcp_h || dhcp_h->htype != BATADV_HTYPE_ETHERNET ||
  	    dhcp_h->hlen != ETH_ALEN)
  		return -EINVAL;
  
  	offset += offsetof(struct batadv_dhcp_packet, magic);
  
  	magic = skb_header_pointer(skb, offset, sizeof(_magic), &_magic);
  	if (!magic || get_unaligned(magic) != htonl(BATADV_DHCP_MAGIC))
  		return -EINVAL;
  
  	return dhcp_h->op;
  }
  
  /**
   * batadv_dat_get_dhcp_message_type() - get message type of a DHCP packet
   * @skb: the DHCP packet to parse
   *
   * Iterates over the DHCP options of the given DHCP packet to find a
   * DHCP Message Type option and parse it.
   *
   * Caller needs to ensure that the given skb is a valid DHCP packet and
   * that the skb transport header is set correctly.
   *
   * Return: The found DHCP message type value, if found. -EINVAL otherwise.
   */
  static int batadv_dat_get_dhcp_message_type(struct sk_buff *skb)
  {
  	unsigned int offset = skb_transport_offset(skb) + sizeof(struct udphdr);
  	u8 *type, _type;
  	struct {
  		u8 type;
  		u8 len;
  	} *tl, _tl;
  
  	offset += sizeof(struct batadv_dhcp_packet);
  
  	while ((tl = skb_header_pointer(skb, offset, sizeof(_tl), &_tl))) {
  		if (tl->type == BATADV_DHCP_OPT_MSG_TYPE)
  			break;
  
  		if (tl->type == BATADV_DHCP_OPT_END)
  			break;
  
  		if (tl->type == BATADV_DHCP_OPT_PAD)
  			offset++;
  		else
  			offset += tl->len + sizeof(_tl);
  	}
  
  	/* Option Overload Code not supported */
  	if (!tl || tl->type != BATADV_DHCP_OPT_MSG_TYPE ||
  	    tl->len != sizeof(_type))
  		return -EINVAL;
  
  	offset += sizeof(_tl);
  
  	type = skb_header_pointer(skb, offset, sizeof(_type), &_type);
  	if (!type)
  		return -EINVAL;
  
  	return *type;
  }
  
  /**
   * batadv_dat_get_dhcp_yiaddr() - get yiaddr from a DHCP packet
   * @skb: the DHCP packet to parse
   * @buf: a buffer to store the yiaddr in
   *
   * Caller needs to ensure that the given skb is a valid DHCP packet and
   * that the skb transport header is set correctly.
   *
   * Return: True on success, false otherwise.
   */
  static bool batadv_dat_dhcp_get_yiaddr(struct sk_buff *skb, __be32 *buf)
  {
  	unsigned int offset = skb_transport_offset(skb) + sizeof(struct udphdr);
  	__be32 *yiaddr;
  
  	offset += offsetof(struct batadv_dhcp_packet, yiaddr);
  	yiaddr = skb_header_pointer(skb, offset, BATADV_DHCP_YIADDR_LEN, buf);
  
  	if (!yiaddr)
  		return false;
  
  	if (yiaddr != buf)
  		*buf = get_unaligned(yiaddr);
  
  	return true;
  }
  
  /**
   * batadv_dat_get_dhcp_chaddr() - get chaddr from a DHCP packet
   * @skb: the DHCP packet to parse
   * @buf: a buffer to store the chaddr in
   *
   * Caller needs to ensure that the given skb is a valid DHCP packet and
   * that the skb transport header is set correctly.
   *
   * Return: True on success, false otherwise
   */
  static bool batadv_dat_get_dhcp_chaddr(struct sk_buff *skb, u8 *buf)
  {
  	unsigned int offset = skb_transport_offset(skb) + sizeof(struct udphdr);
  	u8 *chaddr;
  
  	offset += offsetof(struct batadv_dhcp_packet, chaddr);
  	chaddr = skb_header_pointer(skb, offset, BATADV_DHCP_CHADDR_LEN, buf);
  
  	if (!chaddr)
  		return false;
  
  	if (chaddr != buf)
  		memcpy(buf, chaddr, BATADV_DHCP_CHADDR_LEN);
  
  	return true;
  }
  
  /**
   * batadv_dat_put_dhcp() - puts addresses from a DHCP packet into the DHT and
   *  DAT cache
   * @bat_priv: the bat priv with all the soft interface information
   * @chaddr: the DHCP client MAC address
   * @yiaddr: the DHCP client IP address
   * @hw_dst: the DHCP server MAC address
   * @ip_dst: the DHCP server IP address
   * @vid: VLAN identifier
   *
   * Adds given MAC/IP pairs to the local DAT cache and propagates them further
   * into the DHT.
   *
   * For the DHT propagation, client MAC + IP will appear as the ARP Reply
   * transmitter (and hw_dst/ip_dst as the target).
   */
  static void batadv_dat_put_dhcp(struct batadv_priv *bat_priv, u8 *chaddr,
  				__be32 yiaddr, u8 *hw_dst, __be32 ip_dst,
  				unsigned short vid)
  {
  	struct sk_buff *skb;
  
  	skb = batadv_dat_arp_create_reply(bat_priv, yiaddr, ip_dst, chaddr,
  					  hw_dst, vid);
  	if (!skb)
  		return;
  
  	skb_set_network_header(skb, ETH_HLEN);
  
  	batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid);
  	batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
c2d8b9a6c   Sven Eckelmann   batman-adv: Adjus...
1664
1665
1666
1667
  	batadv_dat_forward_data(bat_priv, skb, yiaddr, vid,
  				BATADV_P_DAT_DHT_PUT);
  	batadv_dat_forward_data(bat_priv, skb, ip_dst, vid,
  				BATADV_P_DAT_DHT_PUT);
b61ec31c8   Linus Lüssing   batman-adv: Snoop...
1668

5f320f09b   Martin Weinelt   batman-adv: fix m...
1669
  	consume_skb(skb);
b61ec31c8   Linus Lüssing   batman-adv: Snoop...
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
  	batadv_dbg(BATADV_DBG_DAT, bat_priv,
  		   "Snooped from outgoing DHCPACK (server address): %pI4, %pM (vid: %i)
  ",
  		   &ip_dst, hw_dst, batadv_print_vid(vid));
  	batadv_dbg(BATADV_DBG_DAT, bat_priv,
  		   "Snooped from outgoing DHCPACK (client address): %pI4, %pM (vid: %i)
  ",
  		   &yiaddr, chaddr, batadv_print_vid(vid));
  }
  
  /**
   * batadv_dat_check_dhcp_ack() - examine packet for valid DHCP message
   * @skb: the packet to check
   * @proto: ethernet protocol hint (behind a potential vlan)
   * @ip_src: a buffer to store the IPv4 source address in
   * @chaddr: a buffer to store the DHCP Client Hardware Address in
   * @yiaddr: a buffer to store the DHCP Your IP Address in
   *
   * Checks whether the given skb is a valid DHCPACK. And if so, stores the
   * IPv4 server source address (ip_src), client MAC address (chaddr) and client
   * IPv4 address (yiaddr) in the provided buffers.
   *
   * Caller needs to ensure that the skb network header is set correctly.
   *
   * Return: True if the skb is a valid DHCPACK. False otherwise.
   */
  static bool
  batadv_dat_check_dhcp_ack(struct sk_buff *skb, __be16 proto, __be32 *ip_src,
  			  u8 *chaddr, __be32 *yiaddr)
  {
  	int type;
  
  	type = batadv_dat_check_dhcp(skb, proto, ip_src);
  	if (type != BATADV_BOOTREPLY)
  		return false;
  
  	type = batadv_dat_get_dhcp_message_type(skb);
  	if (type != BATADV_DHCPACK)
  		return false;
  
  	if (!batadv_dat_dhcp_get_yiaddr(skb, yiaddr))
  		return false;
  
  	if (!batadv_dat_get_dhcp_chaddr(skb, chaddr))
  		return false;
  
  	return true;
  }
  
  /**
   * batadv_dat_snoop_outgoing_dhcp_ack() - snoop DHCPACK and fill DAT with it
   * @bat_priv: the bat priv with all the soft interface information
   * @skb: the packet to snoop
   * @proto: ethernet protocol hint (behind a potential vlan)
   * @vid: VLAN identifier
   *
   * This function first checks whether the given skb is a valid DHCPACK. If
   * so then its source MAC and IP as well as its DHCP Client Hardware Address
   * field and DHCP Your IP Address field are added to the local DAT cache and
   * propagated into the DHT.
   *
   * Caller needs to ensure that the skb mac and network headers are set
   * correctly.
   */
  void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv,
  					struct sk_buff *skb,
  					__be16 proto,
  					unsigned short vid)
  {
  	u8 chaddr[BATADV_DHCP_CHADDR_LEN];
  	__be32 ip_src, yiaddr;
  
  	if (!atomic_read(&bat_priv->distributed_arp_table))
  		return;
  
  	if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr))
  		return;
  
  	batadv_dat_put_dhcp(bat_priv, chaddr, yiaddr, eth_hdr(skb)->h_source,
  			    ip_src, vid);
  }
  
  /**
   * batadv_dat_snoop_incoming_dhcp_ack() - snoop DHCPACK and fill DAT cache
   * @bat_priv: the bat priv with all the soft interface information
   * @skb: the packet to snoop
   * @hdr_size: header size, up to the tail of the batman-adv header
   *
   * This function first checks whether the given skb is a valid DHCPACK. If
   * so then its source MAC and IP as well as its DHCP Client Hardware Address
   * field and DHCP Your IP Address field are added to the local DAT cache.
   */
  void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv,
  					struct sk_buff *skb, int hdr_size)
  {
  	u8 chaddr[BATADV_DHCP_CHADDR_LEN];
  	struct ethhdr *ethhdr;
  	__be32 ip_src, yiaddr;
  	unsigned short vid;
  	__be16 proto;
  	u8 *hw_src;
  
  	if (!atomic_read(&bat_priv->distributed_arp_table))
  		return;
  
  	if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN)))
  		return;
  
  	ethhdr = (struct ethhdr *)(skb->data + hdr_size);
  	skb_set_network_header(skb, hdr_size + ETH_HLEN);
  	proto = ethhdr->h_proto;
  
  	if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr))
  		return;
  
  	hw_src = ethhdr->h_source;
  	vid = batadv_dat_get_vid(skb, &hdr_size);
  
  	batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid);
  	batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
  
  	batadv_dbg(BATADV_DBG_DAT, bat_priv,
  		   "Snooped from incoming DHCPACK (server address): %pI4, %pM (vid: %i)
  ",
  		   &ip_src, hw_src, batadv_print_vid(vid));
  	batadv_dbg(BATADV_DBG_DAT, bat_priv,
  		   "Snooped from incoming DHCPACK (client address): %pI4, %pM (vid: %i)
  ",
  		   &yiaddr, chaddr, batadv_print_vid(vid));
  }
  
  /**
7e9a8c2ce   Sven Eckelmann   batman-adv: Use p...
1802
1803
   * batadv_dat_drop_broadcast_packet() - check if an ARP request has to be
   *  dropped (because the node has already obtained the reply via DAT) or not
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1804
1805
1806
   * @bat_priv: the bat priv with all the soft interface information
   * @forw_packet: the broadcast packet
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
1807
   * Return: true if the node can drop the packet, false otherwise.
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1808
1809
1810
1811
   */
  bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
  				      struct batadv_forw_packet *forw_packet)
  {
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1812
  	u16 type;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1813
1814
1815
  	__be32 ip_dst;
  	struct batadv_dat_entry *dat_entry = NULL;
  	bool ret = false;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1816
1817
  	int hdr_size = sizeof(struct batadv_bcast_packet);
  	unsigned short vid;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1818

33af49ad8   Antonio Quartulli   batman-adv: Distr...
1819
1820
  	if (!atomic_read(&bat_priv->distributed_arp_table))
  		goto out;
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1821
1822
1823
  	/* If this packet is an ARP_REQUEST and the node already has the
  	 * information that it is going to ask, then the packet can be dropped
  	 */
e2d9ba435   Linus Lüssing   batman-adv: restr...
1824
  	if (batadv_forw_packet_is_rebroadcast(forw_packet))
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1825
  		goto out;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1826
1827
1828
  	vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size);
  
  	type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1829
1830
  	if (type != ARPOP_REQUEST)
  		goto out;
be1db4f66   Antonio Quartulli   batman-adv: make ...
1831
1832
  	ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size);
  	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
  	/* check if the node already got this entry */
  	if (!dat_entry) {
  		batadv_dbg(BATADV_DBG_DAT, bat_priv,
  			   "ARP Request for %pI4: fallback
  ", &ip_dst);
  		goto out;
  	}
  
  	batadv_dbg(BATADV_DBG_DAT, bat_priv,
  		   "ARP Request for %pI4: fallback prevented
  ", &ip_dst);
  	ret = true;
  
  out:
  	if (dat_entry)
a6416f9ff   Sven Eckelmann   batman-adv: Renam...
1848
  		batadv_dat_entry_put(dat_entry);
c384ea3ec   Antonio Quartulli   batman-adv: Distr...
1849
1850
  	return ret;
  }