|
@@ -290,6 +290,7 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
|
|
|
}
|
|
|
|
|
|
static void icmp_push_reply(struct icmp_bxm *icmp_param,
|
|
|
+ struct flowi4 *fl4,
|
|
|
struct ipcm_cookie *ipc, struct rtable **rt)
|
|
|
{
|
|
|
struct sock *sk;
|
|
@@ -315,7 +316,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
|
|
|
icmp_param->head_len, csum);
|
|
|
icmph->checksum = csum_fold(csum);
|
|
|
skb->ip_summed = CHECKSUM_NONE;
|
|
|
- ip_push_pending_frames(sk);
|
|
|
+ ip_push_pending_frames(sk, fl4);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -328,6 +329,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
|
|
struct ipcm_cookie ipc;
|
|
|
struct rtable *rt = skb_rtable(skb);
|
|
|
struct net *net = dev_net(rt->dst.dev);
|
|
|
+ struct flowi4 fl4;
|
|
|
struct sock *sk;
|
|
|
struct inet_sock *inet;
|
|
|
__be32 daddr;
|
|
@@ -351,57 +353,52 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
|
|
if (ipc.opt->opt.srr)
|
|
|
daddr = icmp_param->replyopts.opt.opt.faddr;
|
|
|
}
|
|
|
- {
|
|
|
- struct flowi4 fl4 = {
|
|
|
- .daddr = daddr,
|
|
|
- .saddr = rt->rt_spec_dst,
|
|
|
- .flowi4_tos = RT_TOS(ip_hdr(skb)->tos),
|
|
|
- .flowi4_proto = IPPROTO_ICMP,
|
|
|
- };
|
|
|
- security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
|
|
|
- rt = ip_route_output_key(net, &fl4);
|
|
|
- if (IS_ERR(rt))
|
|
|
- goto out_unlock;
|
|
|
- }
|
|
|
+ memset(&fl4, 0, sizeof(fl4));
|
|
|
+ fl4.daddr = daddr;
|
|
|
+ fl4.saddr = rt->rt_spec_dst;
|
|
|
+ fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
|
|
|
+ fl4.flowi4_proto = IPPROTO_ICMP;
|
|
|
+ security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
|
|
|
+ rt = ip_route_output_key(net, &fl4);
|
|
|
+ if (IS_ERR(rt))
|
|
|
+ goto out_unlock;
|
|
|
if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type,
|
|
|
icmp_param->data.icmph.code))
|
|
|
- icmp_push_reply(icmp_param, &ipc, &rt);
|
|
|
+ icmp_push_reply(icmp_param, &fl4, &ipc, &rt);
|
|
|
ip_rt_put(rt);
|
|
|
out_unlock:
|
|
|
icmp_xmit_unlock(sk);
|
|
|
}
|
|
|
|
|
|
-static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
|
|
|
+static struct rtable *icmp_route_lookup(struct net *net,
|
|
|
+ struct flowi4 *fl4,
|
|
|
+ struct sk_buff *skb_in,
|
|
|
const struct iphdr *iph,
|
|
|
__be32 saddr, u8 tos,
|
|
|
int type, int code,
|
|
|
struct icmp_bxm *param)
|
|
|
{
|
|
|
- struct flowi4 fl4 = {
|
|
|
- .daddr = (param->replyopts.opt.opt.srr ?
|
|
|
- param->replyopts.opt.opt.faddr : iph->saddr),
|
|
|
- .saddr = saddr,
|
|
|
- .flowi4_tos = RT_TOS(tos),
|
|
|
- .flowi4_proto = IPPROTO_ICMP,
|
|
|
- .fl4_icmp_type = type,
|
|
|
- .fl4_icmp_code = code,
|
|
|
- };
|
|
|
struct rtable *rt, *rt2;
|
|
|
int err;
|
|
|
|
|
|
- security_skb_classify_flow(skb_in, flowi4_to_flowi(&fl4));
|
|
|
- rt = __ip_route_output_key(net, &fl4);
|
|
|
+ memset(fl4, 0, sizeof(*fl4));
|
|
|
+ fl4->daddr = (param->replyopts.opt.opt.srr ?
|
|
|
+ param->replyopts.opt.opt.faddr : iph->saddr);
|
|
|
+ fl4->saddr = saddr;
|
|
|
+ fl4->flowi4_tos = RT_TOS(tos);
|
|
|
+ fl4->flowi4_proto = IPPROTO_ICMP;
|
|
|
+ fl4->fl4_icmp_type = type;
|
|
|
+ fl4->fl4_icmp_code = code;
|
|
|
+ security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4));
|
|
|
+ rt = __ip_route_output_key(net, fl4);
|
|
|
if (IS_ERR(rt))
|
|
|
return rt;
|
|
|
|
|
|
/* No need to clone since we're just using its address. */
|
|
|
rt2 = rt;
|
|
|
|
|
|
- if (!fl4.saddr)
|
|
|
- fl4.saddr = rt->rt_src;
|
|
|
-
|
|
|
rt = (struct rtable *) xfrm_lookup(net, &rt->dst,
|
|
|
- flowi4_to_flowi(&fl4), NULL, 0);
|
|
|
+ flowi4_to_flowi(fl4), NULL, 0);
|
|
|
if (!IS_ERR(rt)) {
|
|
|
if (rt != rt2)
|
|
|
return rt;
|
|
@@ -410,19 +407,19 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
|
|
|
} else
|
|
|
return rt;
|
|
|
|
|
|
- err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4), AF_INET);
|
|
|
+ err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(fl4), AF_INET);
|
|
|
if (err)
|
|
|
goto relookup_failed;
|
|
|
|
|
|
- if (inet_addr_type(net, fl4.saddr) == RTN_LOCAL) {
|
|
|
- rt2 = __ip_route_output_key(net, &fl4);
|
|
|
+ if (inet_addr_type(net, fl4->saddr) == RTN_LOCAL) {
|
|
|
+ rt2 = __ip_route_output_key(net, fl4);
|
|
|
if (IS_ERR(rt2))
|
|
|
err = PTR_ERR(rt2);
|
|
|
} else {
|
|
|
struct flowi4 fl4_2 = {};
|
|
|
unsigned long orefdst;
|
|
|
|
|
|
- fl4_2.daddr = fl4.saddr;
|
|
|
+ fl4_2.daddr = fl4->saddr;
|
|
|
rt2 = ip_route_output_key(net, &fl4_2);
|
|
|
if (IS_ERR(rt2)) {
|
|
|
err = PTR_ERR(rt2);
|
|
@@ -430,7 +427,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
|
|
|
}
|
|
|
/* Ugh! */
|
|
|
orefdst = skb_in->_skb_refdst; /* save old refdst */
|
|
|
- err = ip_route_input(skb_in, fl4.daddr, fl4.saddr,
|
|
|
+ err = ip_route_input(skb_in, fl4->daddr, fl4->saddr,
|
|
|
RT_TOS(tos), rt2->dst.dev);
|
|
|
|
|
|
dst_release(&rt2->dst);
|
|
@@ -442,7 +439,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
|
|
|
goto relookup_failed;
|
|
|
|
|
|
rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst,
|
|
|
- flowi4_to_flowi(&fl4), NULL,
|
|
|
+ flowi4_to_flowi(fl4), NULL,
|
|
|
XFRM_LOOKUP_ICMP);
|
|
|
if (!IS_ERR(rt2)) {
|
|
|
dst_release(&rt->dst);
|
|
@@ -481,6 +478,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
|
|
|
struct icmp_bxm icmp_param;
|
|
|
struct rtable *rt = skb_rtable(skb_in);
|
|
|
struct ipcm_cookie ipc;
|
|
|
+ struct flowi4 fl4;
|
|
|
__be32 saddr;
|
|
|
u8 tos;
|
|
|
struct net *net;
|
|
@@ -599,7 +597,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
|
|
|
ipc.opt = &icmp_param.replyopts.opt;
|
|
|
ipc.tx_flags = 0;
|
|
|
|
|
|
- rt = icmp_route_lookup(net, skb_in, iph, saddr, tos,
|
|
|
+ rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos,
|
|
|
type, code, &icmp_param);
|
|
|
if (IS_ERR(rt))
|
|
|
goto out_unlock;
|
|
@@ -620,7 +618,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
|
|
|
icmp_param.data_len = room;
|
|
|
icmp_param.head_len = sizeof(struct icmphdr);
|
|
|
|
|
|
- icmp_push_reply(&icmp_param, &ipc, &rt);
|
|
|
+ icmp_push_reply(&icmp_param, &fl4, &ipc, &rt);
|
|
|
ende:
|
|
|
ip_rt_put(rt);
|
|
|
out_unlock:
|