Blame view

net/batman-adv/unicast.c 8.74 KB
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1
  /*
64afe3539   Sven Eckelmann   batman-adv: Updat...
2
   * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors:
c6c8fea29   Sven Eckelmann   net: Add batman-a...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
   *
   * Andreas Langer
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   * 02110-1301, USA
   *
   */
  
  #include "main.h"
  #include "unicast.h"
  #include "send.h"
  #include "soft-interface.h"
  #include "gateway_client.h"
  #include "originator.h"
  #include "hash.h"
  #include "translation-table.h"
  #include "routing.h"
  #include "hard-interface.h"
  
  
  static struct sk_buff *frag_merge_packet(struct list_head *head,
  					 struct frag_packet_list_entry *tfp,
  					 struct sk_buff *skb)
  {
  	struct unicast_frag_packet *up =
  		(struct unicast_frag_packet *)skb->data;
  	struct sk_buff *tmp_skb;
  	struct unicast_packet *unicast_packet;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
42
43
  	int hdr_len = sizeof(*unicast_packet);
  	int uni_diff = sizeof(*up) - hdr_len;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
44
45
46
47
48
49
50
51
  
  	/* set skb to the first part and tmp_skb to the second part */
  	if (up->flags & UNI_FRAG_HEAD) {
  		tmp_skb = tfp->skb;
  	} else {
  		tmp_skb = skb;
  		skb = tfp->skb;
  	}
531c9da8c   Sven Eckelmann   batman-adv: Linea...
52
53
  	if (skb_linearize(skb) < 0 || skb_linearize(tmp_skb) < 0)
  		goto err;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
54
  	skb_pull(tmp_skb, sizeof(*up));
531c9da8c   Sven Eckelmann   batman-adv: Linea...
55
56
  	if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0)
  		goto err;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  
  	/* move free entry to end */
  	tfp->skb = NULL;
  	tfp->seqno = 0;
  	list_move_tail(&tfp->list, head);
  
  	memcpy(skb_put(skb, tmp_skb->len), tmp_skb->data, tmp_skb->len);
  	kfree_skb(tmp_skb);
  
  	memmove(skb->data + uni_diff, skb->data, hdr_len);
  	unicast_packet = (struct unicast_packet *) skb_pull(skb, uni_diff);
  	unicast_packet->packet_type = BAT_UNICAST;
  
  	return skb;
