diff options
Diffstat (limited to 'net/ipv4/raw.c')
-rw-r--r-- | net/ipv4/raw.c | 59 |
1 files changed, 29 insertions, 30 deletions
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 | } |