unicast.c 9.4 KB
Newer Older
1
/* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors:
2 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
 *
 * 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"


32 33 34 35
static struct sk_buff *
batadv_frag_merge_packet(struct list_head *head,
			 struct frag_packet_list_entry *tfp,
			 struct sk_buff *skb)
36 37 38 39 40
{
	struct unicast_frag_packet *up =
		(struct unicast_frag_packet *)skb->data;
	struct sk_buff *tmp_skb;
	struct unicast_packet *unicast_packet;
41 42
	int hdr_len = sizeof(*unicast_packet);
	int uni_diff = sizeof(*up) - hdr_len;
43 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;
	}

52 53 54
	if (skb_linearize(skb) < 0 || skb_linearize(tmp_skb) < 0)
		goto err;

55
	skb_pull(tmp_skb, sizeof(*up));
56 57
	if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0)
		goto err;
58 59 60 61 62 63 64 65 66 67

	/* 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);
68
	unicast_packet = (struct unicast_packet *)skb_pull(skb, uni_diff);
69
	unicast_packet->header.packet_type = BAT_UNICAST;
70 71

	return skb;
72 73 74 75 76

err:
	/* free buffered skb, skb will be freed later */
	kfree_skb(tfp->skb);
	return NULL;
77 78
}

79 80
static void batadv_frag_create_entry(struct list_head *head,
				     struct sk_buff *skb)
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
{
	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;
}

96
static int batadv_frag_create_buffer(struct list_head *head)
97 98 99 100 101
{
	int i;
	struct frag_packet_list_entry *tfp;

	for (i = 0; i < FRAG_BUFFER_SIZE; i++) {
102
		tfp = kmalloc(sizeof(*tfp), GFP_ATOMIC);
103
		if (!tfp) {
104
			batadv_frag_list_free(head);
105 106 107 108 109 110 111 112 113 114 115
			return -ENOMEM;
		}
		tfp->skb = NULL;
		tfp->seqno = 0;
		INIT_LIST_HEAD(&tfp->list);
		list_add(&tfp->list, head);
	}

	return 0;
}

116 117 118
static struct frag_packet_list_entry *
batadv_frag_search_packet(struct list_head *head,
			  const struct unicast_frag_packet *up)
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
{
	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;
}

155
void batadv_frag_list_free(struct list_head *head)
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
{
	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)
 */
176 177
int batadv_frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
			       struct sk_buff **new_skb)
178 179 180 181 182 183 184 185 186
{
	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;

187
	orig_node = batadv_orig_hash_find(bat_priv, unicast_packet->orig);
188
	if (!orig_node)
189 190 191 192 193
		goto out;

	orig_node->last_frag_packet = jiffies;

	if (list_empty(&orig_node->frag_list) &&
194
	    batadv_frag_create_buffer(&orig_node->frag_list)) {
195 196 197 198
		pr_debug("couldn't create frag buffer\n");
		goto out;
	}

199 200
	tmp_frag_entry = batadv_frag_search_packet(&orig_node->frag_list,
						   unicast_packet);
201 202

	if (!tmp_frag_entry) {
203
		batadv_frag_create_entry(&orig_node->frag_list, skb);
204 205 206 207
		ret = NET_RX_SUCCESS;
		goto out;
	}

208 209
	*new_skb = batadv_frag_merge_packet(&orig_node->frag_list,
					    tmp_frag_entry, skb);
210 211 212 213
	/* if not, merge failed */
	if (*new_skb)
		ret = NET_RX_SUCCESS;

214 215
out:
	if (orig_node)
216
		batadv_orig_node_free_ref(orig_node);
217 218 219
	return ret;
}

220 221
int batadv_frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
			 struct hard_iface *hard_iface, const uint8_t dstaddr[])
222 223
{
	struct unicast_packet tmp_uc, *unicast_packet;
224
	struct hard_iface *primary_if;
225 226
	struct sk_buff *frag_skb;
	struct unicast_frag_packet *frag1, *frag2;
227 228
	int uc_hdr_len = sizeof(*unicast_packet);
	int ucf_hdr_len = sizeof(*frag1);
229
	int data_len = skb->len - uc_hdr_len;
230
	int large_tail = 0, ret = NET_RX_DROP;
231
	uint16_t seqno;
232

233
	primary_if = batadv_primary_if_get_selected(bat_priv);
234
	if (!primary_if)
235 236
		goto dropped;

237 238 239
	frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len);
	if (!frag_skb)
		goto dropped;
240
	skb_reserve(frag_skb, ucf_hdr_len);
241

242
	unicast_packet = (struct unicast_packet *)skb->data;
