aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/unicast.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-16 19:29:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-16 19:29:25 -0400
commit7a6362800cb7d1d618a697a650c7aaed3eb39320 (patch)
tree087f9bc6c13ef1fad4b392c5cf9325cd28fa8523 /net/batman-adv/unicast.c
parent6445ced8670f37cfc2c5e24a9de9b413dbfc788d (diff)
parentceda86a108671294052cbf51660097b6534672f5 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1480 commits) bonding: enable netpoll without checking link status xfrm: Refcount destination entry on xfrm_lookup net: introduce rx_handler results and logic around that bonding: get rid of IFF_SLAVE_INACTIVE netdev->priv_flag bonding: wrap slave state work net: get rid of multiple bond-related netdevice->priv_flags bonding: register slave pointer for rx_handler be2net: Bump up the version number be2net: Copyright notice change. Update to Emulex instead of ServerEngines e1000e: fix kconfig for crc32 dependency netfilter ebtables: fix xt_AUDIT to work with ebtables xen network backend driver bonding: Improve syslog message at device creation time bonding: Call netif_carrier_off after register_netdevice bonding: Incorrect TX queue offset net_sched: fix ip_tos2prio xfrm: fix __xfrm_route_forward() be2net: Fix UDP packet detected status in RX compl Phonet: fix aligned-mode pipe socket buffer header reserve netxen: support for GbE port settings ... Fix up conflicts in drivers/staging/brcm80211/brcmsmac/wl_mac80211.c with the staging updates.
Diffstat (limited to 'net/batman-adv/unicast.c')
-rw-r--r--net/batman-adv/unicast.c121
1 files changed, 60 insertions, 61 deletions
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index d1a611322549..19f84bd443af 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2010 B.A.T.M.A.N. contributors: 2 * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors:
3 * 3 *
4 * Andreas Langer 4 * Andreas Langer
5 * 5 *
@@ -39,8 +39,8 @@ static struct sk_buff *frag_merge_packet(struct list_head *head,
39 (struct unicast_frag_packet *)skb->data; 39 (struct unicast_frag_packet *)skb->data;
40 struct sk_buff *tmp_skb; 40 struct sk_buff *tmp_skb;
41 struct unicast_packet *unicast_packet; 41 struct unicast_packet *unicast_packet;
42 int hdr_len = sizeof(struct unicast_packet), 42 int hdr_len = sizeof(struct unicast_packet);
43 uni_diff = sizeof(struct unicast_frag_packet) - hdr_len; 43 int uni_diff = sizeof(struct unicast_frag_packet) - hdr_len;
44 44
45 /* set skb to the first part and tmp_skb to the second part */ 45 /* set skb to the first part and tmp_skb to the second part */
46 if (up->flags & UNI_FRAG_HEAD) { 46 if (up->flags & UNI_FRAG_HEAD) {
@@ -183,15 +183,10 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
183 (struct unicast_frag_packet *)skb->data; 183 (struct unicast_frag_packet *)skb->data;
184 184
185 *new_skb = NULL; 185 *new_skb = NULL;
186 spin_lock_bh(&bat_priv->orig_hash_lock);
187 orig_node = ((struct orig_node *)
188 hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
189 unicast_packet->orig));
190 186
191 if (!orig_node) { 187 orig_node = orig_hash_find(bat_priv, unicast_packet->orig);
192 pr_debug("couldn't find originator in orig_hash\n"); 188 if (!orig_node)
193 goto out; 189 goto out;
194 }
195 190
196 orig_node->last_frag_packet = jiffies; 191 orig_node->last_frag_packet = jiffies;
197 192
@@ -215,21 +210,24 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
215 /* if not, merge failed */ 210 /* if not, merge failed */
216 if (*new_skb) 211 if (*new_skb)
217 ret = NET_RX_SUCCESS; 212 ret = NET_RX_SUCCESS;
218out:
219 spin_unlock_bh(&bat_priv->orig_hash_lock);
220 213
214out:
215 if (orig_node)
216 orig_node_free_ref(orig_node);
221 return ret; 217 return ret;
222} 218}
223 219
224int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, 220int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
225 struct batman_if *batman_if, uint8_t dstaddr[]) 221 struct hard_iface *hard_iface, uint8_t dstaddr[])
226{ 222{
227 struct unicast_packet tmp_uc, *unicast_packet; 223 struct unicast_packet tmp_uc, *unicast_packet;
228 struct sk_buff *frag_skb; 224 struct sk_buff *frag_skb;
229 struct unicast_frag_packet *frag1, *frag2; 225 struct unicast_frag_packet *frag1, *frag2;
230 int uc_hdr_len = sizeof(struct unicast_packet); 226 int uc_hdr_len = sizeof(struct unicast_packet);
231 int ucf_hdr_len = sizeof(struct unicast_frag_packet); 227 int ucf_hdr_len = sizeof(struct unicast_frag_packet);
232 int data_len = skb->len; 228 int data_len = skb->len - uc_hdr_len;
229 int large_tail = 0;
230 uint16_t seqno;
233 231
234 if (!bat_priv->primary_if) 232 if (!bat_priv->primary_if)
235 goto dropped; 233 goto dropped;
@@ -237,10 +235,11 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
237 frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); 235 frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len);
238 if (!frag_skb) 236 if (!frag_skb)
239 goto dropped; 237 goto dropped;
238 skb_reserve(frag_skb, ucf_hdr_len);
240 239
241 unicast_packet = (struct unicast_packet *) skb->data; 240 unicast_packet = (struct unicast_packet *) skb->data;
242 memcpy(&tmp_uc, unicast_packet, uc_hdr_len); 241 memcpy(&tmp_uc, unicast_packet, uc_hdr_len);
243 skb_split(skb, frag_skb, data_len / 2); 242 skb_split(skb, frag_skb, data_len / 2 + uc_hdr_len);
244 243
245 if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 || 244 if (my_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 ||
246 my_skb_head_push(frag_skb, ucf_hdr_len) < 0) 245 my_skb_head_push(frag_skb, ucf_hdr_len) < 0)
@@ -258,16 +257,18 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
258 memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); 257 memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
259 memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); 258 memcpy(frag2, frag1, sizeof(struct unicast_frag_packet));
260 259
261 frag1->flags |= UNI_FRAG_HEAD; 260 if (data_len & 1)
262 frag2->flags &= ~UNI_FRAG_HEAD; 261 large_tail = UNI_FRAG_LARGETAIL;
262
263 frag1->flags = UNI_FRAG_HEAD | large_tail;
264 frag2->flags = large_tail;
263 265
264 frag1->seqno = htons((uint16_t)atomic_inc_return( 266 seqno = atomic_add_return(2, &hard_iface->frag_seqno);
265 &batman_if->frag_seqno)); 267 frag1->seqno = htons(seqno - 1);
266 frag2->seqno = htons((uint16_t)atomic_inc_return( 268 frag2->seqno = htons(seqno);
267 &batman_if->frag_seqno));
268 269
269 send_skb_packet(skb, batman_if, dstaddr); 270 send_skb_packet(skb, hard_iface, dstaddr);
270 send_skb_packet(frag_skb, batman_if, dstaddr); 271 send_skb_packet(frag_skb, hard_iface, dstaddr);
271 return NET_RX_SUCCESS; 272 return NET_RX_SUCCESS;
272 273
273drop_frag: 274drop_frag:
@@ -282,44 +283,36 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
282 struct ethhdr *ethhdr = (struct ethhdr *)skb->data; 283 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
283 struct unicast_packet *unicast_packet; 284 struct unicast_packet *unicast_packet;
284 struct orig_node *orig_node; 285 struct orig_node *orig_node;
285 struct batman_if *batman_if; 286 struct neigh_node *neigh_node;
286 struct neigh_node *router;
287 int data_len = skb->len; 287 int data_len = skb->len;
288 uint8_t dstaddr[6]; 288 int ret = 1;
289
290 spin_lock_bh(&bat_priv->orig_hash_lock);
291 289
292 /* get routing information */ 290 /* get routing information */
293 if (is_multicast_ether_addr(ethhdr->h_dest)) 291 if (is_multicast_ether_addr(ethhdr->h_dest)) {
294 orig_node = (struct orig_node *)gw_get_selected(bat_priv); 292 orig_node = (struct orig_node *)gw_get_selected(bat_priv);
295 else 293 if (orig_node)
296 orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, 294 goto find_router;
297 compare_orig, 295 }
298 choose_orig,
299 ethhdr->h_dest));
300
301 /* check for hna host */
302 if (!orig_node)
303 orig_node = transtable_search(bat_priv, ethhdr->h_dest);
304
305 router = find_router(bat_priv, orig_node, NULL);
306
307 if (!router)
308 goto unlock;
309 296
310 /* don't lock while sending the packets ... we therefore 297 /* check for hna host - increases orig_node refcount */
311 * copy the required data before sending */ 298 orig_node = transtable_search(bat_priv, ethhdr->h_dest);
312 299
313 batman_if = router->if_incoming; 300find_router:
314 memcpy(dstaddr, router->addr, ETH_ALEN); 301 /**
302 * find_router():
303 * - if orig_node is NULL it returns NULL
304 * - increases neigh_nodes refcount if found.
305 */
306 neigh_node = find_router(bat_priv, orig_node, NULL);
315 307
316 spin_unlock_bh(&bat_priv->orig_hash_lock); 308 if (!neigh_node)
309 goto out;
317 310
318 if (batman_if->if_status != IF_ACTIVE) 311 if (neigh_node->if_incoming->if_status != IF_ACTIVE)
319 goto dropped; 312 goto out;
320 313
321 if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) 314 if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0)
322 goto dropped; 315 goto out;
323 316
324 unicast_packet = (struct unicast_packet *)skb->data; 317 unicast_packet = (struct unicast_packet *)skb->data;
325 318
@@ -333,18 +326,24 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
333 326
334 if (atomic_read(&bat_priv->fragmentation) && 327 if (atomic_read(&bat_priv->fragmentation) &&
335 data_len + sizeof(struct unicast_packet) > 328 data_len + sizeof(struct unicast_packet) >
336 batman_if->net_dev->mtu) { 329 neigh_node->if_incoming->net_dev->mtu) {
337 /* send frag skb decreases ttl */ 330 /* send frag skb decreases ttl */
338 unicast_packet->ttl++; 331 unicast_packet->ttl++;
339 return frag_send_skb(skb, bat_priv, batman_if, 332 ret = frag_send_skb(skb, bat_priv,
340 dstaddr); 333 neigh_node->if_incoming, neigh_node->addr);
334 goto out;
341 } 335 }
342 send_skb_packet(skb, batman_if, dstaddr);
343 return 0;
344 336
345unlock: 337 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
346 spin_unlock_bh(&bat_priv->orig_hash_lock); 338 ret = 0;
347dropped: 339 goto out;
348 kfree_skb(skb); 340
349 return 1; 341out:
342 if (neigh_node)
343 neigh_node_free_ref(neigh_node);
344 if (orig_node)
345 orig_node_free_ref(orig_node);
346 if (ret == 1)
347 kfree_skb(skb);
348 return ret;
350} 349}