531c9da8c   Sven Eckelmann   batman-adv: Linea...
71
72
73
74
75
  
  err:
  	/* free buffered skb, skb will be freed later */
  	kfree_skb(tfp->skb);
  	return NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  }
  
  static void frag_create_entry(struct list_head *head, struct sk_buff *skb)
  {
  	struct frag_packet_list_entry *tfp;
  	struct unicast_frag_packet *up =
  		(struct unicast_frag_packet *)skb->data;
  
  	/* free and oldest packets stand at the end */
  	tfp = list_entry((head)->prev, typeof(*tfp), list);
  	kfree_skb(tfp->skb);
  
  	tfp->seqno = ntohs(up->seqno);
  	tfp->skb = skb;
  	list_move(&tfp->list, head);
  	return;
  }
  
  static int frag_create_buffer(struct list_head *head)
  {
  	int i;
  	struct frag_packet_list_entry *tfp;
  
  	for (i = 0; i < FRAG_BUFFER_SIZE; i++) {
704509b8d   Sven Eckelmann   batman-adv: Calcu...
100
  		tfp = kmalloc(sizeof(*tfp), GFP_ATOMIC);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  		if (!tfp) {
  			frag_list_free(head);
  			return -ENOMEM;
  		}
  		tfp->skb = NULL;
  		tfp->seqno = 0;
  		INIT_LIST_HEAD(&tfp->list);
  		list_add(&tfp->list, head);
  	}
  
  	return 0;
  }
  
  static struct frag_packet_list_entry *frag_search_packet(struct list_head *head,
747e4221a   Sven Eckelmann   batman-adv: Add c...
115
  					   const struct unicast_frag_packet *up)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  {
  	struct frag_packet_list_entry *tfp;
  	struct unicast_frag_packet *tmp_up = NULL;
  	uint16_t search_seqno;
  
  	if (up->flags & UNI_FRAG_HEAD)
  		search_seqno = ntohs(up->seqno)+1;
  	else
  		search_seqno = ntohs(up->seqno)-1;
  
  	list_for_each_entry(tfp, head, list) {
  
  		if (!tfp->skb)
  			continue;
  
  		if (tfp->seqno == ntohs(up->seqno))
  			goto mov_tail;
  
  		tmp_up = (struct unicast_frag_packet *)tfp->skb->data;
  
  		if (tfp->seqno == search_seqno) {
  
  			if ((tmp_up->flags & UNI_FRAG_HEAD) !=
  			    (up->flags & UNI_FRAG_HEAD))
  				return tfp;
  			else
  				goto mov_tail;
  		}
  	}
  	return NULL;
  
  mov_tail:
  	list_move_tail(&tfp->list, head);
  	return NULL;
  }
  
  void frag_list_free(struct list_head *head)
  {
  	struct frag_packet_list_entry *pf, *tmp_pf;
  
  	if (!list_empty(head)) {
  
  		list_for_each_entry_safe(pf, tmp_pf, head, list) {
  			kfree_skb(pf->skb);
  			list_del(&pf->list);
  			kfree(pf);
  		}
  	}
  	return;
  }
  
  /* frag_reassemble_skb():
   * returns NET_RX_DROP if the operation failed - skb is left intact
   * returns NET_RX_SUCCESS if the fragment was buffered (skb_new will be NULL)
   * or the skb could be reassembled (skb_new will point to the new packet and
   * skb was freed)
   */
  int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
  			struct sk_buff **new_skb)
  {
  	struct orig_node *orig_node;
  	struct frag_packet_list_entry *tmp_frag_entry;
  	int ret = NET_RX_DROP;
  	struct unicast_frag_packet *unicast_packet =
  		(struct unicast_frag_packet *)skb->data;
  
  	*new_skb = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
183

7aadf889e   Marek Lindner   batman-adv: remov...
184
185
  	orig_node = orig_hash_find(bat_priv, unicast_packet->orig);
  	if (!orig_node)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
186
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  
  	orig_node->last_frag_packet = jiffies;
  
  	if (list_empty(&orig_node->frag_list) &&
  	    frag_create_buffer(&orig_node->frag_list)) {
  		pr_debug("couldn't create frag buffer
  ");
  		goto out;
  	}
  
  	tmp_frag_entry = frag_search_packet(&orig_node->frag_list,
  					    unicast_packet);
  
  	if (!tmp_frag_entry) {
  		frag_create_entry(&orig_node->frag_list, skb);
  		ret = NET_RX_SUCCESS;
  		goto out;
  	}
  
  	*new_skb = frag_merge_packet(&orig_node->frag_list, tmp_frag_entry,
  				     skb);
  	/* if not, merge failed */
  	if (*new_skb)
  		ret = NET_RX_SUCCESS;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
211

7aadf889e   Marek Lindner   batman-adv: remov...
212
213
  out:
  	if (orig_node)
7b36e8eef   Marek Lindner   batman-adv: Corre...
214
  		orig_node_free_ref(orig_node);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
215
216
217
218
  	return ret;
  }
  
  int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
747e4221a   Sven Eckelmann   batman-adv: Add c...
219
  		  struct hard_iface *hard_iface, const uint8_t dstaddr[])
