diff options
| -rw-r--r-- | include/net/route.h | 25 | ||||
| -rw-r--r-- | net/ipv4/icmp.c | 9 | ||||
| -rw-r--r-- | net/ipv4/igmp.c | 5 | ||||
| -rw-r--r-- | net/ipv4/ip_gre.c | 16 | ||||
| -rw-r--r-- | net/ipv4/ip_nat_dumb.c | 16 | ||||
| -rw-r--r-- | net/ipv4/ip_output.c | 15 | ||||
| -rw-r--r-- | net/ipv4/ipip.c | 11 | ||||
| -rw-r--r-- | net/ipv4/ipmr.c | 10 | ||||
| -rw-r--r-- | net/ipv4/raw.c | 5 | ||||
| -rw-r--r-- | net/ipv4/syncookies.c | 6 | ||||
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 44 | ||||
| -rw-r--r-- | net/ipv4/udp.c | 12 |
12 files changed, 123 insertions, 51 deletions
diff --git a/include/net/route.h b/include/net/route.h index 621b0c44b250..0a65f6a6b884 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -139,12 +139,16 @@ static inline char rt_tos2priority(u8 tos) return ip_tos2prio[IPTOS_TOS(tos)>>1]; } -static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif) +static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif, u8 protocol, u16 sport, u16 dport) { - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst, + struct flowi fl = { .oif = oif, + .nl_u = { .ip4_u = { .daddr = dst, .saddr = src, .tos = tos } }, - .oif = oif }; + .proto = protocol, + .uli_u = { .ports = + { .sport = sport, + .dport = dport } } }; int err; err = ip_route_output_key(rp, &fl); @@ -157,6 +161,21 @@ static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos return ip_route_output_key(rp, &fl); } +static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport) +{ + if (sport != (*rp)->fl.uli_u.ports.sport || + dport != (*rp)->fl.uli_u.ports.dport) { + struct flowi fl; + + memcpy(&fl, &(*rp)->fl, sizeof(fl)); + fl.uli_u.ports.sport = sport; + fl.uli_u.ports.dport = dport; + *rp = NULL; + return ip_route_output_key(rp, &fl); + } + return 0; +} + extern void rt_bind_peer(struct rtable *rt, int create); static inline struct inet_peer *rt_get_peer(struct rtable *rt) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index f9364605a729..b8d8ccd70578 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -428,7 +428,8 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) struct flowi fl = { .nl_u = { .ip4_u = { .daddr = daddr, .saddr = rt->rt_spec_dst, - .tos = RT_TOS(skb->nh.iph->tos) } } }; + .tos = RT_TOS(skb->nh.iph->tos) } }, + .proto = IPPROTO_ICMP }; if (ip_route_output_key(&rt, &fl)) goto out_unlock; } @@ -550,7 +551,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr, .saddr = saddr, - .tos = RT_TOS(tos) } } }; + .tos = RT_TOS(tos) } }, + .proto = IPPROTO_ICMP }; if (ip_route_output_key(&rt, &fl)) goto out_unlock; } @@ -577,7 +579,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) struct flowi fl = { .nl_u = { .ip4_u = { .daddr = icmp_param.replyopts.faddr, .saddr = saddr, - .tos = RT_TOS(tos) } } }; + .tos = RT_TOS(tos) } }, + .proto = IPPROTO_ICMP }; ip_rt_put(rt); if (ip_route_output_key(&rt, &fl)) goto out_unlock; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 661e65974e39..ba52c37b39ed 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -208,8 +208,9 @@ static int igmp_send_report(struct net_device *dev, u32 group, int type) dst = IGMP_ALL_ROUTER; { - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst } }, - .oif = dev->ifindex }; + struct flowi fl = { .oif = dev->ifindex, + .nl_u = { .ip4_u = { .daddr = dst } }, + .proto = IPPROTO_IGMP }; if (ip_route_output_key(&rt, &fl)) return -1; } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index f120e87b4cc3..1f2be777418d 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -492,6 +492,7 @@ out: memset(&fl, 0, sizeof(fl)); fl.fl4_dst = eiph->saddr; fl.fl4_tos = RT_TOS(eiph->tos); + fl.proto = IPPROTO_GRE; if (ip_route_output_key(&rt, &fl)) { kfree_skb(skb2); return; @@ -757,11 +758,12 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = tunnel->parms.link, + .nl_u = { .ip4_u = { .daddr = dst, .saddr = tiph->saddr, .tos = RT_TOS(tos) } }, - .oif = tunnel->parms.link }; + .proto = IPPROTO_GRE }; if (ip_route_output_key(&rt, &fl)) { tunnel->stat.tx_carrier_errors++; goto tx_error; @@ -1118,11 +1120,12 @@ static int ipgre_open(struct net_device *dev) MOD_INC_USE_COUNT; if (MULTICAST(t->parms.iph.daddr)) { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = t->parms.link, + .nl_u = { .ip4_u = { .daddr = t->parms.iph.daddr, .saddr = t->parms.iph.saddr, .tos = RT_TOS(t->parms.iph.tos) } }, - .oif = t->parms.link }; + .proto = IPPROTO_GRE }; struct rtable *rt; if (ip_route_output_key(&rt, &fl)) { MOD_DEC_USE_COUNT; @@ -1194,11 +1197,12 @@ static int ipgre_tunnel_init(struct net_device *dev) /* Guess output device to choose reasonable mtu and hard_header_len */ if (iph->daddr) { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = tunnel->parms.link, + .nl_u = { .ip4_u = { .daddr = iph->daddr, .saddr = iph->saddr, .tos = RT_TOS(iph->tos) } }, - .oif = tunnel->parms.link }; + .proto = IPPROTO_GRE }; struct rtable *rt; if (!ip_route_output_key(&rt, &fl)) { tdev = rt->u.dst.dev; diff --git a/net/ipv4/ip_nat_dumb.c b/net/ipv4/ip_nat_dumb.c index 58d1d3f4b8c9..b58b5e22d019 100644 --- a/net/ipv4/ip_nat_dumb.c +++ b/net/ipv4/ip_nat_dumb.c @@ -118,15 +118,17 @@ ip_do_nat(struct sk_buff *skb) if (ciph->daddr != osaddr) { struct fib_result res; unsigned flags = 0; - struct flowi fl = { .nl_u = - { .ip4_u = - { .daddr = ciph->saddr, - .saddr = ciph->daddr, + struct flowi fl = { + .iif = skb->dev->ifindex, + .nl_u = + { .ip4_u = + { .daddr = ciph->saddr, + .saddr = ciph->daddr, #ifdef CONFIG_IP_ROUTE_TOS - .tos = RT_TOS(ciph->tos) + .tos = RT_TOS(ciph->tos) #endif - } }, - .iif = skb->dev->ifindex }; + } }, + .proto = ciph->protocol }; /* Use fib_lookup() until we get our own * hash table of NATed hosts -- Rani diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ee01b7d043c5..9b481e0aa4f6 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -306,15 +306,19 @@ int ip_queue_xmit(struct sk_buff *skb) daddr = opt->faddr; { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = sk->bound_dev_if, + .nl_u = { .ip4_u = { .daddr = daddr, .saddr = inet->saddr, .tos = RT_CONN_FLAGS(sk) } }, - .oif = sk->bound_dev_if }; + .proto = sk->protocol, + .uli_u = { .ports = + { .sport = inet->sport, + .dport = inet->dport } } }; /* If this fails, retransmit mechanism of transport layer will - * keep trying until route appears or the connection times itself - * out. + * keep trying until route appears or the connection times + * itself out. */ if (ip_route_output_key(&rt, &fl)) goto no_route; @@ -1206,7 +1210,8 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar struct flowi fl = { .nl_u = { .ip4_u = { .daddr = daddr, .saddr = rt->rt_spec_dst, - .tos = RT_TOS(skb->nh.iph->tos) } } }; + .tos = RT_TOS(skb->nh.iph->tos) } }, + .proto = sk->protocol }; if (ip_route_output_key(&rt, &fl)) return; } diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 1e6ed55c935a..26e76160f75a 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -421,6 +421,7 @@ out: memset(&fl, 0, sizeof(fl)); fl.fl4_daddr = eiph->saddr; fl.fl4_tos = RT_TOS(eiph->tos); + fl.proto = IPPROTO_IPIP; if (ip_route_output_key(&rt, &key)) { kfree_skb(skb2); return; @@ -568,11 +569,12 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = tunnel->parms.link, + .nl_u = { .ip4_u = { .daddr = dst, .saddr = tiph->saddr, .tos = RT_TOS(tos) } }, - .oif = tunnel->parms.link }; + .proto = IPPROTO_IPIP }; if (ip_route_output_key(&rt, &fl)) { tunnel->stat.tx_carrier_errors++; goto tx_error_icmp; @@ -836,11 +838,12 @@ static int ipip_tunnel_init(struct net_device *dev) ipip_tunnel_init_gen(dev); if (iph->daddr) { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = tunnel->parms.link, + .nl_u = { .ip4_u = { .daddr = iph->daddr, .saddr = iph->saddr, .tos = RT_TOS(iph->tos) } }, - .oif = tunnel->parms.link }; + .proto = IPPROTO_IPIP }; struct rtable *rt; if (!ip_route_output_key(&rt, &fl)) { tdev = rt->u.dst.dev; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index a5450b23ef8a..01060712123e 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1146,19 +1146,21 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, #endif if (vif->flags&VIFF_TUNNEL) { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = vif->link, + .nl_u = { .ip4_u = { .daddr = vif->remote, .saddr = vif->local, .tos = RT_TOS(iph->tos) } }, - .oif = vif->link }; + .proto = IPPROTO_IPIP }; if (ip_route_output_key(&rt, &fl)) return; encap = sizeof(struct iphdr); } else { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = vif->link, + .nl_u = { .ip4_u = { .daddr = iph->daddr, .tos = RT_TOS(iph->tos) } }, - .oif = vif->link }; + .proto = IPPROTO_IPIP }; if (ip_route_output_key(&rt, &fl)) return; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 02179296ae54..0bcc94b16dbe 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -420,11 +420,12 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = ipc.oif, + .nl_u = { .ip4_u = { .daddr = daddr, .saddr = saddr, .tos = tos } }, - .oif = ipc.oif }; + .proto = IPPROTO_RAW }; err = ip_route_output_key(&rt, &fl); } if (err) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index b6de66f262af..066989423869 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -177,7 +177,11 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, opt->faddr : req->af.v4_req.rmt_addr), .saddr = req->af.v4_req.loc_addr, - .tos = RT_CONN_FLAGS(sk) } } }; + .tos = RT_CONN_FLAGS(sk) } }, + .proto = IPPROTO_TCP, + .uli_u = { .ports = + { .sport = skb->h.th->dest, + .dport = skb->h.th->source } } }; if (ip_route_output_key(&rt, &fl)) { tcp_openreq_free(req); goto out; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1e38c064b554..a05d2d19c04f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -770,7 +770,9 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) } tmp = ip_route_connect(&rt, nexthop, inet->saddr, - RT_CONN_FLAGS(sk), sk->bound_dev_if); + RT_CONN_FLAGS(sk), sk->bound_dev_if, + IPPROTO_TCP, + inet->sport, usin->sin_port); if (tmp < 0) return tmp; @@ -779,10 +781,6 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return -ENETUNREACH; } - __sk_dst_set(sk, &rt->u.dst); - tcp_v4_setup_caps(sk, &rt->u.dst); - tp->ext_header_len += rt->u.dst.header_len; - if (!inet->opt || !inet->opt->srr) daddr = rt->rt_dst; @@ -831,6 +829,19 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err) goto failure; + err = ip_route_newports(&rt, inet->sport, inet->dport); + if (err) + goto failure; + + /* OK, now commit destination to socket. */ + __sk_dst_set(sk, &rt->u.dst); + tcp_v4_setup_caps(sk, &rt->u.dst); + + /* DAVEM REDPEN: This used to sit above forced ext_header_len = 0 + * above, it was real bug. Is this one correct? + */ + tp->ext_header_len += rt->u.dst.header_len; + if (!tp->write_seq) tp->write_seq = secure_tcp_sequence_number(inet->saddr, inet->daddr, @@ -846,8 +857,9 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return 0; failure: + /* This unhashes the socket and releases the local port, if necessary. */ tcp_set_state(sk, TCP_CLOSE); - __sk_dst_reset(sk); + ip_rt_put(rt); sk->route_caps = 0; inet->dport = 0; return err; @@ -1265,13 +1277,17 @@ static struct dst_entry* tcp_v4_route_req(struct sock *sk, { struct rtable *rt; struct ip_options *opt = req->af.v4_req.opt; - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = sk->bound_dev_if, + .nl_u = { .ip4_u = { .daddr = ((opt && opt->srr) ? opt->faddr : req->af.v4_req.rmt_addr), .saddr = req->af.v4_req.loc_addr, .tos = RT_CONN_FLAGS(sk) } }, - .oif = sk->bound_dev_if }; + .proto = IPPROTO_TCP, + .uli_u = { .ports = + { .sport = inet_sk(sk)->sport, + .dport = req->rmt_port } } }; if (ip_route_output_key(&rt, &fl)) { IP_INC_STATS_BH(IpOutNoRoutes); @@ -1864,7 +1880,9 @@ static int tcp_v4_reselect_saddr(struct sock *sk) /* Query new route. */ err = ip_route_connect(&rt, daddr, 0, RT_TOS(inet->tos) | sk->localroute, - sk->bound_dev_if); + sk->bound_dev_if, + IPPROTO_TCP, + inet->sport, inet->dport); if (err) return err; @@ -1914,11 +1932,15 @@ int tcp_v4_rebuild_header(struct sock *sk) daddr = inet->opt->faddr; { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = sk->bound_dev_if, + .nl_u = { .ip4_u = { .daddr = daddr, .saddr = inet->saddr, .tos = RT_CONN_FLAGS(sk) } }, - .oif = sk->bound_dev_if }; + .proto = IPPROTO_TCP, + .uli_u = { .ports = + { .sport = inet->sport, + .dport = inet->dport } } }; err = ip_route_output_key(&rt, &fl); } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 56118cd694ab..ac7bb2851dc7 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -586,11 +586,15 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, rt = (struct rtable*)sk_dst_check(sk, 0); if (rt == NULL) { - struct flowi fl = { .nl_u = { .ip4_u = + struct flowi fl = { .oif = ipc.oif, + .nl_u = { .ip4_u = { .daddr = faddr, .saddr = saddr, .tos = tos } }, - .oif = ipc.oif }; + .proto = IPPROTO_UDP, + .uli_u = { .ports = + { .sport = inet->sport, + .dport = dport } } }; err = ip_route_output_key(&rt, &fl); if (err) goto out; @@ -872,7 +876,9 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) saddr = inet->mc_addr; } err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr, - RT_CONN_FLAGS(sk), oif); + RT_CONN_FLAGS(sk), oif, + IPPROTO_UDP, + inet->sport, usin->sin_port); if (err) return err; if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) { |
