diff options
Diffstat (limited to 'net/ipv4/af_inet.c')
-rw-r--r-- | net/ipv4/af_inet.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 9e83d7773d8f..7137e6420d66 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -951,6 +951,119 @@ void inet_unregister_protosw(struct inet_protosw *p) | |||
951 | } | 951 | } |
952 | } | 952 | } |
953 | 953 | ||
954 | /* | ||
955 | * Shall we try to damage output packets if routing dev changes? | ||
956 | */ | ||
957 | |||
958 | int sysctl_ip_dynaddr; | ||
959 | |||
960 | static int inet_sk_reselect_saddr(struct sock *sk) | ||
961 | { | ||
962 | struct inet_sock *inet = inet_sk(sk); | ||
963 | int err; | ||
964 | struct rtable *rt; | ||
965 | __u32 old_saddr = inet->saddr; | ||
966 | __u32 new_saddr; | ||
967 | __u32 daddr = inet->daddr; | ||
968 | |||
969 | if (inet->opt && inet->opt->srr) | ||
970 | daddr = inet->opt->faddr; | ||
971 | |||
972 | /* Query new route. */ | ||
973 | err = ip_route_connect(&rt, daddr, 0, | ||
974 | RT_CONN_FLAGS(sk), | ||
975 | sk->sk_bound_dev_if, | ||
976 | sk->sk_protocol, | ||
977 | inet->sport, inet->dport, sk); | ||
978 | if (err) | ||
979 | return err; | ||
980 | |||
981 | sk_setup_caps(sk, &rt->u.dst); | ||
982 | |||
983 | new_saddr = rt->rt_src; | ||
984 | |||
985 | if (new_saddr == old_saddr) | ||
986 | return 0; | ||
987 | |||
988 | if (sysctl_ip_dynaddr > 1) { | ||
989 | printk(KERN_INFO "%s(): shifting inet->" | ||
990 | "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n", | ||
991 | __FUNCTION__, | ||
992 | NIPQUAD(old_saddr), | ||
993 | NIPQUAD(new_saddr)); | ||
994 | } | ||
995 | |||
996 | inet->saddr = inet->rcv_saddr = new_saddr; | ||
997 | |||
998 | /* | ||
999 | * XXX The only one ugly spot where we need to | ||
1000 | * XXX really change the sockets identity after | ||
1001 | * XXX it has entered the hashes. -DaveM | ||
1002 | * | ||
1003 | * Besides that, it does not check for connection | ||
1004 | * uniqueness. Wait for troubles. | ||
1005 | */ | ||
1006 | __sk_prot_rehash(sk); | ||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
1010 | int inet_sk_rebuild_header(struct sock *sk) | ||
1011 | { | ||
1012 | struct inet_sock *inet = inet_sk(sk); | ||
1013 | struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0); | ||
1014 | u32 daddr; | ||
1015 | int err; | ||
1016 | |||
1017 | /* Route is OK, nothing to do. */ | ||
1018 | if (rt) | ||
1019 | return 0; | ||
1020 | |||
1021 | /* Reroute. */ | ||
1022 | daddr = inet->daddr; | ||
1023 | if (inet->opt && inet->opt->srr) | ||
1024 | daddr = inet->opt->faddr; | ||
1025 | { | ||
1026 | struct flowi fl = { | ||
1027 | .oif = sk->sk_bound_dev_if, | ||
1028 | .nl_u = { | ||
1029 | .ip4_u = { | ||
1030 | .daddr = daddr, | ||
1031 | .saddr = inet->saddr, | ||
1032 | .tos = RT_CONN_FLAGS(sk), | ||
1033 | }, | ||
1034 | }, | ||
1035 | .proto = sk->sk_protocol, | ||
1036 | .uli_u = { | ||
1037 | .ports = { | ||
1038 | .sport = inet->sport, | ||
1039 | .dport = inet->dport, | ||
1040 | }, | ||
1041 | }, | ||
1042 | }; | ||
1043 | |||
1044 | err = ip_route_output_flow(&rt, &fl, sk, 0); | ||
1045 | } | ||
1046 | if (!err) | ||
1047 | sk_setup_caps(sk, &rt->u.dst); | ||
1048 | else { | ||
1049 | /* Routing failed... */ | ||
1050 | sk->sk_route_caps = 0; | ||
1051 | /* | ||
1052 | * Other protocols have to map its equivalent state to TCP_SYN_SENT. | ||
1053 | * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme | ||
1054 | */ | ||
1055 | if (!sysctl_ip_dynaddr || | ||
1056 | sk->sk_state != TCP_SYN_SENT || | ||
1057 | (sk->sk_userlocks & SOCK_BINDADDR_LOCK) || | ||
1058 | (err = inet_sk_reselect_saddr(sk)) != 0) | ||
1059 | sk->sk_err_soft = -err; | ||
1060 | } | ||
1061 | |||
1062 | return err; | ||
1063 | } | ||
1064 | |||
1065 | EXPORT_SYMBOL(inet_sk_rebuild_header); | ||
1066 | |||
954 | #ifdef CONFIG_IP_MULTICAST | 1067 | #ifdef CONFIG_IP_MULTICAST |
955 | static struct net_protocol igmp_protocol = { | 1068 | static struct net_protocol igmp_protocol = { |
956 | .handler = igmp_rcv, | 1069 | .handler = igmp_rcv, |