diff options
-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); |