diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 19:29:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 19:29:25 -0400 |
commit | 7a6362800cb7d1d618a697a650c7aaed3eb39320 (patch) | |
tree | 087f9bc6c13ef1fad4b392c5cf9325cd28fa8523 /net/batman-adv/unicast.c | |
parent | 6445ced8670f37cfc2c5e24a9de9b413dbfc788d (diff) | |
parent | ceda86a108671294052cbf51660097b6534672f5 (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.c | 121 |
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; |
218 | out: | ||
219 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
220 | 213 | ||
214 | out: | ||
215 | if (orig_node) | ||
216 | orig_node_free_ref(orig_node); | ||
221 | return ret; | 217 | return ret; |
222 | } | 218 | } |
223 | 219 | ||
224 | int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | 220 | int 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 | ||
273 | drop_frag: | 274 | drop_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; | 300 | find_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 | ||
345 | unlock: | 337 | send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); |
346 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 338 | ret = 0; |
347 | dropped: | 339 | goto out; |
348 | kfree_skb(skb); | 340 | |
349 | return 1; | 341 | out: |
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 | } |