summaryrefslogtreecommitdiffstats
path: root/translate.c
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2013-04-08 19:12:43 +0900
committerLorenzo Colitti <lorenzo@google.com>2013-04-12 09:59:11 +0900
commit5cc877d4fc20d66ca5a057a3dc445adb998409bd (patch)
tree04c07f58d75f425022269f6a441e59fa890f5729 /translate.c
parentf913fe49272286a7f1e58d94a208b6dc06a51fd2 (diff)
downloadandroid_external_android-clat-5cc877d4fc20d66ca5a057a3dc445adb998409bd.tar.gz
android_external_android-clat-5cc877d4fc20d66ca5a057a3dc445adb998409bd.tar.bz2
android_external_android-clat-5cc877d4fc20d66ca5a057a3dc445adb998409bd.zip
Treat the options as part of the TCP header.
This simplifies the code and makes UDP and TCP look the same. It will also make it easier to implement nested translation in the future because there will only be one iovec array entry for the transport layer header, regardless of whether we are translating UDP or TCP and regardless of the presence of options. Also get rid of a couple of memcpy statements by pointing to the original data instead. Bug: 8276725 Change-Id: I6a702aefdf3a070eedfc6f7d3ebec21880ecc22b
Diffstat (limited to 'translate.c')
-rw-r--r--translate.c77
1 files changed, 37 insertions, 40 deletions
diff --git a/translate.c b/translate.c
index 89a7e7b..936c781 100644
--- a/translate.c
+++ b/translate.c
@@ -303,44 +303,41 @@ void udp6_to_udp(int fd, const struct ip6_hdr *ip6, const struct udphdr *udp, co
* array position 0 - tun header
* array position 1 - ipv4/ipv6 header
* array position 2 - empty (will be tcp header)
- * array position 3 - empty (will be tcp options or payload)
- * array position 4 - empty (can be payload)
+ * array position 3 - empty (will be payload)
* checksum - partial checksum covering ipv4/ipv6 header
- * options - pointer to tcp option buffer
- * options_size - size of tcp option buffer
*
* TODO: mss rewrite
* TODO: hosts without pmtu discovery - non DF packets will rely on fragmentation (unimplemented)
*/
-void tcp_translate(int fd, const struct tcphdr *tcp, const char *payload, size_t payload_size, struct iovec *io_targ, uint32_t checksum, const char *options, size_t options_size) {
- struct tcphdr tcp_targ;
- int targ_index = 2;
-
- memcpy(&tcp_targ, tcp, sizeof(tcp_targ));
- tcp_targ.check = 0;
-
- checksum = ip_checksum_add(checksum, &tcp_targ, sizeof(tcp_targ));
- if(options) {
- checksum = ip_checksum_add(checksum, options, options_size);
+void tcp_translate(int fd, const struct tcphdr *tcp, size_t header_size, const char *payload,
+ size_t payload_size, struct iovec *io_targ, uint32_t checksum) {
+ union {
+ // Reserve space for the maximum size of the TCP header, including options. The TCP header
+ // length field is 4 bits long and counts 4-byte words, so it can be at most 60 bytes.
+ char buf[15 * 4];
+ struct tcphdr tcp;
+ } header;
+
+ if (header_size > sizeof(header.buf)) {
+ // A TCP header cannot be more than 60 bytes long, so this can never happen unless there is a
+ // bug in the caller.
+ logmsg(ANDROID_LOG_ERROR, "tcp_translate: header too long %d > %d, truncating",
+ header_size, sizeof(header.buf));
+ header_size = sizeof(header.buf);
}
- checksum = ip_checksum_add(checksum, payload, payload_size);
- tcp_targ.check = ip_checksum_finish(checksum);
- io_targ[targ_index].iov_base = &tcp_targ;
- io_targ[targ_index].iov_len = sizeof(tcp_targ);
- targ_index++;
+ memcpy(&header, tcp, header_size);
- if(options) {
- io_targ[targ_index].iov_base = (char *)options;
- io_targ[targ_index].iov_len = options_size;
- targ_index++;
- }
+ header.tcp.check = 0;
+ checksum = ip_checksum_add(checksum, &header, header_size);
+ checksum = ip_checksum_add(checksum, payload, payload_size);
+ header.tcp.check = ip_checksum_finish(checksum);
- io_targ[targ_index].iov_base = (char *)payload;
- io_targ[targ_index].iov_len = payload_size;
- targ_index++;
+ io_targ[2].iov_base = &header;
+ io_targ[2].iov_len = header_size;
- writev(fd, io_targ, targ_index);
+ io_targ[3].iov_base = (char *)payload;
+ io_targ[3].iov_len = payload_size;
}
/* function: tcp_to_tcp6
@@ -348,12 +345,12 @@ void tcp_translate(int fd, const struct tcphdr *tcp, const char *payload, size_t
* fd - tun interface fd
* ip - source packet ipv4 header
* tcp - source packet tcp header
+ * header_size - size of tcp header including options
* payload - tcp payload
* payload_size - size of payload
- * options - tcp options
- * options_size - size of options
*/
-void tcp_to_tcp6(int fd,const struct iphdr *ip, const struct tcphdr *tcp, const char *payload, size_t payload_size, const char *options, size_t options_size) {
+void tcp_to_tcp6(int fd, const struct iphdr *ip, const struct tcphdr *tcp, size_t header_size,
+ const char *payload, size_t payload_size) {
struct ip6_hdr ip6_targ;
struct iovec io_targ[5];
struct tun_pi tun_header;
@@ -361,16 +358,16 @@ void tcp_to_tcp6(int fd,const struct iphdr *ip, const struct tcphdr *tcp, const
fill_tun_header(&tun_header,ETH_P_IPV6);
- fill_ip6_header(&ip6_targ,payload_size+options_size+sizeof(struct tcphdr),IPPROTO_TCP,ip);
+ fill_ip6_header(&ip6_targ, header_size + payload_size, IPPROTO_TCP, ip);
- checksum = ipv6_pseudo_header_checksum(0, &ip6_targ, sizeof(*tcp) + options_size + payload_size);
+ checksum = ipv6_pseudo_header_checksum(0, &ip6_targ, header_size + payload_size);
io_targ[0].iov_base = &tun_header;
io_targ[0].iov_len = sizeof(tun_header);
io_targ[1].iov_base = &ip6_targ;
io_targ[1].iov_len = sizeof(ip6_targ);
- tcp_translate(fd,tcp,payload,payload_size,io_targ,checksum,options,options_size);
+ tcp_translate(fd, tcp, header_size, payload, payload_size, io_targ, checksum);
}
/* function: tcp6_to_tcp
@@ -378,12 +375,12 @@ void tcp_to_tcp6(int fd,const struct iphdr *ip, const struct tcphdr *tcp, const
* fd - tun interface fd
* ip6 - source packet ipv6 header
* tcp - source packet tcp header
+ * header_size - size of tcp header including options
* payload - tcp payload
* payload_size - size of payload
- * options - tcp options
- * options_size - size of options
*/
-void tcp6_to_tcp(int fd,const struct ip6_hdr *ip6, const struct tcphdr *tcp, const char *payload, size_t payload_size, const char *options, size_t options_size) {
+void tcp6_to_tcp(int fd, const struct ip6_hdr *ip6, const struct tcphdr *tcp, size_t header_size,
+ const char *payload, size_t payload_size) {
struct iphdr ip_targ;
struct iovec io_targ[5];
struct tun_pi tun_header;
@@ -391,14 +388,14 @@ void tcp6_to_tcp(int fd,const struct ip6_hdr *ip6, const struct tcphdr *tcp, con
fill_tun_header(&tun_header,ETH_P_IP);
- fill_ip_header(&ip_targ,payload_size+options_size+sizeof(struct tcphdr),IPPROTO_TCP,ip6);
+ fill_ip_header(&ip_targ, header_size + payload_size, IPPROTO_TCP, ip6);
- checksum = ipv4_pseudo_header_checksum(0, &ip_targ, sizeof(*tcp) + payload_size + options_size);
+ checksum = ipv4_pseudo_header_checksum(0, &ip_targ, header_size + payload_size);
io_targ[0].iov_base = &tun_header;
io_targ[0].iov_len = sizeof(tun_header);
io_targ[1].iov_base = &ip_targ;
io_targ[1].iov_len = sizeof(ip_targ);
- tcp_translate(fd,tcp,payload,payload_size,io_targ,checksum,options,options_size);
+ tcp_translate(fd, tcp, header_size, payload, payload_size, io_targ, checksum);
}