diff options
| author | David S. Miller <davem@davemloft.net> | 2011-05-08 20:12:19 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-05-09 00:24:06 -0400 |
| commit | 77968b78242ee25e2a4d759f0fca8dd52df6d479 (patch) | |
| tree | 6de21f3a2efe49cb30ea8109fdfc79d30d6b27a3 | |
| parent | e474995f290ff7bc236b549aa9a89ae445ee5b1b (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>
| -rw-r--r-- | include/net/ip.h | 8 | ||||
| -rw-r--r-- | net/ipv4/icmp.c | 74 | ||||
| -rw-r--r-- | net/ipv4/ip_output.c | 39 | ||||
| -rw-r--r-- | net/ipv4/raw.c | 59 | ||||
| -rw-r--r-- | net/ipv4/udp.c | 4 |
5 files changed, 91 insertions, 93 deletions
diff --git a/include/net/ip.h b/include/net/ip.h index acf8b7814c4e..a4253795c5c5 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
| @@ -117,12 +117,14 @@ extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int od | |||
| 117 | extern ssize_t ip_append_page(struct sock *sk, struct page *page, | 117 | extern ssize_t ip_append_page(struct sock *sk, struct page *page, |
| 118 | int offset, size_t size, int flags); | 118 | int offset, size_t size, int flags); |
| 119 | extern struct sk_buff *__ip_make_skb(struct sock *sk, | 119 | extern struct sk_buff *__ip_make_skb(struct sock *sk, |
| 120 | struct flowi4 *fl4, | ||
| 120 | struct sk_buff_head *queue, | 121 | struct sk_buff_head *queue, |
| 121 | struct inet_cork *cork); | 122 | struct inet_cork *cork); |
| 122 | extern int ip_send_skb(struct sk_buff *skb); | 123 | extern int ip_send_skb(struct sk_buff *skb); |
| 123 | extern int ip_push_pending_frames(struct sock *sk); | 124 | extern int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4); |
| 124 | extern void ip_flush_pending_frames(struct sock *sk); | 125 | extern void ip_flush_pending_frames(struct sock *sk); |
| 125 | extern struct sk_buff *ip_make_skb(struct sock *sk, | 126 | extern struct sk_buff *ip_make_skb(struct sock *sk, |
| 127 | struct flowi4 *fl4, | ||
| 126 | int getfrag(void *from, char *to, int offset, int len, | 128 | int getfrag(void *from, char *to, int offset, int len, |
| 127 | int odd, struct sk_buff *skb), | 129 | int odd, struct sk_buff *skb), |
| 128 | void *from, int length, int transhdrlen, | 130 | void *from, int length, int transhdrlen, |
| @@ -130,9 +132,9 @@ extern struct sk_buff *ip_make_skb(struct sock *sk, | |||
| 130 | struct rtable **rtp, | 132 | struct rtable **rtp, |
| 131 | unsigned int flags); | 133 | unsigned int flags); |
| 132 | 134 | ||
| 133 | static inline struct sk_buff *ip_finish_skb(struct sock *sk) | 135 | static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4) |
| 134 | { | 136 | { |
| 135 | return __ip_make_skb(sk, &sk->sk_write_queue, &inet_sk(sk)->cork.base); | 137 | return __ip_make_skb(sk, fl4, &sk->sk_write_queue, &inet_sk(sk)->cork.base); |
| 136 | } | 138 | } |
| 137 | 139 | ||
| 138 | /* datagram.c */ | 140 | /* datagram.c */ |
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 | ||
| 292 | static void icmp_push_reply(struct icmp_bxm *icmp_param, | 292 | static 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); |
| 370 | out_unlock: | 369 | out_unlock: |
| 371 | icmp_xmit_unlock(sk); | 370 | icmp_xmit_unlock(sk); |
| 372 | } | 371 | } |
| 373 | 372 | ||
| 374 | static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in, | 373 | static 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); |
| 624 | ende: | 622 | ende: |
| 625 | ip_rt_put(rt); | 623 | ip_rt_put(rt); |
| 626 | out_unlock: | 624 | out_unlock: |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index b88ee5fdcbca..dca637b9d8ae 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
| @@ -1267,6 +1267,7 @@ static void ip_cork_release(struct inet_cork *cork) | |||
| 1267 | * and push them out. | 1267 | * and push them out. |
| 1268 | */ | 1268 | */ |
| 1269 | struct sk_buff *__ip_make_skb(struct sock *sk, | 1269 | struct sk_buff *__ip_make_skb(struct sock *sk, |
| 1270 | struct flowi4 *fl4, | ||
| 1270 | struct sk_buff_head *queue, | 1271 | struct sk_buff_head *queue, |
| 1271 | struct inet_cork *cork) | 1272 | struct inet_cork *cork) |
| 1272 | { | 1273 | { |
| @@ -1333,8 +1334,8 @@ struct sk_buff *__ip_make_skb(struct sock *sk, | |||
| 1333 | ip_select_ident(iph, &rt->dst, sk); | 1334 | ip_select_ident(iph, &rt->dst, sk); |
| 1334 | iph->ttl = ttl; | 1335 | iph->ttl = ttl; |
| 1335 | iph->protocol = sk->sk_protocol; | 1336 | iph->protocol = sk->sk_protocol; |
| 1336 | iph->saddr = rt->rt_src; | 1337 | iph->saddr = fl4->saddr; |
| 1337 | iph->daddr = rt->rt_dst; | 1338 | iph->daddr = fl4->daddr; |
| 1338 | 1339 | ||
| 1339 | skb->priority = sk->sk_priority; | 1340 | skb->priority = sk->sk_priority; |
| 1340 | skb->mark = sk->sk_mark; | 1341 | skb->mark = sk->sk_mark; |
| @@ -1370,11 +1371,11 @@ int ip_send_skb(struct sk_buff *skb) | |||
| 1370 | return err; | 1371 | return err; |
| 1371 | } | 1372 | } |
| 1372 | 1373 | ||
| 1373 | int ip_push_pending_frames(struct sock *sk) | 1374 | int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4) |
| 1374 | { | 1375 | { |
| 1375 | struct sk_buff *skb; | 1376 | struct sk_buff *skb; |
| 1376 | 1377 | ||
| 1377 | skb = ip_finish_skb(sk); | 1378 | skb = ip_finish_skb(sk, fl4); |
| 1378 | if (!skb) | 1379 | if (!skb) |
| 1379 | return 0; | 1380 | return 0; |
| 1380 | 1381 | ||
| @@ -1403,6 +1404,7 @@ void ip_flush_pending_frames(struct sock *sk) | |||
| 1403 | } | 1404 | } |
| 1404 | 1405 | ||
| 1405 | struct sk_buff *ip_make_skb(struct sock *sk, | 1406 | struct sk_buff *ip_make_skb(struct sock *sk, |
| 1407 | struct flowi4 *fl4, | ||
| 1406 | int getfrag(void *from, char *to, int offset, | 1408 | int getfrag(void *from, char *to, int offset, |
| 1407 | int len, int odd, struct sk_buff *skb), | 1409 | int len, int odd, struct sk_buff *skb), |
| 1408 | void *from, int length, int transhdrlen, | 1410 | void *from, int length, int transhdrlen, |
| @@ -1432,7 +1434,7 @@ struct sk_buff *ip_make_skb(struct sock *sk, | |||
| 1432 | return ERR_PTR(err); | 1434 | return ERR_PTR(err); |
| 1433 | } | 1435 | } |
| 1434 | 1436 | ||
| 1435 | return __ip_make_skb(sk, &queue, &cork); | 1437 | return __ip_make_skb(sk, fl4, &queue, &cork); |
| 1436 | } | 1438 | } |
| 1437 | 1439 | ||
| 1438 | /* | 1440 | /* |
| @@ -1461,6 +1463,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
| 1461 | struct inet_sock *inet = inet_sk(sk); | 1463 | struct inet_sock *inet = inet_sk(sk); |
| 1462 | struct ip_options_data replyopts; | 1464 | struct ip_options_data replyopts; |
| 1463 | struct ipcm_cookie ipc; | 1465 | struct ipcm_cookie ipc; |
| 1466 | struct flowi4 fl4; | ||
| 1464 | __be32 daddr; | 1467 | __be32 daddr; |
| 1465 | struct rtable *rt = skb_rtable(skb); | 1468 | struct rtable *rt = skb_rtable(skb); |
| 1466 | 1469 | ||
| @@ -1478,20 +1481,16 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
| 1478 | daddr = replyopts.opt.opt.faddr; | 1481 | daddr = replyopts.opt.opt.faddr; |
| 1479 | } | 1482 | } |
| 1480 | 1483 | ||
| 1481 | { | 1484 | flowi4_init_output(&fl4, arg->bound_dev_if, 0, |
| 1482 | struct flowi4 fl4; | 1485 | RT_TOS(ip_hdr(skb)->tos), |
| 1483 | 1486 | RT_SCOPE_UNIVERSE, sk->sk_protocol, | |
| 1484 | flowi4_init_output(&fl4, arg->bound_dev_if, 0, | 1487 | ip_reply_arg_flowi_flags(arg), |
| 1485 | RT_TOS(ip_hdr(skb)->tos), | 1488 | daddr, rt->rt_spec_dst, |
| 1486 | RT_SCOPE_UNIVERSE, sk->sk_protocol, | 1489 | tcp_hdr(skb)->source, tcp_hdr(skb)->dest); |
| 1487 | ip_reply_arg_flowi_flags(arg), | 1490 | security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); |
| 1488 | daddr, rt->rt_spec_dst, | 1491 | rt = ip_route_output_key(sock_net(sk), &fl4); |
| 1489 | tcp_hdr(skb)->source, tcp_hdr(skb)->dest); | 1492 | if (IS_ERR(rt)) |
| 1490 | security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); | 1493 | return; |
| 1491 | rt = ip_route_output_key(sock_net(sk), &fl4); | ||
| 1492 | if (IS_ERR(rt)) | ||
| 1493 | return; | ||
| 1494 | } | ||
| 1495 | 1494 | ||
| 1496 | /* And let IP do all the hard work. | 1495 | /* And let IP do all the hard work. |
| 1497 | 1496 | ||
| @@ -1512,7 +1511,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
| 1512 | arg->csumoffset) = csum_fold(csum_add(skb->csum, | 1511 | arg->csumoffset) = csum_fold(csum_add(skb->csum, |
| 1513 | arg->csum)); | 1512 | arg->csum)); |
| 1514 | skb->ip_summed = CHECKSUM_NONE; | 1513 | skb->ip_summed = CHECKSUM_NONE; |
| 1515 | ip_push_pending_frames(sk); | 1514 | ip_push_pending_frames(sk, &fl4); |
| 1516 | } | 1515 | } |
| 1517 | 1516 | ||
| 1518 | bh_unlock_sock(sk); | 1517 | bh_unlock_sock(sk); |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index a8659e0c4a6e..6fee91f656a9 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
| @@ -314,9 +314,10 @@ int raw_rcv(struct sock *sk, struct sk_buff *skb) | |||
| 314 | return 0; | 314 | return 0; |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, | 317 | static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, |
| 318 | struct rtable **rtp, | 318 | void *from, size_t length, |
| 319 | unsigned int flags) | 319 | struct rtable **rtp, |
| 320 | unsigned int flags) | ||
| 320 | { | 321 | { |
| 321 | struct inet_sock *inet = inet_sk(sk); | 322 | struct inet_sock *inet = inet_sk(sk); |
| 322 | struct net *net = sock_net(sk); | 323 | struct net *net = sock_net(sk); |
| @@ -327,7 +328,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, | |||
| 327 | struct rtable *rt = *rtp; | 328 | struct rtable *rt = *rtp; |
| 328 | 329 | ||
| 329 | if (length > rt->dst.dev->mtu) { | 330 | if (length > rt->dst.dev->mtu) { |
| 330 | ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, | 331 | ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, |
| 331 | rt->dst.dev->mtu); | 332 | rt->dst.dev->mtu); |
| 332 | return -EMSGSIZE; | 333 | return -EMSGSIZE; |
| 333 | } | 334 | } |
| @@ -372,7 +373,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, | |||
| 372 | 373 | ||
| 373 | if (iphlen >= sizeof(*iph)) { | 374 | if (iphlen >= sizeof(*iph)) { |
| 374 | if (!iph->saddr) | 375 | if (!iph->saddr) |
| 375 | iph->saddr = rt->rt_src; | 376 | iph->saddr = fl4->saddr; |
| 376 | iph->check = 0; | 377 | iph->check = 0; |
| 377 | iph->tot_len = htons(length); | 378 | iph->tot_len = htons(length); |
| 378 | if (!iph->id) | 379 | if (!iph->id) |
| @@ -455,6 +456,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 455 | struct inet_sock *inet = inet_sk(sk); | 456 | struct inet_sock *inet = inet_sk(sk); |
| 456 | struct ipcm_cookie ipc; | 457 | struct ipcm_cookie ipc; |
| 457 | struct rtable *rt = NULL; | 458 | struct rtable *rt = NULL; |
| 459 | struct flowi4 fl4; | ||
| 458 | int free = 0; | 460 | int free = 0; |
| 459 | __be32 daddr; | 461 | __be32 daddr; |
| 460 | __be32 saddr; | 462 | __be32 saddr; |
| @@ -558,27 +560,23 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 558 | saddr = inet->mc_addr; | 560 | saddr = inet->mc_addr; |
| 559 | } | 561 | } |
| 560 | 562 | ||
| 561 | { | 563 | flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, |
| 562 | struct flowi4 fl4; | 564 | RT_SCOPE_UNIVERSE, |
| 565 | inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, | ||
| 566 | FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0); | ||
| 563 | 567 | ||
| 564 | flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, | 568 | if (!inet->hdrincl) { |
| 565 | RT_SCOPE_UNIVERSE, | 569 | err = raw_probe_proto_opt(&fl4, msg); |
| 566 | inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, | 570 | if (err) |
| 567 | FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0); | ||
| 568 | |||
| 569 | if (!inet->hdrincl) { | ||
| 570 | err = raw_probe_proto_opt(&fl4, msg); | ||
| 571 | if (err) | ||
| 572 | goto done; | ||
| 573 | } | ||
| 574 | |||
| 575 | security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); | ||
| 576 | rt = ip_route_output_flow(sock_net(sk), &fl4, sk); | ||
| 577 | if (IS_ERR(rt)) { | ||
| 578 | err = PTR_ERR(rt); | ||
| 579 | rt = NULL; | ||
| 580 | goto done; | 571 | goto done; |
| 581 | } | 572 | } |
| 573 | |||
| 574 | security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); | ||
| 575 | rt = ip_route_output_flow(sock_net(sk), &fl4, sk); | ||
| 576 | if (IS_ERR(rt)) { | ||
| 577 | err = PTR_ERR(rt); | ||
| 578 | rt = NULL; | ||
| 579 | goto done; | ||
| 582 | } | 580 | } |
| 583 | 581 | ||
| 584 | err = -EACCES; | 582 | err = -EACCES; |
| @@ -590,19 +588,20 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
| 590 | back_from_confirm: | 588 | back_from_confirm: |
| 591 | 589 | ||
| 592 | if (inet->hdrincl) | 590 | if (inet->hdrincl) |
| 593 | err = raw_send_hdrinc(sk, msg->msg_iov, len, | 591 | err = raw_send_hdrinc(sk, &fl4, msg->msg_iov, len, |
| 594 | &rt, msg->msg_flags); | 592 | &rt, msg->msg_flags); |
| 595 | 593 | ||
| 596 | else { | 594 | else { |
| 597 | if (!ipc.addr) | 595 | if (!ipc.addr) |
| 598 | ipc.addr = rt->rt_dst; | 596 | ipc.addr = fl4.daddr; |
| 599 | lock_sock(sk); | 597 | lock_sock(sk); |
| 600 | err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0, | 598 | err = ip_append_data(sk, ip_generic_getfrag, |
| 601 | &ipc, &rt, msg->msg_flags); | 599 | msg->msg_iov, len, 0, |
| 600 | &ipc, &rt, msg->msg_flags); | ||
| 602 | if (err) | 601 | if (err) |
| 603 | ip_flush_pending_frames(sk); | 602 | ip_flush_pending_frames(sk); |
| 604 | else if (!(msg->msg_flags & MSG_MORE)) { | 603 | else if (!(msg->msg_flags & MSG_MORE)) { |
| 605 | err = ip_push_pending_frames(sk); | 604 | err = ip_push_pending_frames(sk, &fl4); |
| 606 | if (err == -ENOBUFS && !inet->recverr) | 605 | if (err == -ENOBUFS && !inet->recverr) |
| 607 | err = 0; | 606 | err = 0; |
| 608 | } | 607 | } |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ba9f137f5aa7..006e2ccd6cc2 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
| @@ -774,7 +774,7 @@ static int udp_push_pending_frames(struct sock *sk) | |||
| 774 | struct sk_buff *skb; | 774 | struct sk_buff *skb; |
| 775 | int err = 0; | 775 | int err = 0; |
| 776 | 776 | ||
| 777 | skb = ip_finish_skb(sk); | 777 | skb = ip_finish_skb(sk, fl4); |
| 778 | if (!skb) | 778 | if (!skb) |
| 779 | goto out; | 779 | goto out; |
| 780 | 780 | ||
| @@ -958,7 +958,7 @@ back_from_confirm: | |||
| 958 | 958 | ||
| 959 | /* Lockless fast path for the non-corking case. */ | 959 | /* Lockless fast path for the non-corking case. */ |
| 960 | if (!corkreq) { | 960 | if (!corkreq) { |
| 961 | skb = ip_make_skb(sk, getfrag, msg->msg_iov, ulen, | 961 | skb = ip_make_skb(sk, fl4, getfrag, msg->msg_iov, ulen, |
| 962 | sizeof(struct udphdr), &ipc, &rt, | 962 | sizeof(struct udphdr), &ipc, &rt, |
| 963 | msg->msg_flags); | 963 | msg->msg_flags); |
| 964 | err = PTR_ERR(skb); | 964 | err = PTR_ERR(skb); |