c6c8fea29   Sven Eckelmann   net: Add batman-a...
220
221
  {
  	struct unicast_packet tmp_uc, *unicast_packet;
32ae9b221   Marek Lindner   batman-adv: Make ...
222
  	struct hard_iface *primary_if;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
223
224
  	struct sk_buff *frag_skb;
  	struct unicast_frag_packet *frag1, *frag2;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
225
226
  	int uc_hdr_len = sizeof(*unicast_packet);
  	int ucf_hdr_len = sizeof(*frag1);
5c77d8bb8   Sven Eckelmann   batman-adv: Creat...
227
  	int data_len = skb->len - uc_hdr_len;
32ae9b221   Marek Lindner   batman-adv: Make ...
228
  	int large_tail = 0, ret = NET_RX_DROP;
c2f7f0e7b   Sven Eckelmann   batman-adv: Use s...
229
  	uint16_t seqno;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
230

32ae9b221   Marek Lindner   batman-adv: Make ...
231
232
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
233
  		goto dropped;
ed7809d9c   Jesper Juhl   batman-adv: Even ...
234
235
236
  	frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len);
  	if (!frag_skb)
  		goto dropped;
5c77d8bb8   Sven Eckelmann   batman-adv: Creat...
237
  	skb_reserve(frag_skb, ucf_hdr_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
238

ed7809d9c   Jesper Juhl   batman-adv: Even ...
239
  	unicast_packet = (struct unicast_packet *) skb->data;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
240
  	memcpy(&tmp_uc, unicast_packet, uc_hdr_len);
5c77d8bb8   Sven Eckelmann   batman-adv: Creat...
241
  	skb_split(skb, frag_skb, data_len / 2 + uc_hdr_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
242
243
244
245
246
247
248
  
  	if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 ||
  	    my_skb_head_push(frag_skb, ucf_hdr_len) < 0)
  		goto drop_frag;
  
  	frag1 = (struct unicast_frag_packet *)skb->data;
  	frag2 = (struct unicast_frag_packet *)frag_skb->data;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
249
  	memcpy(frag1, &tmp_uc, sizeof(tmp_uc));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
250
251
252
253
  
  	frag1->ttl--;
  	frag1->version = COMPAT_VERSION;
  	frag1->packet_type = BAT_UNICAST_FRAG;
32ae9b221   Marek Lindner   batman-adv: Make ...
254
  	memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
704509b8d   Sven Eckelmann   batman-adv: Calcu...
255
  	memcpy(frag2, frag1, sizeof(*frag2));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
256

ae361ce19   Sven Eckelmann   batman-adv: Calcu...
257
258
259
260
261
  	if (data_len & 1)
  		large_tail = UNI_FRAG_LARGETAIL;
  
  	frag1->flags = UNI_FRAG_HEAD | large_tail;
  	frag2->flags = large_tail;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
262

e6c10f433   Marek Lindner   batman-adv: renam...
263
  	seqno = atomic_add_return(2, &hard_iface->frag_seqno);
c2f7f0e7b   Sven Eckelmann   batman-adv: Use s...
264
265
  	frag1->seqno = htons(seqno - 1);
  	frag2->seqno = htons(seqno);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
266

e6c10f433   Marek Lindner   batman-adv: renam...
267
268
  	send_skb_packet(skb, hard_iface, dstaddr);
  	send_skb_packet(frag_skb, hard_iface, dstaddr);
32ae9b221   Marek Lindner   batman-adv: Make ...
269
270
  	ret = NET_RX_SUCCESS;
  	goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
271
272
273
274
275
  
  drop_frag:
  	kfree_skb(frag_skb);
  dropped:
  	kfree_skb(skb);
32ae9b221   Marek Lindner   batman-adv: Make ...
276
277
278
279
  out:
  	if (primary_if)
  		hardif_free_ref(primary_if);
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
280
281
282
283
284
285
  }
  
  int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
  {
  	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
  	struct unicast_packet *unicast_packet;
7b36e8eef   Marek Lindner   batman-adv: Corre...
286
  	struct orig_node *orig_node;
44524fcdf   Marek Lindner   batman-adv: Corre...
287
  	struct neigh_node *neigh_node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
288
  	int data_len = skb->len;
44524fcdf   Marek Lindner   batman-adv: Corre...
289
  	int ret = 1;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
290
291
  
  	/* get routing information */
43c70ad5c   Linus Lüssing   batman-adv: Incre...
292
  	if (is_multicast_ether_addr(ethhdr->h_dest)) {
958ca5985   Sven Eckelmann   batman-adv: Remov...
293
  		orig_node = gw_get_selected_orig(bat_priv);
43c70ad5c   Linus Lüssing   batman-adv: Incre...
294
  		if (orig_node)
44524fcdf   Marek Lindner   batman-adv: Corre...
295
296
  			goto find_router;
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
297

3d393e473   Antonio Quartulli   batman-adv: imple...
298
299
300
301
  	/* check for tt host - increases orig_node refcount.
  	 * returns NULL in case of AP isolation */
  	orig_node = transtable_search(bat_priv, ethhdr->h_source,
  				      ethhdr->h_dest);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
302

44524fcdf   Marek Lindner   batman-adv: Corre...
303
  find_router:
d0072609b   Marek Lindner   batman-adv: remov...
304
305
306
307
308
  	/**
  	 * find_router():
  	 *  - if orig_node is NULL it returns NULL
  	 *  - increases neigh_nodes refcount if found.
  	 */
44524fcdf   Marek Lindner   batman-adv: Corre...
309
  	neigh_node = find_router(bat_priv, orig_node, NULL);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
310

44524fcdf   Marek Lindner   batman-adv: Corre...
311
  	if (!neigh_node)
d0072609b   Marek Lindner   batman-adv: remov...
312
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
313

704509b8d   Sven Eckelmann   batman-adv: Calcu...
314
  	if (my_skb_head_push(skb, sizeof(*unicast_packet)) < 0)
d0072609b   Marek Lindner   batman-adv: remov...
315
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
316
317
318
319
320
321
322
323
324
325
  
  	unicast_packet = (struct unicast_packet *)skb->data;
  
  	unicast_packet->version = COMPAT_VERSION;
  	/* batman packet type: unicast */
  	unicast_packet->packet_type = BAT_UNICAST;
  	/* set unicast ttl */
  	unicast_packet->ttl = TTL;
  	/* copy the destination for faster routing */
  	memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
a73105b8d   Antonio Quartulli   batman-adv: impro...
326
327
328
  	/* set the destination tt version number */
  	unicast_packet->ttvn =
  		(uint8_t)atomic_read(&orig_node->last_ttvn);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
329
330
  
  	if (atomic_read(&bat_priv->fragmentation) &&
704509b8d   Sven Eckelmann   batman-adv: Calcu...
331
  	    data_len + sizeof(*unicast_packet) >
d0072609b   Marek Lindner   batman-adv: remov...
332
  				neigh_node->if_incoming->net_dev->mtu) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
333
334
  		/* send frag skb decreases ttl */
  		unicast_packet->ttl++;
d0072609b   Marek Lindner   batman-adv: remov...
335
336
  		ret = frag_send_skb(skb, bat_priv,
  				    neigh_node->if_incoming, neigh_node->addr);
44524fcdf   Marek Lindner   batman-adv: Corre...
337
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
338
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
339

d0072609b   Marek Lindner   batman-adv: remov...
340
  	send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
44524fcdf   Marek Lindner   batman-adv: Corre...
341
342
  	ret = 0;
  	goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
343

44524fcdf   Marek Lindner   batman-adv: Corre...
344
345
346
347
  out:
  	if (neigh_node)
  		neigh_node_free_ref(neigh_node);
  	if (orig_node)
7b36e8eef   Marek Lindner   batman-adv: Corre...
348
  		orig_node_free_ref(orig_node);
44524fcdf   Marek Lindner   batman-adv: Corre...
349
350
351
  	if (ret == 1)
  		kfree_skb(skb);
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
352
  }