diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 139 |
1 files changed, 40 insertions, 99 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 1941c5c888d3..13c65144a00a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -942,7 +942,8 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) | |||
942 | return 0; | 942 | return 0; |
943 | } | 943 | } |
944 | 944 | ||
945 | static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | 945 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, |
946 | u32 ts, struct tcp_md5sig_key *key, int rst) | ||
946 | { | 947 | { |
947 | struct tcphdr *th = tcp_hdr(skb), *t1; | 948 | struct tcphdr *th = tcp_hdr(skb), *t1; |
948 | struct sk_buff *buff; | 949 | struct sk_buff *buff; |
@@ -951,31 +952,14 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
951 | struct sock *ctl_sk = net->ipv6.tcp_sk; | 952 | struct sock *ctl_sk = net->ipv6.tcp_sk; |
952 | unsigned int tot_len = sizeof(struct tcphdr); | 953 | unsigned int tot_len = sizeof(struct tcphdr); |
953 | __be32 *topt; | 954 | __be32 *topt; |
954 | #ifdef CONFIG_TCP_MD5SIG | ||
955 | struct tcp_md5sig_key *key; | ||
956 | #endif | ||
957 | |||
958 | if (th->rst) | ||
959 | return; | ||
960 | |||
961 | if (!ipv6_unicast_destination(skb)) | ||
962 | return; | ||
963 | 955 | ||
956 | if (ts) | ||
957 | tot_len += TCPOLEN_TSTAMP_ALIGNED; | ||
964 | #ifdef CONFIG_TCP_MD5SIG | 958 | #ifdef CONFIG_TCP_MD5SIG |
965 | if (sk) | ||
966 | key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr); | ||
967 | else | ||
968 | key = NULL; | ||
969 | |||
970 | if (key) | 959 | if (key) |
971 | tot_len += TCPOLEN_MD5SIG_ALIGNED; | 960 | tot_len += TCPOLEN_MD5SIG_ALIGNED; |
972 | #endif | 961 | #endif |
973 | 962 | ||
974 | /* | ||
975 | * We need to grab some memory, and put together an RST, | ||
976 | * and then put it into the queue to be sent. | ||
977 | */ | ||
978 | |||
979 | buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, | 963 | buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, |
980 | GFP_ATOMIC); | 964 | GFP_ATOMIC); |
981 | if (buff == NULL) | 965 | if (buff == NULL) |
@@ -990,18 +974,21 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
990 | t1->dest = th->source; | 974 | t1->dest = th->source; |
991 | t1->source = th->dest; | 975 | t1->source = th->dest; |
992 | t1->doff = tot_len / 4; | 976 | t1->doff = tot_len / 4; |
993 | t1->rst = 1; | 977 | t1->seq = htonl(seq); |
994 | 978 | t1->ack_seq = htonl(ack); | |
995 | if(th->ack) { | 979 | t1->ack = !rst || !th->ack; |
996 | t1->seq = th->ack_seq; | 980 | t1->rst = rst; |
997 | } else { | 981 | t1->window = htons(win); |
998 | t1->ack = 1; | ||
999 | t1->ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin | ||
1000 | + skb->len - (th->doff<<2)); | ||
1001 | } | ||
1002 | 982 | ||
1003 | topt = (__be32 *)(t1 + 1); | 983 | topt = (__be32 *)(t1 + 1); |
1004 | 984 | ||
985 | if (ts) { | ||
986 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | ||
987 | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); | ||
988 | *topt++ = htonl(tcp_time_stamp); | ||
989 | *topt++ = htonl(ts); | ||
990 | } | ||
991 | |||
1005 | #ifdef CONFIG_TCP_MD5SIG | 992 | #ifdef CONFIG_TCP_MD5SIG |
1006 | if (key) { | 993 | if (key) { |
1007 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | 994 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | |
@@ -1036,7 +1023,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1036 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { | 1023 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { |
1037 | ip6_xmit(ctl_sk, buff, &fl, NULL, 0); | 1024 | ip6_xmit(ctl_sk, buff, &fl, NULL, 0); |
1038 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); | 1025 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); |
1039 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); | 1026 | if (rst) |
1027 | TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); | ||
1040 | return; | 1028 | return; |
1041 | } | 1029 | } |
1042 | } | 1030 | } |
@@ -1044,87 +1032,40 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
1044 | kfree_skb(buff); | 1032 | kfree_skb(buff); |
1045 | } | 1033 | } |
1046 | 1034 | ||
1047 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, | 1035 | static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) |
1048 | struct tcp_md5sig_key *key) | ||
1049 | { | 1036 | { |
1050 | struct tcphdr *th = tcp_hdr(skb), *t1; | 1037 | struct tcphdr *th = tcp_hdr(skb); |
1051 | struct sk_buff *buff; | 1038 | u32 seq = 0, ack_seq = 0; |
1052 | struct flowi fl; | ||
1053 | struct net *net = dev_net(skb->dst->dev); | ||
1054 | struct sock *ctl_sk = net->ipv6.tcp_sk; | ||
1055 | unsigned int tot_len = sizeof(struct tcphdr); | ||
1056 | __be32 *topt; | ||
1057 | |||
1058 | if (ts) | ||
1059 | tot_len += TCPOLEN_TSTAMP_ALIGNED; | ||
1060 | #ifdef CONFIG_TCP_MD5SIG | 1039 | #ifdef CONFIG_TCP_MD5SIG |
1061 | if (key) | 1040 | struct tcp_md5sig_key *key; |
1062 | tot_len += TCPOLEN_MD5SIG_ALIGNED; | ||
1063 | #endif | 1041 | #endif |
1064 | 1042 | ||
1065 | buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, | 1043 | if (th->rst) |
1066 | GFP_ATOMIC); | ||
1067 | if (buff == NULL) | ||
1068 | return; | 1044 | return; |
1069 | 1045 | ||
1070 | skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); | 1046 | if (!ipv6_unicast_destination(skb)) |
1071 | 1047 | return; | |
1072 | t1 = (struct tcphdr *) skb_push(buff, tot_len); | ||
1073 | |||
1074 | /* Swap the send and the receive. */ | ||
1075 | memset(t1, 0, sizeof(*t1)); | ||
1076 | t1->dest = th->source; | ||
1077 | t1->source = th->dest; | ||
1078 | t1->doff = tot_len / 4; | ||
1079 | t1->seq = htonl(seq); | ||
1080 | t1->ack_seq = htonl(ack); | ||
1081 | t1->ack = 1; | ||
1082 | t1->window = htons(win); | ||
1083 | |||
1084 | topt = (__be32 *)(t1 + 1); | ||
1085 | |||
1086 | if (ts) { | ||
1087 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | ||
1088 | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); | ||
1089 | *topt++ = htonl(tcp_time_stamp); | ||
1090 | *topt++ = htonl(ts); | ||
1091 | } | ||
1092 | 1048 | ||
1093 | #ifdef CONFIG_TCP_MD5SIG | 1049 | #ifdef CONFIG_TCP_MD5SIG |
1094 | if (key) { | 1050 | if (sk) |
1095 | *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | 1051 | key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr); |
1096 | (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); | 1052 | else |
1097 | tcp_v6_md5_hash_hdr((__u8 *)topt, key, | 1053 | key = NULL; |
1098 | &ipv6_hdr(skb)->saddr, | ||
1099 | &ipv6_hdr(skb)->daddr, t1); | ||
1100 | } | ||
1101 | #endif | 1054 | #endif |
1102 | 1055 | ||
1103 | buff->csum = csum_partial((char *)t1, tot_len, 0); | 1056 | if (th->ack) |
1104 | 1057 | seq = ntohl(th->ack_seq); | |
1105 | memset(&fl, 0, sizeof(fl)); | 1058 | else |
1106 | ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); | 1059 | ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - |
1107 | ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr); | 1060 | (th->doff << 2); |
1108 | |||
1109 | t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst, | ||
1110 | tot_len, IPPROTO_TCP, | ||
1111 | buff->csum); | ||
1112 | |||
1113 | fl.proto = IPPROTO_TCP; | ||
1114 | fl.oif = inet6_iif(skb); | ||
1115 | fl.fl_ip_dport = t1->dest; | ||
1116 | fl.fl_ip_sport = t1->source; | ||
1117 | security_skb_classify_flow(skb, &fl); | ||
1118 | 1061 | ||
1119 | if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { | 1062 | tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1); |
1120 | if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { | 1063 | } |
1121 | ip6_xmit(ctl_sk, buff, &fl, NULL, 0); | ||
1122 | TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); | ||
1123 | return; | ||
1124 | } | ||
1125 | } | ||
1126 | 1064 | ||
1127 | kfree_skb(buff); | 1065 | static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, |
1066 | struct tcp_md5sig_key *key) | ||
1067 | { | ||
1068 | tcp_v6_send_response(skb, seq, ack, win, ts, key, 0); | ||
1128 | } | 1069 | } |
1129 | 1070 | ||
1130 | static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) | 1071 | static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) |