243
	memcpy(&tmp_uc, unicast_packet, uc_hdr_len);
244
	skb_split(skb, frag_skb, data_len / 2 + uc_hdr_len);
245

246 247
	if (batadv_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 ||
	    batadv_skb_head_push(frag_skb, ucf_hdr_len) < 0)
248 249 250 251 252
		goto drop_frag;

	frag1 = (struct unicast_frag_packet *)skb->data;
	frag2 = (struct unicast_frag_packet *)frag_skb->data;

253
	memcpy(frag1, &tmp_uc, sizeof(tmp_uc));
254

255
	frag1->header.ttl--;
256
	frag1->header.version = BATADV_COMPAT_VERSION;
257
	frag1->header.packet_type = BAT_UNICAST_FRAG;
258

259
	memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
260
	memcpy(frag2, frag1, sizeof(*frag2));
261

262 263 264 265 266
	if (data_len & 1)
		large_tail = UNI_FRAG_LARGETAIL;

	frag1->flags = UNI_FRAG_HEAD | large_tail;
	frag2->flags = large_tail;
267

268
	seqno = atomic_add_return(2, &hard_iface->frag_seqno);
269 270
	frag1->seqno = htons(seqno - 1);
	frag2->seqno = htons(seqno);
271

272 273
	batadv_send_skb_packet(skb, hard_iface, dstaddr);
	batadv_send_skb_packet(frag_skb, hard_iface, dstaddr);
274 275
	ret = NET_RX_SUCCESS;
	goto out;
276 277 278 279 280

drop_frag:
	kfree_skb(frag_skb);
dropped:
	kfree_skb(skb);
281 282
out:
	if (primary_if)
283
		batadv_hardif_free_ref(primary_if);
284
	return ret;
285 286
}

287
int batadv_unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
288 289 290
{
	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
	struct unicast_packet *unicast_packet;
291
	struct orig_node *orig_node;
292
	struct neigh_node *neigh_node;
293
	int data_len = skb->len;
294
	int ret = 1;
295 296

	/* get routing information */
297
	if (is_multicast_ether_addr(ethhdr->h_dest)) {
298
		orig_node = batadv_gw_get_selected_orig(bat_priv);
299
		if (orig_node)
300 301
			goto find_router;
	}
302

303
	/* check for tt host - increases orig_node refcount.
304 305
	 * returns NULL in case of AP isolation
	 */
306 307
	orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
					     ethhdr->h_dest);
308
find_router:
309
	/* find_router():
310 311 312
	 *  - if orig_node is NULL it returns NULL
	 *  - increases neigh_nodes refcount if found.
	 */
313
	neigh_node = batadv_find_router(bat_priv, orig_node, NULL);
314
	if (!neigh_node)
315
		goto out;
316

317
	if (batadv_skb_head_push(skb, sizeof(*unicast_packet)) < 0)
318
		goto out;
319 320 321

	unicast_packet = (struct unicast_packet *)skb->data;

322
	unicast_packet->header.version = BATADV_COMPAT_VERSION;
323
	/* batman packet type: unicast */
324
	unicast_packet->header.packet_type = BAT_UNICAST;
325
	/* set unicast ttl */
326
	unicast_packet->header.ttl = TTL;
327 328
	/* copy the destination for faster routing */
	memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
329 330 331
	/* set the destination tt version number */
	unicast_packet->ttvn =
		(uint8_t)atomic_read(&orig_node->last_ttvn);
332

333 334 335 336 337
	/* inform the destination node that we are still missing a correct route
	 * for this client. The destination will receive this packet and will
	 * try to reroute it because the ttvn contained in the header is less
	 * than the current one
	 */
338
	if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest))
339 340
		unicast_packet->ttvn = unicast_packet->ttvn - 1;

341
	if (atomic_read(&bat_priv->fragmentation) &&
342
	    data_len + sizeof(*unicast_packet) >
343
				neigh_node->if_incoming->net_dev->mtu) {
344
		/* send frag skb decreases ttl */
345
		unicast_packet->header.ttl++;
346 347 348
		ret = batadv_frag_send_skb(skb, bat_priv,
					   neigh_node->if_incoming,
					   neigh_node->addr);
349
		goto out;
350 351
	}

352
	batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
353 354
	ret = 0;
	goto out;
355

356 357
out:
	if (neigh_node)
358
		batadv_neigh_node_free_ref(neigh_node);
359
	if (orig_node)
360
		batadv_orig_node_free_ref(orig_node);
361 362 363
	if (ret == 1)
		kfree_skb(skb);
	return ret;
364
}