aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/icmp.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-05-08 20:12:19 -0400
committerDavid S. Miller <davem@davemloft.net>2011-05-09 00:24:06 -0400
commit77968b78242ee25e2a4d759f0fca8dd52df6d479 (patch)
tree6de21f3a2efe49cb30ea8109fdfc79d30d6b27a3 /net/ipv4/icmp.c
parente474995f290ff7bc236b549aa9a89ae445ee5b1b (diff)
ipv4: Pass flow keys down into datagram packet building engine.
This way ip_output.c no longer needs rt->rt_{src,dst}. We already have these keys sitting, ready and waiting, on the stack or in a socket structure. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/icmp.c')
-rw-r--r--net/ipv4/icmp.c74
1 files changed, 36 insertions, 38 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index cfeca3c2152d..be5cc8d04c00 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -290,6 +290,7 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
290} 290}
291 291
292static void icmp_push_reply(struct icmp_bxm *icmp_param, 292static void icmp_push_reply(struct icmp_bxm *icmp_param,
293 struct flowi4 *fl4,
293 struct ipcm_cookie *ipc, struct rtable **rt) 294 struct ipcm_cookie *ipc, struct rtable **rt)
294{ 295{
295 struct sock *sk; 296 struct sock *sk;
@@ -315,7 +316,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
315 icmp_param->head_len, csum); 316 icmp_param->head_len, csum);
316 icmph->checksum = csum_fold(csum); 317 icmph->checksum = csum_fold(csum);
317 skb->ip_summed = CHECKSUM_NONE; 318 skb->ip_summed = CHECKSUM_NONE;
318 ip_push_pending_frames(sk); 319 ip_push_pending_frames(sk, fl4);
319 } 320 }
320} 321}
321 322
@@ -328,6 +329,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
328 struct ipcm_cookie ipc; 329 struct ipcm_cookie ipc;
329 struct rtable *rt = skb_rtable(skb); 330 struct rtable *rt = skb_rtable(skb);
330 struct net *net = dev_net(rt->dst.dev); 331 struct net *net = dev_net(rt->dst.dev);
332 struct flowi4 fl4;
331 struct sock *sk; 333 struct sock *sk;
332 struct inet_sock *inet; 334 struct inet_sock *inet;
333 __be32 daddr; 335 __be32 daddr;
@@ -351,57 +353,52 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
351 if (ipc.opt->opt.srr) 353 if (ipc.opt->opt.srr)
352 daddr = icmp_param->replyopts.opt.opt.faddr; 354 daddr = icmp_param->replyopts.opt.opt.faddr;
353 } 355 }
354 { 356 memset(&fl4, 0, sizeof(fl4));
355 struct flowi4 fl4 = { 357 fl4.daddr = daddr;
356 .daddr = daddr, 358 fl4.saddr = rt->rt_spec_dst;
357 .saddr = rt->rt_spec_dst, 359 fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
358 .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), 360 fl4.flowi4_proto = IPPROTO_ICMP;
359 .flowi4_proto = IPPROTO_ICMP, 361 security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
360 }; 362 rt = ip_route_output_key(net, &fl4);
361 security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); 363 if (IS_ERR(rt))
362 rt = ip_route_output_key(net, &fl4); 364 goto out_unlock;
363 if (IS_ERR(rt))
364 goto out_unlock;
365 }
366 if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, 365 if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type,
367 icmp_param->data.icmph.code)) 366 icmp_param->data.icmph.code))
368 icmp_push_reply(icmp_param, &ipc, &rt); 367 icmp_push_reply(icmp_param, &fl4, &ipc, &rt);
369 ip_rt_put(rt); 368 ip_rt_put(rt);
370out_unlock: 369out_unlock:
371 icmp_xmit_unlock(sk); 370 icmp_xmit_unlock(sk);
372} 371}
373 372
374static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, 373static struct rtable *icmp_route_lookup(struct net *net,
374 struct flowi4 *fl4,
375 struct sk_buff *skb_in,
375 const struct iphdr *iph, 376 const struct iphdr *iph,
376 __be32 saddr, u8 tos, 377 __be32 saddr, u8 tos,
377 int type, int code, 378 int type, int code,
378 struct icmp_bxm *param) 379 struct icmp_bxm *param)
379{ 380{
380 struct flowi4 fl4 = {
381 .daddr = (param->replyopts.opt.opt.srr ?
382 param->replyopts.opt.opt.faddr : iph->saddr),
383 .saddr = saddr,
384 .flowi4_tos = RT_TOS(tos),
385 .flowi4_proto = IPPROTO_ICMP,
386 .fl4_icmp_type = type,
387 .fl4_icmp_code = code,
388 };
389 struct rtable *rt, *rt2; 381 struct rtable *rt, *rt2;
390 int err; 382 int err;
391 383
392 security_skb_classify_flow(skb_in, flowi4_to_flowi(&fl4)); 384 memset(fl4, 0, sizeof(*fl4));
393 rt = __ip_route_output_key(net, &fl4); 385 fl4->daddr = (param->replyopts.opt.opt.srr ?
386 param->replyopts.opt.opt.faddr : iph->saddr);
387 fl4->saddr = saddr;
388 fl4->flowi4_tos = RT_TOS(tos);
389 fl4->flowi4_proto = IPPROTO_ICMP;
390 fl4->fl4_icmp_type = type;
391 fl4->fl4_icmp_code = code;
392 security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4));
393 rt = __ip_route_output_key(net, fl4);
394 if (IS_ERR(rt)) 394 if (IS_ERR(rt))
395 return rt; 395 return rt;
396 396
397 /* No need to clone since we're just using its address. */ 397 /* No need to clone since we're just using its address. */
398 rt2 = rt; 398 rt2 = rt;
399 399
400 if (!fl4.saddr)
401 fl4.saddr = rt->rt_src;
402
403 rt = (struct rtable *) xfrm_lookup(net, &rt->dst, 400 rt = (struct rtable *) xfrm_lookup(net, &rt->dst,
404 flowi4_to_flowi(&fl4), NULL, 0); 401 flowi4_to_flowi(fl4), NULL, 0);
405 if (!IS_ERR(rt)) { 402 if (!IS_ERR(rt)) {
406 if (rt != rt2) 403 if (rt != rt2)
407 return rt; 404 return rt;
@@ -410,19 +407,19 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
410 } else 407 } else
411 return rt; 408 return rt;
412 409
413 err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4), AF_INET); 410 err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(fl4), AF_INET);
414 if (err) 411 if (err)
415 goto relookup_failed; 412 goto relookup_failed;
416 413
417 if (inet_addr_type(net, fl4.saddr) == RTN_LOCAL) { 414 if (inet_addr_type(net, fl4->saddr) == RTN_LOCAL) {
418 rt2 = __ip_route_output_key(net, &fl4); 415 rt2 = __ip_route_output_key(net, fl4);
419 if (IS_ERR(rt2)) 416 if (IS_ERR(rt2))
420 err = PTR_ERR(rt2); 417 err = PTR_ERR(rt2);
421 } else { 418 } else {
422 struct flowi4 fl4_2 = {}; 419 struct flowi4 fl4_2 = {};
423 unsigned long orefdst; 420 unsigned long orefdst;
424 421
425 fl4_2.daddr = fl4.saddr; 422 fl4_2.daddr = fl4->saddr;
426 rt2 = ip_route_output_key(net, &fl4_2); 423 rt2 = ip_route_output_key(net, &fl4_2);
427 if (IS_ERR(rt2)) { 424 if (IS_ERR(rt2)) {
428 err = PTR_ERR(rt2); 425 err = PTR_ERR(rt2);
@@ -430,7 +427,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
430 } 427 }
431 /* Ugh! */ 428 /* Ugh! */
432 orefdst = skb_in->_skb_refdst; /* save old refdst */ 429 orefdst = skb_in->_skb_refdst; /* save old refdst */
433 err = ip_route_input(skb_in, fl4.daddr, fl4.saddr, 430 err = ip_route_input(skb_in, fl4->daddr, fl4->saddr,
434 RT_TOS(tos), rt2->dst.dev); 431 RT_TOS(tos), rt2->dst.dev);
435 432
436 dst_release(&rt2->dst); 433 dst_release(&rt2->dst);
@@ -442,7 +439,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
442 goto relookup_failed; 439 goto relookup_failed;
443 440
444 rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst, 441 rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst,
445 flowi4_to_flowi(&fl4), NULL, 442 flowi4_to_flowi(fl4), NULL,
446 XFRM_LOOKUP_ICMP); 443 XFRM_LOOKUP_ICMP);
447 if (!IS_ERR(rt2)) { 444 if (!IS_ERR(rt2)) {
448 dst_release(&rt->dst); 445 dst_release(&rt->dst);
@@ -481,6 +478,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
481 struct icmp_bxm icmp_param; 478 struct icmp_bxm icmp_param;
482 struct rtable *rt = skb_rtable(skb_in); 479 struct rtable *rt = skb_rtable(skb_in);
483 struct ipcm_cookie ipc; 480 struct ipcm_cookie ipc;
481 struct flowi4 fl4;
484 __be32 saddr; 482 __be32 saddr;
485 u8 tos; 483 u8 tos;
486 struct net *net; 484 struct net *net;
@@ -599,7 +597,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
599 ipc.opt = &icmp_param.replyopts.opt; 597 ipc.opt = &icmp_param.replyopts.opt;
600 ipc.tx_flags = 0; 598 ipc.tx_flags = 0;
601 599
602 rt = icmp_route_lookup(net, skb_in, iph, saddr, tos, 600 rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos,
603 type, code, &icmp_param); 601 type, code, &icmp_param);
604 if (IS_ERR(rt)) 602 if (IS_ERR(rt))
605 goto out_unlock; 603 goto out_unlock;
@@ -620,7 +618,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
620 icmp_param.data_len = room; 618 icmp_param.data_len = room;
621 icmp_param.head_len = sizeof(struct icmphdr); 619 icmp_param.head_len = sizeof(struct icmphdr);
622 620
623 icmp_push_reply(&icmp_param, &ipc, &rt); 621 icmp_push_reply(&icmp_param, &fl4, &ipc, &rt);
624ende: 622ende:
625 ip_rt_put(rt); 623 ip_rt_put(rt);
626out_unlock: 624out_unlock: