diff options
Diffstat (limited to 'net/ipv4/ip_output.c')
-rw-r--r-- | net/ipv4/ip_output.c | 158 |
1 files changed, 81 insertions, 77 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 459c011b1d4a..98af3697c718 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -140,14 +140,14 @@ static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst) | |||
140 | * | 140 | * |
141 | */ | 141 | */ |
142 | int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, | 142 | int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, |
143 | __be32 saddr, __be32 daddr, struct ip_options *opt) | 143 | __be32 saddr, __be32 daddr, struct ip_options_rcu *opt) |
144 | { | 144 | { |
145 | struct inet_sock *inet = inet_sk(sk); | 145 | struct inet_sock *inet = inet_sk(sk); |
146 | struct rtable *rt = skb_rtable(skb); | 146 | struct rtable *rt = skb_rtable(skb); |
147 | struct iphdr *iph; | 147 | struct iphdr *iph; |
148 | 148 | ||
149 | /* Build the IP header. */ | 149 | /* Build the IP header. */ |
150 | skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); | 150 | skb_push(skb, sizeof(struct iphdr) + (opt ? opt->opt.optlen : 0)); |
151 | skb_reset_network_header(skb); | 151 | skb_reset_network_header(skb); |
152 | iph = ip_hdr(skb); | 152 | iph = ip_hdr(skb); |
153 | iph->version = 4; | 153 | iph->version = 4; |
@@ -158,14 +158,14 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, | |||
158 | else | 158 | else |
159 | iph->frag_off = 0; | 159 | iph->frag_off = 0; |
160 | iph->ttl = ip_select_ttl(inet, &rt->dst); | 160 | iph->ttl = ip_select_ttl(inet, &rt->dst); |
161 | iph->daddr = rt->rt_dst; | 161 | iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr); |
162 | iph->saddr = rt->rt_src; | 162 | iph->saddr = saddr; |
163 | iph->protocol = sk->sk_protocol; | 163 | iph->protocol = sk->sk_protocol; |
164 | ip_select_ident(iph, &rt->dst, sk); | 164 | ip_select_ident(iph, &rt->dst, sk); |
165 | 165 | ||
166 | if (opt && opt->optlen) { | 166 | if (opt && opt->opt.optlen) { |
167 | iph->ihl += opt->optlen>>2; | 167 | iph->ihl += opt->opt.optlen>>2; |
168 | ip_options_build(skb, opt, daddr, rt, 0); | 168 | ip_options_build(skb, &opt->opt, daddr, rt, 0); |
169 | } | 169 | } |
170 | 170 | ||
171 | skb->priority = sk->sk_priority; | 171 | skb->priority = sk->sk_priority; |
@@ -312,11 +312,12 @@ int ip_output(struct sk_buff *skb) | |||
312 | !(IPCB(skb)->flags & IPSKB_REROUTED)); | 312 | !(IPCB(skb)->flags & IPSKB_REROUTED)); |
313 | } | 313 | } |
314 | 314 | ||
315 | int ip_queue_xmit(struct sk_buff *skb) | 315 | int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl) |
316 | { | 316 | { |
317 | struct sock *sk = skb->sk; | 317 | struct sock *sk = skb->sk; |
318 | struct inet_sock *inet = inet_sk(sk); | 318 | struct inet_sock *inet = inet_sk(sk); |
319 | struct ip_options *opt = inet->opt; | 319 | struct ip_options_rcu *inet_opt; |
320 | struct flowi4 *fl4; | ||
320 | struct rtable *rt; | 321 | struct rtable *rt; |
321 | struct iphdr *iph; | 322 | struct iphdr *iph; |
322 | int res; | 323 | int res; |
@@ -325,6 +326,8 @@ int ip_queue_xmit(struct sk_buff *skb) | |||
325 | * f.e. by something like SCTP. | 326 | * f.e. by something like SCTP. |
326 | */ | 327 | */ |
327 | rcu_read_lock(); | 328 | rcu_read_lock(); |
329 | inet_opt = rcu_dereference(inet->inet_opt); | ||
330 | fl4 = &fl->u.ip4; | ||
328 | rt = skb_rtable(skb); | 331 | rt = skb_rtable(skb); |
329 | if (rt != NULL) | 332 | if (rt != NULL) |
330 | goto packet_routed; | 333 | goto packet_routed; |
@@ -336,14 +339,14 @@ int ip_queue_xmit(struct sk_buff *skb) | |||
336 | 339 | ||
337 | /* Use correct destination address if we have options. */ | 340 | /* Use correct destination address if we have options. */ |
338 | daddr = inet->inet_daddr; | 341 | daddr = inet->inet_daddr; |
339 | if(opt && opt->srr) | 342 | if (inet_opt && inet_opt->opt.srr) |
340 | daddr = opt->faddr; | 343 | daddr = inet_opt->opt.faddr; |
341 | 344 | ||
342 | /* If this fails, retransmit mechanism of transport layer will | 345 | /* If this fails, retransmit mechanism of transport layer will |
343 | * keep trying until route appears or the connection times | 346 | * keep trying until route appears or the connection times |
344 | * itself out. | 347 | * itself out. |
345 | */ | 348 | */ |
346 | rt = ip_route_output_ports(sock_net(sk), sk, | 349 | rt = ip_route_output_ports(sock_net(sk), fl4, sk, |
347 | daddr, inet->inet_saddr, | 350 | daddr, inet->inet_saddr, |
348 | inet->inet_dport, | 351 | inet->inet_dport, |
349 | inet->inet_sport, | 352 | inet->inet_sport, |
@@ -357,11 +360,11 @@ int ip_queue_xmit(struct sk_buff *skb) | |||
357 | skb_dst_set_noref(skb, &rt->dst); | 360 | skb_dst_set_noref(skb, &rt->dst); |
358 | 361 | ||
359 | packet_routed: | 362 | packet_routed: |
360 | if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) | 363 | if (inet_opt && inet_opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway) |
361 | goto no_route; | 364 | goto no_route; |
362 | 365 | ||
363 | /* OK, we know where to send it, allocate and build IP header. */ | 366 | /* OK, we know where to send it, allocate and build IP header. */ |
364 | skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0)); | 367 | skb_push(skb, sizeof(struct iphdr) + (inet_opt ? inet_opt->opt.optlen : 0)); |
365 | skb_reset_network_header(skb); | 368 | skb_reset_network_header(skb); |
366 | iph = ip_hdr(skb); | 369 | iph = ip_hdr(skb); |
367 | *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); | 370 | *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); |
@@ -371,13 +374,13 @@ packet_routed: | |||
371 | iph->frag_off = 0; | 374 | iph->frag_off = 0; |
372 | iph->ttl = ip_select_ttl(inet, &rt->dst); | 375 | iph->ttl = ip_select_ttl(inet, &rt->dst); |
373 | iph->protocol = sk->sk_protocol; | 376 | iph->protocol = sk->sk_protocol; |
374 | iph->saddr = rt->rt_src; | 377 | iph->saddr = fl4->saddr; |
375 | iph->daddr = rt->rt_dst; | 378 | iph->daddr = fl4->daddr; |
376 | /* Transport layer set skb->h.foo itself. */ | 379 | /* Transport layer set skb->h.foo itself. */ |
377 | 380 | ||
378 | if (opt && opt->optlen) { | 381 | if (inet_opt && inet_opt->opt.optlen) { |
379 | iph->ihl += opt->optlen >> 2; | 382 | iph->ihl += inet_opt->opt.optlen >> 2; |
380 | ip_options_build(skb, opt, inet->inet_daddr, rt, 0); | 383 | ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0); |
381 | } | 384 | } |
382 | 385 | ||
383 | ip_select_ident_more(iph, &rt->dst, sk, | 386 | ip_select_ident_more(iph, &rt->dst, sk, |
@@ -773,7 +776,9 @@ static inline int ip_ufo_append_data(struct sock *sk, | |||
773 | (length - transhdrlen)); | 776 | (length - transhdrlen)); |
774 | } | 777 | } |
775 | 778 | ||
776 | static int __ip_append_data(struct sock *sk, struct sk_buff_head *queue, | 779 | static int __ip_append_data(struct sock *sk, |
780 | struct flowi4 *fl4, | ||
781 | struct sk_buff_head *queue, | ||
777 | struct inet_cork *cork, | 782 | struct inet_cork *cork, |
778 | int getfrag(void *from, char *to, int offset, | 783 | int getfrag(void *from, char *to, int offset, |
779 | int len, int odd, struct sk_buff *skb), | 784 | int len, int odd, struct sk_buff *skb), |
@@ -805,7 +810,7 @@ static int __ip_append_data(struct sock *sk, struct sk_buff_head *queue, | |||
805 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; | 810 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; |
806 | 811 | ||
807 | if (cork->length + length > 0xFFFF - fragheaderlen) { | 812 | if (cork->length + length > 0xFFFF - fragheaderlen) { |
808 | ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, | 813 | ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, |
809 | mtu-exthdrlen); | 814 | mtu-exthdrlen); |
810 | return -EMSGSIZE; | 815 | return -EMSGSIZE; |
811 | } | 816 | } |
@@ -1033,7 +1038,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, | |||
1033 | struct ipcm_cookie *ipc, struct rtable **rtp) | 1038 | struct ipcm_cookie *ipc, struct rtable **rtp) |
1034 | { | 1039 | { |
1035 | struct inet_sock *inet = inet_sk(sk); | 1040 | struct inet_sock *inet = inet_sk(sk); |
1036 | struct ip_options *opt; | 1041 | struct ip_options_rcu *opt; |
1037 | struct rtable *rt; | 1042 | struct rtable *rt; |
1038 | 1043 | ||
1039 | /* | 1044 | /* |
@@ -1047,7 +1052,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, | |||
1047 | if (unlikely(cork->opt == NULL)) | 1052 | if (unlikely(cork->opt == NULL)) |
1048 | return -ENOBUFS; | 1053 | return -ENOBUFS; |
1049 | } | 1054 | } |
1050 | memcpy(cork->opt, opt, sizeof(struct ip_options) + opt->optlen); | 1055 | memcpy(cork->opt, &opt->opt, sizeof(struct ip_options) + opt->opt.optlen); |
1051 | cork->flags |= IPCORK_OPT; | 1056 | cork->flags |= IPCORK_OPT; |
1052 | cork->addr = ipc->addr; | 1057 | cork->addr = ipc->addr; |
1053 | } | 1058 | } |
@@ -1080,7 +1085,7 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, | |||
1080 | * | 1085 | * |
1081 | * LATER: length must be adjusted by pad at tail, when it is required. | 1086 | * LATER: length must be adjusted by pad at tail, when it is required. |
1082 | */ | 1087 | */ |
1083 | int ip_append_data(struct sock *sk, | 1088 | int ip_append_data(struct sock *sk, struct flowi4 *fl4, |
1084 | int getfrag(void *from, char *to, int offset, int len, | 1089 | int getfrag(void *from, char *to, int offset, int len, |
1085 | int odd, struct sk_buff *skb), | 1090 | int odd, struct sk_buff *skb), |
1086 | void *from, int length, int transhdrlen, | 1091 | void *from, int length, int transhdrlen, |
@@ -1094,24 +1099,25 @@ int ip_append_data(struct sock *sk, | |||
1094 | return 0; | 1099 | return 0; |
1095 | 1100 | ||
1096 | if (skb_queue_empty(&sk->sk_write_queue)) { | 1101 | if (skb_queue_empty(&sk->sk_write_queue)) { |
1097 | err = ip_setup_cork(sk, &inet->cork, ipc, rtp); | 1102 | err = ip_setup_cork(sk, &inet->cork.base, ipc, rtp); |
1098 | if (err) | 1103 | if (err) |
1099 | return err; | 1104 | return err; |
1100 | } else { | 1105 | } else { |
1101 | transhdrlen = 0; | 1106 | transhdrlen = 0; |
1102 | } | 1107 | } |
1103 | 1108 | ||
1104 | return __ip_append_data(sk, &sk->sk_write_queue, &inet->cork, getfrag, | 1109 | return __ip_append_data(sk, fl4, &sk->sk_write_queue, &inet->cork.base, getfrag, |
1105 | from, length, transhdrlen, flags); | 1110 | from, length, transhdrlen, flags); |
1106 | } | 1111 | } |
1107 | 1112 | ||
1108 | ssize_t ip_append_page(struct sock *sk, struct page *page, | 1113 | ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, |
1109 | int offset, size_t size, int flags) | 1114 | int offset, size_t size, int flags) |
1110 | { | 1115 | { |
1111 | struct inet_sock *inet = inet_sk(sk); | 1116 | struct inet_sock *inet = inet_sk(sk); |
1112 | struct sk_buff *skb; | 1117 | struct sk_buff *skb; |
1113 | struct rtable *rt; | 1118 | struct rtable *rt; |
1114 | struct ip_options *opt = NULL; | 1119 | struct ip_options *opt = NULL; |
1120 | struct inet_cork *cork; | ||
1115 | int hh_len; | 1121 | int hh_len; |
1116 | int mtu; | 1122 | int mtu; |
1117 | int len; | 1123 | int len; |
@@ -1127,28 +1133,29 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, | |||
1127 | if (skb_queue_empty(&sk->sk_write_queue)) | 1133 | if (skb_queue_empty(&sk->sk_write_queue)) |
1128 | return -EINVAL; | 1134 | return -EINVAL; |
1129 | 1135 | ||
1130 | rt = (struct rtable *)inet->cork.dst; | 1136 | cork = &inet->cork.base; |
1131 | if (inet->cork.flags & IPCORK_OPT) | 1137 | rt = (struct rtable *)cork->dst; |
1132 | opt = inet->cork.opt; | 1138 | if (cork->flags & IPCORK_OPT) |
1139 | opt = cork->opt; | ||
1133 | 1140 | ||
1134 | if (!(rt->dst.dev->features&NETIF_F_SG)) | 1141 | if (!(rt->dst.dev->features&NETIF_F_SG)) |
1135 | return -EOPNOTSUPP; | 1142 | return -EOPNOTSUPP; |
1136 | 1143 | ||
1137 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); | 1144 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); |
1138 | mtu = inet->cork.fragsize; | 1145 | mtu = cork->fragsize; |
1139 | 1146 | ||
1140 | fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0); | 1147 | fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0); |
1141 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; | 1148 | maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; |
1142 | 1149 | ||
1143 | if (inet->cork.length + size > 0xFFFF - fragheaderlen) { | 1150 | if (cork->length + size > 0xFFFF - fragheaderlen) { |
1144 | ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->inet_dport, mtu); | 1151 | ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, mtu); |
1145 | return -EMSGSIZE; | 1152 | return -EMSGSIZE; |
1146 | } | 1153 | } |
1147 | 1154 | ||
1148 | if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) | 1155 | if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) |
1149 | return -EINVAL; | 1156 | return -EINVAL; |
1150 | 1157 | ||
1151 | inet->cork.length += size; | 1158 | cork->length += size; |
1152 | if ((size + skb->len > mtu) && | 1159 | if ((size + skb->len > mtu) && |
1153 | (sk->sk_protocol == IPPROTO_UDP) && | 1160 | (sk->sk_protocol == IPPROTO_UDP) && |
1154 | (rt->dst.dev->features & NETIF_F_UFO)) { | 1161 | (rt->dst.dev->features & NETIF_F_UFO)) { |
@@ -1243,7 +1250,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, | |||
1243 | return 0; | 1250 | return 0; |
1244 | 1251 | ||
1245 | error: | 1252 | error: |
1246 | inet->cork.length -= size; | 1253 | cork->length -= size; |
1247 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); | 1254 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); |
1248 | return err; | 1255 | return err; |
1249 | } | 1256 | } |
@@ -1262,6 +1269,7 @@ static void ip_cork_release(struct inet_cork *cork) | |||
1262 | * and push them out. | 1269 | * and push them out. |
1263 | */ | 1270 | */ |
1264 | struct sk_buff *__ip_make_skb(struct sock *sk, | 1271 | struct sk_buff *__ip_make_skb(struct sock *sk, |
1272 | struct flowi4 *fl4, | ||
1265 | struct sk_buff_head *queue, | 1273 | struct sk_buff_head *queue, |
1266 | struct inet_cork *cork) | 1274 | struct inet_cork *cork) |
1267 | { | 1275 | { |
@@ -1319,17 +1327,18 @@ struct sk_buff *__ip_make_skb(struct sock *sk, | |||
1319 | iph = (struct iphdr *)skb->data; | 1327 | iph = (struct iphdr *)skb->data; |
1320 | iph->version = 4; | 1328 | iph->version = 4; |
1321 | iph->ihl = 5; | 1329 | iph->ihl = 5; |
1322 | if (opt) { | ||
1323 | iph->ihl += opt->optlen>>2; | ||
1324 | ip_options_build(skb, opt, cork->addr, rt, 0); | ||
1325 | } | ||
1326 | iph->tos = inet->tos; | 1330 | iph->tos = inet->tos; |
1327 | iph->frag_off = df; | 1331 | iph->frag_off = df; |
1328 | ip_select_ident(iph, &rt->dst, sk); | 1332 | ip_select_ident(iph, &rt->dst, sk); |
1329 | iph->ttl = ttl; | 1333 | iph->ttl = ttl; |
1330 | iph->protocol = sk->sk_protocol; | 1334 | iph->protocol = sk->sk_protocol; |
1331 | iph->saddr = rt->rt_src; | 1335 | iph->saddr = fl4->saddr; |
1332 | iph->daddr = rt->rt_dst; | 1336 | iph->daddr = fl4->daddr; |
1337 | |||
1338 | if (opt) { | ||
1339 | iph->ihl += opt->optlen>>2; | ||
1340 | ip_options_build(skb, opt, cork->addr, rt, 0); | ||
1341 | } | ||
1333 | 1342 | ||
1334 | skb->priority = sk->sk_priority; | 1343 | skb->priority = sk->sk_priority; |
1335 | skb->mark = sk->sk_mark; | 1344 | skb->mark = sk->sk_mark; |
@@ -1365,11 +1374,11 @@ int ip_send_skb(struct sk_buff *skb) | |||
1365 | return err; | 1374 | return err; |
1366 | } | 1375 | } |
1367 | 1376 | ||
1368 | int ip_push_pending_frames(struct sock *sk) | 1377 | int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4) |
1369 | { | 1378 | { |
1370 | struct sk_buff *skb; | 1379 | struct sk_buff *skb; |
1371 | 1380 | ||
1372 | skb = ip_finish_skb(sk); | 1381 | skb = ip_finish_skb(sk, fl4); |
1373 | if (!skb) | 1382 | if (!skb) |
1374 | return 0; | 1383 | return 0; |
1375 | 1384 | ||
@@ -1394,17 +1403,18 @@ static void __ip_flush_pending_frames(struct sock *sk, | |||
1394 | 1403 | ||
1395 | void ip_flush_pending_frames(struct sock *sk) | 1404 | void ip_flush_pending_frames(struct sock *sk) |
1396 | { | 1405 | { |
1397 | __ip_flush_pending_frames(sk, &sk->sk_write_queue, &inet_sk(sk)->cork); | 1406 | __ip_flush_pending_frames(sk, &sk->sk_write_queue, &inet_sk(sk)->cork.base); |
1398 | } | 1407 | } |
1399 | 1408 | ||
1400 | struct sk_buff *ip_make_skb(struct sock *sk, | 1409 | struct sk_buff *ip_make_skb(struct sock *sk, |
1410 | struct flowi4 *fl4, | ||
1401 | int getfrag(void *from, char *to, int offset, | 1411 | int getfrag(void *from, char *to, int offset, |
1402 | int len, int odd, struct sk_buff *skb), | 1412 | int len, int odd, struct sk_buff *skb), |
1403 | void *from, int length, int transhdrlen, | 1413 | void *from, int length, int transhdrlen, |
1404 | struct ipcm_cookie *ipc, struct rtable **rtp, | 1414 | struct ipcm_cookie *ipc, struct rtable **rtp, |
1405 | unsigned int flags) | 1415 | unsigned int flags) |
1406 | { | 1416 | { |
1407 | struct inet_cork cork = {}; | 1417 | struct inet_cork cork; |
1408 | struct sk_buff_head queue; | 1418 | struct sk_buff_head queue; |
1409 | int err; | 1419 | int err; |
1410 | 1420 | ||
@@ -1413,18 +1423,21 @@ struct sk_buff *ip_make_skb(struct sock *sk, | |||
1413 | 1423 | ||
1414 | __skb_queue_head_init(&queue); | 1424 | __skb_queue_head_init(&queue); |
1415 | 1425 | ||
1426 | cork.flags = 0; | ||
1427 | cork.addr = 0; | ||
1428 | cork.opt = NULL; | ||
1416 | err = ip_setup_cork(sk, &cork, ipc, rtp); | 1429 | err = ip_setup_cork(sk, &cork, ipc, rtp); |
1417 | if (err) | 1430 | if (err) |
1418 | return ERR_PTR(err); | 1431 | return ERR_PTR(err); |
1419 | 1432 | ||
1420 | err = __ip_append_data(sk, &queue, &cork, getfrag, | 1433 | err = __ip_append_data(sk, fl4, &queue, &cork, getfrag, |
1421 | from, length, transhdrlen, flags); | 1434 | from, length, transhdrlen, flags); |
1422 | if (err) { | 1435 | if (err) { |
1423 | __ip_flush_pending_frames(sk, &queue, &cork); | 1436 | __ip_flush_pending_frames(sk, &queue, &cork); |
1424 | return ERR_PTR(err); | 1437 | return ERR_PTR(err); |
1425 | } | 1438 | } |
1426 | 1439 | ||
1427 | return __ip_make_skb(sk, &queue, &cork); | 1440 | return __ip_make_skb(sk, fl4, &queue, &cork); |
1428 | } | 1441 | } |
1429 | 1442 | ||
1430 | /* | 1443 | /* |
@@ -1447,48 +1460,39 @@ static int ip_reply_glue_bits(void *dptr, char *to, int offset, | |||
1447 | * Should run single threaded per socket because it uses the sock | 1460 | * Should run single threaded per socket because it uses the sock |
1448 | * structure to pass arguments. | 1461 | * structure to pass arguments. |
1449 | */ | 1462 | */ |
1450 | void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg, | 1463 | void ip_send_reply(struct sock *sk, struct sk_buff *skb, __be32 daddr, |
1451 | unsigned int len) | 1464 | struct ip_reply_arg *arg, unsigned int len) |
1452 | { | 1465 | { |
1453 | struct inet_sock *inet = inet_sk(sk); | 1466 | struct inet_sock *inet = inet_sk(sk); |
1454 | struct { | 1467 | struct ip_options_data replyopts; |
1455 | struct ip_options opt; | ||
1456 | char data[40]; | ||
1457 | } replyopts; | ||
1458 | struct ipcm_cookie ipc; | 1468 | struct ipcm_cookie ipc; |
1459 | __be32 daddr; | 1469 | struct flowi4 fl4; |
1460 | struct rtable *rt = skb_rtable(skb); | 1470 | struct rtable *rt = skb_rtable(skb); |
1461 | 1471 | ||
1462 | if (ip_options_echo(&replyopts.opt, skb)) | 1472 | if (ip_options_echo(&replyopts.opt.opt, skb)) |
1463 | return; | 1473 | return; |
1464 | 1474 | ||
1465 | daddr = ipc.addr = rt->rt_src; | 1475 | ipc.addr = daddr; |
1466 | ipc.opt = NULL; | 1476 | ipc.opt = NULL; |
1467 | ipc.tx_flags = 0; | 1477 | ipc.tx_flags = 0; |
1468 | 1478 | ||
1469 | if (replyopts.opt.optlen) { | 1479 | if (replyopts.opt.opt.optlen) { |
1470 | ipc.opt = &replyopts.opt; | 1480 | ipc.opt = &replyopts.opt; |
1471 | 1481 | ||
1472 | if (ipc.opt->srr) | 1482 | if (replyopts.opt.opt.srr) |
1473 | daddr = replyopts.opt.faddr; | 1483 | daddr = replyopts.opt.opt.faddr; |
1474 | } | 1484 | } |
1475 | 1485 | ||
1476 | { | 1486 | flowi4_init_output(&fl4, arg->bound_dev_if, 0, |
1477 | struct flowi4 fl4 = { | 1487 | RT_TOS(ip_hdr(skb)->tos), |
1478 | .flowi4_oif = arg->bound_dev_if, | 1488 | RT_SCOPE_UNIVERSE, sk->sk_protocol, |
1479 | .daddr = daddr, | 1489 | ip_reply_arg_flowi_flags(arg), |
1480 | .saddr = rt->rt_spec_dst, | 1490 | daddr, rt->rt_spec_dst, |
1481 | .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), | 1491 | tcp_hdr(skb)->source, tcp_hdr(skb)->dest); |
1482 | .fl4_sport = tcp_hdr(skb)->dest, | 1492 | security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); |
1483 | .fl4_dport = tcp_hdr(skb)->source, | 1493 | rt = ip_route_output_key(sock_net(sk), &fl4); |
1484 | .flowi4_proto = sk->sk_protocol, | 1494 | if (IS_ERR(rt)) |
1485 | .flowi4_flags = ip_reply_arg_flowi_flags(arg), | 1495 | return; |
1486 | }; | ||
1487 | security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); | ||
1488 | rt = ip_route_output_key(sock_net(sk), &fl4); | ||
1489 | if (IS_ERR(rt)) | ||
1490 | return; | ||
1491 | } | ||
1492 | 1496 | ||
1493 | /* And let IP do all the hard work. | 1497 | /* And let IP do all the hard work. |
1494 | 1498 | ||
@@ -1501,7 +1505,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
1501 | sk->sk_priority = skb->priority; | 1505 | sk->sk_priority = skb->priority; |
1502 | sk->sk_protocol = ip_hdr(skb)->protocol; | 1506 | sk->sk_protocol = ip_hdr(skb)->protocol; |
1503 | sk->sk_bound_dev_if = arg->bound_dev_if; | 1507 | sk->sk_bound_dev_if = arg->bound_dev_if; |
1504 | ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0, | 1508 | ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base, len, 0, |
1505 | &ipc, &rt, MSG_DONTWAIT); | 1509 | &ipc, &rt, MSG_DONTWAIT); |
1506 | if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { | 1510 | if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { |
1507 | if (arg->csumoffset >= 0) | 1511 | if (arg->csumoffset >= 0) |
@@ -1509,7 +1513,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar | |||
1509 | arg->csumoffset) = csum_fold(csum_add(skb->csum, | 1513 | arg->csumoffset) = csum_fold(csum_add(skb->csum, |
1510 | arg->csum)); | 1514 | arg->csum)); |
1511 | skb->ip_summed = CHECKSUM_NONE; | 1515 | skb->ip_summed = CHECKSUM_NONE; |
1512 | ip_push_pending_frames(sk); | 1516 | ip_push_pending_frames(sk, &fl4); |
1513 | } | 1517 | } |
1514 | 1518 | ||
1515 | bh_unlock_sock(sk); | 1519 | bh_unlock_sock(sk); |