0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 #define _GNU_SOURCE
0039
0040 #include <arpa/inet.h>
0041 #include <errno.h>
0042 #include <error.h>
0043 #include <getopt.h>
0044 #include <linux/filter.h>
0045 #include <linux/if_packet.h>
0046 #include <linux/ipv6.h>
0047 #include <net/ethernet.h>
0048 #include <net/if.h>
0049 #include <netinet/in.h>
0050 #include <netinet/ip.h>
0051 #include <netinet/ip6.h>
0052 #include <netinet/tcp.h>
0053 #include <stdbool.h>
0054 #include <stddef.h>
0055 #include <stdio.h>
0056 #include <stdarg.h>
0057 #include <string.h>
0058 #include <unistd.h>
0059
0060 #include "../kselftest.h"
0061
0062 #define DPORT 8000
0063 #define SPORT 1500
0064 #define PAYLOAD_LEN 100
0065 #define NUM_PACKETS 4
0066 #define START_SEQ 100
0067 #define START_ACK 100
0068 #define ETH_P_NONE 0
0069 #define TOTAL_HDR_LEN (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct tcphdr))
0070 #define MSS (4096 - sizeof(struct tcphdr) - sizeof(struct ipv6hdr))
0071 #define MAX_PAYLOAD (IP_MAXPACKET - sizeof(struct tcphdr) - sizeof(struct ipv6hdr))
0072 #define NUM_LARGE_PKT (MAX_PAYLOAD / MSS)
0073 #define MAX_HDR_LEN (ETH_HLEN + sizeof(struct ipv6hdr) + sizeof(struct tcphdr))
0074
0075 static const char *addr6_src = "fdaa::2";
0076 static const char *addr6_dst = "fdaa::1";
0077 static const char *addr4_src = "192.168.1.200";
0078 static const char *addr4_dst = "192.168.1.100";
0079 static int proto = -1;
0080 static uint8_t src_mac[ETH_ALEN], dst_mac[ETH_ALEN];
0081 static char *testname = "data";
0082 static char *ifname = "eth0";
0083 static char *smac = "aa:00:00:00:00:02";
0084 static char *dmac = "aa:00:00:00:00:01";
0085 static bool verbose;
0086 static bool tx_socket = true;
0087 static int tcp_offset = -1;
0088 static int total_hdr_len = -1;
0089 static int ethhdr_proto = -1;
0090
0091 static void vlog(const char *fmt, ...)
0092 {
0093 va_list args;
0094
0095 if (verbose) {
0096 va_start(args, fmt);
0097 vfprintf(stderr, fmt, args);
0098 va_end(args);
0099 }
0100 }
0101
0102 static void setup_sock_filter(int fd)
0103 {
0104 const int dport_off = tcp_offset + offsetof(struct tcphdr, dest);
0105 const int ethproto_off = offsetof(struct ethhdr, h_proto);
0106 int optlen = 0;
0107 int ipproto_off;
0108 int next_off;
0109
0110 if (proto == PF_INET)
0111 next_off = offsetof(struct iphdr, protocol);
0112 else
0113 next_off = offsetof(struct ipv6hdr, nexthdr);
0114 ipproto_off = ETH_HLEN + next_off;
0115
0116 if (strcmp(testname, "ip") == 0) {
0117 if (proto == PF_INET)
0118 optlen = sizeof(struct ip_timestamp);
0119 else
0120 optlen = sizeof(struct ip6_frag);
0121 }
0122
0123 struct sock_filter filter[] = {
0124 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, ethproto_off),
0125 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ntohs(ethhdr_proto), 0, 7),
0126 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ipproto_off),
0127 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_TCP, 0, 5),
0128 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, dport_off),
0129 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DPORT, 2, 0),
0130 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, dport_off + optlen),
0131 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DPORT, 0, 1),
0132 BPF_STMT(BPF_RET + BPF_K, 0xFFFFFFFF),
0133 BPF_STMT(BPF_RET + BPF_K, 0),
0134 };
0135
0136 struct sock_fprog bpf = {
0137 .len = ARRAY_SIZE(filter),
0138 .filter = filter,
0139 };
0140
0141 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)) < 0)
0142 error(1, errno, "error setting filter");
0143 }
0144
0145 static uint32_t checksum_nofold(void *data, size_t len, uint32_t sum)
0146 {
0147 uint16_t *words = data;
0148 int i;
0149
0150 for (i = 0; i < len / 2; i++)
0151 sum += words[i];
0152 if (len & 1)
0153 sum += ((char *)data)[len - 1];
0154 return sum;
0155 }
0156
0157 static uint16_t checksum_fold(void *data, size_t len, uint32_t sum)
0158 {
0159 sum = checksum_nofold(data, len, sum);
0160 while (sum > 0xFFFF)
0161 sum = (sum & 0xFFFF) + (sum >> 16);
0162 return ~sum;
0163 }
0164
0165 static uint16_t tcp_checksum(void *buf, int payload_len)
0166 {
0167 struct pseudo_header6 {
0168 struct in6_addr saddr;
0169 struct in6_addr daddr;
0170 uint16_t protocol;
0171 uint16_t payload_len;
0172 } ph6;
0173 struct pseudo_header4 {
0174 struct in_addr saddr;
0175 struct in_addr daddr;
0176 uint16_t protocol;
0177 uint16_t payload_len;
0178 } ph4;
0179 uint32_t sum = 0;
0180
0181 if (proto == PF_INET6) {
0182 if (inet_pton(AF_INET6, addr6_src, &ph6.saddr) != 1)
0183 error(1, errno, "inet_pton6 source ip pseudo");
0184 if (inet_pton(AF_INET6, addr6_dst, &ph6.daddr) != 1)
0185 error(1, errno, "inet_pton6 dest ip pseudo");
0186 ph6.protocol = htons(IPPROTO_TCP);
0187 ph6.payload_len = htons(sizeof(struct tcphdr) + payload_len);
0188
0189 sum = checksum_nofold(&ph6, sizeof(ph6), 0);
0190 } else if (proto == PF_INET) {
0191 if (inet_pton(AF_INET, addr4_src, &ph4.saddr) != 1)
0192 error(1, errno, "inet_pton source ip pseudo");
0193 if (inet_pton(AF_INET, addr4_dst, &ph4.daddr) != 1)
0194 error(1, errno, "inet_pton dest ip pseudo");
0195 ph4.protocol = htons(IPPROTO_TCP);
0196 ph4.payload_len = htons(sizeof(struct tcphdr) + payload_len);
0197
0198 sum = checksum_nofold(&ph4, sizeof(ph4), 0);
0199 }
0200
0201 return checksum_fold(buf, sizeof(struct tcphdr) + payload_len, sum);
0202 }
0203
0204 static void read_MAC(uint8_t *mac_addr, char *mac)
0205 {
0206 if (sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
0207 &mac_addr[0], &mac_addr[1], &mac_addr[2],
0208 &mac_addr[3], &mac_addr[4], &mac_addr[5]) != 6)
0209 error(1, 0, "sscanf");
0210 }
0211
0212 static void fill_datalinklayer(void *buf)
0213 {
0214 struct ethhdr *eth = buf;
0215
0216 memcpy(eth->h_dest, dst_mac, ETH_ALEN);
0217 memcpy(eth->h_source, src_mac, ETH_ALEN);
0218 eth->h_proto = ethhdr_proto;
0219 }
0220
0221 static void fill_networklayer(void *buf, int payload_len)
0222 {
0223 struct ipv6hdr *ip6h = buf;
0224 struct iphdr *iph = buf;
0225
0226 if (proto == PF_INET6) {
0227 memset(ip6h, 0, sizeof(*ip6h));
0228
0229 ip6h->version = 6;
0230 ip6h->payload_len = htons(sizeof(struct tcphdr) + payload_len);
0231 ip6h->nexthdr = IPPROTO_TCP;
0232 ip6h->hop_limit = 8;
0233 if (inet_pton(AF_INET6, addr6_src, &ip6h->saddr) != 1)
0234 error(1, errno, "inet_pton source ip6");
0235 if (inet_pton(AF_INET6, addr6_dst, &ip6h->daddr) != 1)
0236 error(1, errno, "inet_pton dest ip6");
0237 } else if (proto == PF_INET) {
0238 memset(iph, 0, sizeof(*iph));
0239
0240 iph->version = 4;
0241 iph->ihl = 5;
0242 iph->ttl = 8;
0243 iph->protocol = IPPROTO_TCP;
0244 iph->tot_len = htons(sizeof(struct tcphdr) +
0245 payload_len + sizeof(struct iphdr));
0246 iph->frag_off = htons(0x4000);
0247 if (inet_pton(AF_INET, addr4_src, &iph->saddr) != 1)
0248 error(1, errno, "inet_pton source ip");
0249 if (inet_pton(AF_INET, addr4_dst, &iph->daddr) != 1)
0250 error(1, errno, "inet_pton dest ip");
0251 iph->check = checksum_fold(buf, sizeof(struct iphdr), 0);
0252 }
0253 }
0254
0255 static void fill_transportlayer(void *buf, int seq_offset, int ack_offset,
0256 int payload_len, int fin)
0257 {
0258 struct tcphdr *tcph = buf;
0259
0260 memset(tcph, 0, sizeof(*tcph));
0261
0262 tcph->source = htons(SPORT);
0263 tcph->dest = htons(DPORT);
0264 tcph->seq = ntohl(START_SEQ + seq_offset);
0265 tcph->ack_seq = ntohl(START_ACK + ack_offset);
0266 tcph->ack = 1;
0267 tcph->fin = fin;
0268 tcph->doff = 5;
0269 tcph->window = htons(TCP_MAXWIN);
0270 tcph->urg_ptr = 0;
0271 tcph->check = tcp_checksum(tcph, payload_len);
0272 }
0273
0274 static void write_packet(int fd, char *buf, int len, struct sockaddr_ll *daddr)
0275 {
0276 int ret = -1;
0277
0278 ret = sendto(fd, buf, len, 0, (struct sockaddr *)daddr, sizeof(*daddr));
0279 if (ret == -1)
0280 error(1, errno, "sendto failure");
0281 if (ret != len)
0282 error(1, errno, "sendto wrong length");
0283 }
0284
0285 static void create_packet(void *buf, int seq_offset, int ack_offset,
0286 int payload_len, int fin)
0287 {
0288 memset(buf, 0, total_hdr_len);
0289 memset(buf + total_hdr_len, 'a', payload_len);
0290 fill_transportlayer(buf + tcp_offset, seq_offset, ack_offset,
0291 payload_len, fin);
0292 fill_networklayer(buf + ETH_HLEN, payload_len);
0293 fill_datalinklayer(buf);
0294 }
0295
0296
0297 static void send_flags(int fd, struct sockaddr_ll *daddr, int psh, int syn,
0298 int rst, int urg)
0299 {
0300 static char flag_buf[MAX_HDR_LEN + PAYLOAD_LEN];
0301 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0302 int payload_len, pkt_size, flag, i;
0303 struct tcphdr *tcph;
0304
0305 payload_len = PAYLOAD_LEN * psh;
0306 pkt_size = total_hdr_len + payload_len;
0307 flag = NUM_PACKETS / 2;
0308
0309 create_packet(flag_buf, flag * payload_len, 0, payload_len, 0);
0310
0311 tcph = (struct tcphdr *)(flag_buf + tcp_offset);
0312 tcph->psh = psh;
0313 tcph->syn = syn;
0314 tcph->rst = rst;
0315 tcph->urg = urg;
0316 tcph->check = 0;
0317 tcph->check = tcp_checksum(tcph, payload_len);
0318
0319 for (i = 0; i < NUM_PACKETS + 1; i++) {
0320 if (i == flag) {
0321 write_packet(fd, flag_buf, pkt_size, daddr);
0322 continue;
0323 }
0324 create_packet(buf, i * PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
0325 write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr);
0326 }
0327 }
0328
0329
0330
0331
0332 static void send_data_pkts(int fd, struct sockaddr_ll *daddr,
0333 int payload_len1, int payload_len2)
0334 {
0335 static char buf[ETH_HLEN + IP_MAXPACKET];
0336
0337 create_packet(buf, 0, 0, payload_len1, 0);
0338 write_packet(fd, buf, total_hdr_len + payload_len1, daddr);
0339 create_packet(buf, payload_len1, 0, payload_len2, 0);
0340 write_packet(fd, buf, total_hdr_len + payload_len2, daddr);
0341 }
0342
0343
0344
0345
0346 static void send_large(int fd, struct sockaddr_ll *daddr, int remainder)
0347 {
0348 static char pkts[NUM_LARGE_PKT][TOTAL_HDR_LEN + MSS];
0349 static char last[TOTAL_HDR_LEN + MSS];
0350 static char new_seg[TOTAL_HDR_LEN + MSS];
0351 int i;
0352
0353 for (i = 0; i < NUM_LARGE_PKT; i++)
0354 create_packet(pkts[i], i * MSS, 0, MSS, 0);
0355 create_packet(last, NUM_LARGE_PKT * MSS, 0, remainder, 0);
0356 create_packet(new_seg, (NUM_LARGE_PKT + 1) * MSS, 0, remainder, 0);
0357
0358 for (i = 0; i < NUM_LARGE_PKT; i++)
0359 write_packet(fd, pkts[i], total_hdr_len + MSS, daddr);
0360 write_packet(fd, last, total_hdr_len + remainder, daddr);
0361 write_packet(fd, new_seg, total_hdr_len + remainder, daddr);
0362 }
0363
0364
0365 static void send_ack(int fd, struct sockaddr_ll *daddr)
0366 {
0367 static char buf[MAX_HDR_LEN];
0368
0369 create_packet(buf, 0, 0, 0, 0);
0370 write_packet(fd, buf, total_hdr_len, daddr);
0371 write_packet(fd, buf, total_hdr_len, daddr);
0372 create_packet(buf, 0, 1, 0, 0);
0373 write_packet(fd, buf, total_hdr_len, daddr);
0374 }
0375
0376 static void recompute_packet(char *buf, char *no_ext, int extlen)
0377 {
0378 struct tcphdr *tcphdr = (struct tcphdr *)(buf + tcp_offset);
0379 struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN);
0380 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
0381
0382 memmove(buf, no_ext, total_hdr_len);
0383 memmove(buf + total_hdr_len + extlen,
0384 no_ext + total_hdr_len, PAYLOAD_LEN);
0385
0386 tcphdr->doff = tcphdr->doff + (extlen / 4);
0387 tcphdr->check = 0;
0388 tcphdr->check = tcp_checksum(tcphdr, PAYLOAD_LEN + extlen);
0389 if (proto == PF_INET) {
0390 iph->tot_len = htons(ntohs(iph->tot_len) + extlen);
0391 iph->check = 0;
0392 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
0393 } else {
0394 ip6h->payload_len = htons(ntohs(ip6h->payload_len) + extlen);
0395 }
0396 }
0397
0398 static void tcp_write_options(char *buf, int kind, int ts)
0399 {
0400 struct tcp_option_ts {
0401 uint8_t kind;
0402 uint8_t len;
0403 uint32_t tsval;
0404 uint32_t tsecr;
0405 } *opt_ts = (void *)buf;
0406 struct tcp_option_window {
0407 uint8_t kind;
0408 uint8_t len;
0409 uint8_t shift;
0410 } *opt_window = (void *)buf;
0411
0412 switch (kind) {
0413 case TCPOPT_NOP:
0414 buf[0] = TCPOPT_NOP;
0415 break;
0416 case TCPOPT_WINDOW:
0417 memset(opt_window, 0, sizeof(struct tcp_option_window));
0418 opt_window->kind = TCPOPT_WINDOW;
0419 opt_window->len = TCPOLEN_WINDOW;
0420 opt_window->shift = 0;
0421 break;
0422 case TCPOPT_TIMESTAMP:
0423 memset(opt_ts, 0, sizeof(struct tcp_option_ts));
0424 opt_ts->kind = TCPOPT_TIMESTAMP;
0425 opt_ts->len = TCPOLEN_TIMESTAMP;
0426 opt_ts->tsval = ts;
0427 opt_ts->tsecr = 0;
0428 break;
0429 default:
0430 error(1, 0, "unimplemented TCP option");
0431 break;
0432 }
0433 }
0434
0435
0436
0437
0438 static void add_standard_tcp_options(char *buf, char *no_ext, int ts, int order)
0439 {
0440 switch (order) {
0441 case 0:
0442 tcp_write_options(buf + total_hdr_len, TCPOPT_NOP, 0);
0443 tcp_write_options(buf + total_hdr_len + 1, TCPOPT_NOP, 0);
0444 tcp_write_options(buf + total_hdr_len + 2 ,
0445 TCPOPT_TIMESTAMP, ts);
0446 break;
0447 case 1:
0448 tcp_write_options(buf + total_hdr_len, TCPOPT_NOP, 0);
0449 tcp_write_options(buf + total_hdr_len + 1,
0450 TCPOPT_TIMESTAMP, ts);
0451 tcp_write_options(buf + total_hdr_len + 1 + TCPOLEN_TIMESTAMP,
0452 TCPOPT_NOP, 0);
0453 break;
0454 case 2:
0455 tcp_write_options(buf + total_hdr_len, TCPOPT_TIMESTAMP, ts);
0456 tcp_write_options(buf + total_hdr_len + TCPOLEN_TIMESTAMP + 1,
0457 TCPOPT_NOP, 0);
0458 tcp_write_options(buf + total_hdr_len + TCPOLEN_TIMESTAMP + 2,
0459 TCPOPT_NOP, 0);
0460 break;
0461 default:
0462 error(1, 0, "unknown order");
0463 break;
0464 }
0465 recompute_packet(buf, no_ext, TCPOLEN_TSTAMP_APPA);
0466 }
0467
0468
0469 static void send_changed_checksum(int fd, struct sockaddr_ll *daddr)
0470 {
0471 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0472 struct tcphdr *tcph = (struct tcphdr *)(buf + tcp_offset);
0473 int pkt_size = total_hdr_len + PAYLOAD_LEN;
0474
0475 create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
0476 write_packet(fd, buf, pkt_size, daddr);
0477
0478 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
0479 tcph->check = tcph->check - 1;
0480 write_packet(fd, buf, pkt_size, daddr);
0481 }
0482
0483
0484 static void send_changed_seq(int fd, struct sockaddr_ll *daddr)
0485 {
0486 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0487 struct tcphdr *tcph = (struct tcphdr *)(buf + tcp_offset);
0488 int pkt_size = total_hdr_len + PAYLOAD_LEN;
0489
0490 create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
0491 write_packet(fd, buf, pkt_size, daddr);
0492
0493 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
0494 tcph->seq = ntohl(htonl(tcph->seq) + 1);
0495 tcph->check = 0;
0496 tcph->check = tcp_checksum(tcph, PAYLOAD_LEN);
0497 write_packet(fd, buf, pkt_size, daddr);
0498 }
0499
0500
0501
0502
0503 static void send_changed_ts(int fd, struct sockaddr_ll *daddr)
0504 {
0505 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0506 static char extpkt[sizeof(buf) + TCPOLEN_TSTAMP_APPA];
0507 int pkt_size = total_hdr_len + PAYLOAD_LEN + TCPOLEN_TSTAMP_APPA;
0508
0509 create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
0510 add_standard_tcp_options(extpkt, buf, 0, 0);
0511 write_packet(fd, extpkt, pkt_size, daddr);
0512
0513 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
0514 add_standard_tcp_options(extpkt, buf, 0, 0);
0515 write_packet(fd, extpkt, pkt_size, daddr);
0516
0517 create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0);
0518 add_standard_tcp_options(extpkt, buf, 100, 0);
0519 write_packet(fd, extpkt, pkt_size, daddr);
0520
0521 create_packet(buf, PAYLOAD_LEN * 3, 0, PAYLOAD_LEN, 0);
0522 add_standard_tcp_options(extpkt, buf, 100, 1);
0523 write_packet(fd, extpkt, pkt_size, daddr);
0524
0525 create_packet(buf, PAYLOAD_LEN * 4, 0, PAYLOAD_LEN, 0);
0526 add_standard_tcp_options(extpkt, buf, 100, 2);
0527 write_packet(fd, extpkt, pkt_size, daddr);
0528 }
0529
0530
0531 static void send_diff_opt(int fd, struct sockaddr_ll *daddr)
0532 {
0533 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0534 static char extpkt1[sizeof(buf) + TCPOLEN_TSTAMP_APPA];
0535 static char extpkt2[sizeof(buf) + TCPOLEN_MAXSEG];
0536 int extpkt1_size = total_hdr_len + PAYLOAD_LEN + TCPOLEN_TSTAMP_APPA;
0537 int extpkt2_size = total_hdr_len + PAYLOAD_LEN + TCPOLEN_MAXSEG;
0538
0539 create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
0540 add_standard_tcp_options(extpkt1, buf, 0, 0);
0541 write_packet(fd, extpkt1, extpkt1_size, daddr);
0542
0543 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
0544 add_standard_tcp_options(extpkt1, buf, 0, 0);
0545 write_packet(fd, extpkt1, extpkt1_size, daddr);
0546
0547 create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0);
0548 tcp_write_options(extpkt2 + MAX_HDR_LEN, TCPOPT_NOP, 0);
0549 tcp_write_options(extpkt2 + MAX_HDR_LEN + 1, TCPOPT_WINDOW, 0);
0550 recompute_packet(extpkt2, buf, TCPOLEN_WINDOW + 1);
0551 write_packet(fd, extpkt2, extpkt2_size, daddr);
0552 }
0553
0554 static void add_ipv4_ts_option(void *buf, void *optpkt)
0555 {
0556 struct ip_timestamp *ts = (struct ip_timestamp *)(optpkt + tcp_offset);
0557 int optlen = sizeof(struct ip_timestamp);
0558 struct iphdr *iph;
0559
0560 if (optlen % 4)
0561 error(1, 0, "ipv4 timestamp length is not a multiple of 4B");
0562
0563 ts->ipt_code = IPOPT_TS;
0564 ts->ipt_len = optlen;
0565 ts->ipt_ptr = 5;
0566 ts->ipt_flg = IPOPT_TS_TSONLY;
0567
0568 memcpy(optpkt, buf, tcp_offset);
0569 memcpy(optpkt + tcp_offset + optlen, buf + tcp_offset,
0570 sizeof(struct tcphdr) + PAYLOAD_LEN);
0571
0572 iph = (struct iphdr *)(optpkt + ETH_HLEN);
0573 iph->ihl = 5 + (optlen / 4);
0574 iph->tot_len = htons(ntohs(iph->tot_len) + optlen);
0575 iph->check = 0;
0576 iph->check = checksum_fold(iph, sizeof(struct iphdr) + optlen, 0);
0577 }
0578
0579
0580 static void send_ip_options(int fd, struct sockaddr_ll *daddr)
0581 {
0582 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0583 static char optpkt[sizeof(buf) + sizeof(struct ip_timestamp)];
0584 int optlen = sizeof(struct ip_timestamp);
0585 int pkt_size = total_hdr_len + PAYLOAD_LEN + optlen;
0586
0587 create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
0588 write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr);
0589
0590 create_packet(buf, PAYLOAD_LEN * 1, 0, PAYLOAD_LEN, 0);
0591 add_ipv4_ts_option(buf, optpkt);
0592 write_packet(fd, optpkt, pkt_size, daddr);
0593
0594 create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0);
0595 write_packet(fd, buf, total_hdr_len + PAYLOAD_LEN, daddr);
0596 }
0597
0598
0599 static void send_fragment4(int fd, struct sockaddr_ll *daddr)
0600 {
0601 static char buf[IP_MAXPACKET];
0602 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
0603 int pkt_size = total_hdr_len + PAYLOAD_LEN;
0604
0605 create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
0606 write_packet(fd, buf, pkt_size, daddr);
0607
0608
0609
0610
0611
0612 memset(buf + total_hdr_len, 'a', PAYLOAD_LEN * 2);
0613 fill_transportlayer(buf + tcp_offset, PAYLOAD_LEN, 0, PAYLOAD_LEN * 2, 0);
0614 fill_networklayer(buf + ETH_HLEN, PAYLOAD_LEN);
0615 fill_datalinklayer(buf);
0616
0617 iph->frag_off = htons(0x6000);
0618 iph->check = 0;
0619 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
0620 write_packet(fd, buf, pkt_size, daddr);
0621 }
0622
0623
0624 static void send_changed_ttl(int fd, struct sockaddr_ll *daddr)
0625 {
0626 int pkt_size = total_hdr_len + PAYLOAD_LEN;
0627 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0628 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
0629
0630 create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
0631 write_packet(fd, buf, pkt_size, daddr);
0632
0633 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
0634 iph->ttl = 7;
0635 iph->check = 0;
0636 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
0637 write_packet(fd, buf, pkt_size, daddr);
0638 }
0639
0640
0641 static void send_changed_tos(int fd, struct sockaddr_ll *daddr)
0642 {
0643 int pkt_size = total_hdr_len + PAYLOAD_LEN;
0644 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0645 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
0646 struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN);
0647
0648 create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
0649 write_packet(fd, buf, pkt_size, daddr);
0650
0651 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
0652 if (proto == PF_INET) {
0653 iph->tos = 1;
0654 iph->check = 0;
0655 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
0656 } else if (proto == PF_INET6) {
0657 ip6h->priority = 0xf;
0658 }
0659 write_packet(fd, buf, pkt_size, daddr);
0660 }
0661
0662
0663 static void send_changed_ECN(int fd, struct sockaddr_ll *daddr)
0664 {
0665 int pkt_size = total_hdr_len + PAYLOAD_LEN;
0666 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0667 struct iphdr *iph = (struct iphdr *)(buf + ETH_HLEN);
0668
0669 create_packet(buf, 0, 0, PAYLOAD_LEN, 0);
0670 write_packet(fd, buf, pkt_size, daddr);
0671
0672 create_packet(buf, PAYLOAD_LEN, 0, PAYLOAD_LEN, 0);
0673 if (proto == PF_INET) {
0674 buf[ETH_HLEN + 1] ^= 0x2;
0675 iph->check = 0;
0676 iph->check = checksum_fold(iph, sizeof(struct iphdr), 0);
0677 } else {
0678 buf[ETH_HLEN + 1] ^= 0x20;
0679 }
0680 write_packet(fd, buf, pkt_size, daddr);
0681 }
0682
0683
0684 static void send_fragment6(int fd, struct sockaddr_ll *daddr)
0685 {
0686 static char buf[MAX_HDR_LEN + PAYLOAD_LEN];
0687 static char extpkt[MAX_HDR_LEN + PAYLOAD_LEN +
0688 sizeof(struct ip6_frag)];
0689 struct ipv6hdr *ip6h = (struct ipv6hdr *)(buf + ETH_HLEN);
0690 struct ip6_frag *frag = (void *)(extpkt + tcp_offset);
0691 int extlen = sizeof(struct ip6_frag);
0692 int bufpkt_len = total_hdr_len + PAYLOAD_LEN;
0693 int extpkt_len = bufpkt_len + extlen;
0694 int i;
0695
0696 for (i = 0; i < 2; i++) {
0697 create_packet(buf, PAYLOAD_LEN * i, 0, PAYLOAD_LEN, 0);
0698 write_packet(fd, buf, bufpkt_len, daddr);
0699 }
0700
0701 create_packet(buf, PAYLOAD_LEN * 2, 0, PAYLOAD_LEN, 0);
0702 memset(extpkt, 0, extpkt_len);
0703
0704 ip6h->nexthdr = IPPROTO_FRAGMENT;
0705 ip6h->payload_len = htons(ntohs(ip6h->payload_len) + extlen);
0706 frag->ip6f_nxt = IPPROTO_TCP;
0707
0708 memcpy(extpkt, buf, tcp_offset);
0709 memcpy(extpkt + tcp_offset + extlen, buf + tcp_offset,
0710 sizeof(struct tcphdr) + PAYLOAD_LEN);
0711 write_packet(fd, extpkt, extpkt_len, daddr);
0712
0713 create_packet(buf, PAYLOAD_LEN * 3, 0, PAYLOAD_LEN, 0);
0714 write_packet(fd, buf, bufpkt_len, daddr);
0715 }
0716
0717 static void bind_packetsocket(int fd)
0718 {
0719 struct sockaddr_ll daddr = {};
0720
0721 daddr.sll_family = AF_PACKET;
0722 daddr.sll_protocol = ethhdr_proto;
0723 daddr.sll_ifindex = if_nametoindex(ifname);
0724 if (daddr.sll_ifindex == 0)
0725 error(1, errno, "if_nametoindex");
0726
0727 if (bind(fd, (void *)&daddr, sizeof(daddr)) < 0)
0728 error(1, errno, "could not bind socket");
0729 }
0730
0731 static void set_timeout(int fd)
0732 {
0733 struct timeval timeout;
0734
0735 timeout.tv_sec = 3;
0736 timeout.tv_usec = 0;
0737 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
0738 sizeof(timeout)) < 0)
0739 error(1, errno, "cannot set timeout, setsockopt failed");
0740 }
0741
0742 static void check_recv_pkts(int fd, int *correct_payload,
0743 int correct_num_pkts)
0744 {
0745 static char buffer[IP_MAXPACKET + ETH_HLEN + 1];
0746 struct iphdr *iph = (struct iphdr *)(buffer + ETH_HLEN);
0747 struct ipv6hdr *ip6h = (struct ipv6hdr *)(buffer + ETH_HLEN);
0748 struct tcphdr *tcph;
0749 bool bad_packet = false;
0750 int tcp_ext_len = 0;
0751 int ip_ext_len = 0;
0752 int pkt_size = -1;
0753 int data_len = 0;
0754 int num_pkt = 0;
0755 int i;
0756
0757 vlog("Expected {");
0758 for (i = 0; i < correct_num_pkts; i++)
0759 vlog("%d ", correct_payload[i]);
0760 vlog("}, Total %d packets\nReceived {", correct_num_pkts);
0761
0762 while (1) {
0763 pkt_size = recv(fd, buffer, IP_MAXPACKET + ETH_HLEN + 1, 0);
0764 if (pkt_size < 0)
0765 error(1, errno, "could not receive");
0766
0767 if (iph->version == 4)
0768 ip_ext_len = (iph->ihl - 5) * 4;
0769 else if (ip6h->version == 6 && ip6h->nexthdr != IPPROTO_TCP)
0770 ip_ext_len = sizeof(struct ip6_frag);
0771
0772 tcph = (struct tcphdr *)(buffer + tcp_offset + ip_ext_len);
0773
0774 if (tcph->fin)
0775 break;
0776
0777 tcp_ext_len = (tcph->doff - 5) * 4;
0778 data_len = pkt_size - total_hdr_len - tcp_ext_len - ip_ext_len;
0779
0780
0781
0782
0783 if (pkt_size == ETH_ZLEN && iph->version == 4) {
0784 data_len = ntohs(iph->tot_len)
0785 - sizeof(struct tcphdr) - sizeof(struct iphdr);
0786 }
0787 vlog("%d ", data_len);
0788 if (data_len != correct_payload[num_pkt]) {
0789 vlog("[!=%d]", correct_payload[num_pkt]);
0790 bad_packet = true;
0791 }
0792 num_pkt++;
0793 }
0794 vlog("}, Total %d packets.\n", num_pkt);
0795 if (num_pkt != correct_num_pkts)
0796 error(1, 0, "incorrect number of packets");
0797 if (bad_packet)
0798 error(1, 0, "incorrect packet geometry");
0799
0800 printf("Test succeeded\n\n");
0801 }
0802
0803 static void gro_sender(void)
0804 {
0805 static char fin_pkt[MAX_HDR_LEN];
0806 struct sockaddr_ll daddr = {};
0807 int txfd = -1;
0808
0809 txfd = socket(PF_PACKET, SOCK_RAW, IPPROTO_RAW);
0810 if (txfd < 0)
0811 error(1, errno, "socket creation");
0812
0813 memset(&daddr, 0, sizeof(daddr));
0814 daddr.sll_ifindex = if_nametoindex(ifname);
0815 if (daddr.sll_ifindex == 0)
0816 error(1, errno, "if_nametoindex");
0817 daddr.sll_family = AF_PACKET;
0818 memcpy(daddr.sll_addr, dst_mac, ETH_ALEN);
0819 daddr.sll_halen = ETH_ALEN;
0820 create_packet(fin_pkt, PAYLOAD_LEN * 2, 0, 0, 1);
0821
0822 if (strcmp(testname, "data") == 0) {
0823 send_data_pkts(txfd, &daddr, PAYLOAD_LEN, PAYLOAD_LEN);
0824 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0825
0826 send_data_pkts(txfd, &daddr, PAYLOAD_LEN, PAYLOAD_LEN / 2);
0827 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0828
0829 send_data_pkts(txfd, &daddr, PAYLOAD_LEN / 2, PAYLOAD_LEN);
0830 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0831 } else if (strcmp(testname, "ack") == 0) {
0832 send_ack(txfd, &daddr);
0833 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0834 } else if (strcmp(testname, "flags") == 0) {
0835 send_flags(txfd, &daddr, 1, 0, 0, 0);
0836 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0837
0838 send_flags(txfd, &daddr, 0, 1, 0, 0);
0839 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0840
0841 send_flags(txfd, &daddr, 0, 0, 1, 0);
0842 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0843
0844 send_flags(txfd, &daddr, 0, 0, 0, 1);
0845 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0846 } else if (strcmp(testname, "tcp") == 0) {
0847 send_changed_checksum(txfd, &daddr);
0848 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0849
0850 send_changed_seq(txfd, &daddr);
0851 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0852
0853 send_changed_ts(txfd, &daddr);
0854 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0855
0856 send_diff_opt(txfd, &daddr);
0857 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0858 } else if (strcmp(testname, "ip") == 0) {
0859 send_changed_ECN(txfd, &daddr);
0860 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0861
0862 send_changed_tos(txfd, &daddr);
0863 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0864 if (proto == PF_INET) {
0865
0866
0867
0868
0869 sleep(1);
0870 send_changed_ttl(txfd, &daddr);
0871 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0872
0873 sleep(1);
0874 send_ip_options(txfd, &daddr);
0875 sleep(1);
0876 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0877
0878 sleep(1);
0879 send_fragment4(txfd, &daddr);
0880 sleep(1);
0881 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0882 } else if (proto == PF_INET6) {
0883 send_fragment6(txfd, &daddr);
0884 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0885 }
0886 } else if (strcmp(testname, "large") == 0) {
0887
0888
0889
0890
0891 int offset = proto == PF_INET ? 20 : 0;
0892 int remainder = (MAX_PAYLOAD + offset) % MSS;
0893
0894 send_large(txfd, &daddr, remainder);
0895 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0896
0897 send_large(txfd, &daddr, remainder + 1);
0898 write_packet(txfd, fin_pkt, total_hdr_len, &daddr);
0899 } else {
0900 error(1, 0, "Unknown testcase");
0901 }
0902
0903 if (close(txfd))
0904 error(1, errno, "socket close");
0905 }
0906
0907 static void gro_receiver(void)
0908 {
0909 static int correct_payload[NUM_PACKETS];
0910 int rxfd = -1;
0911
0912 rxfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_NONE));
0913 if (rxfd < 0)
0914 error(1, 0, "socket creation");
0915 setup_sock_filter(rxfd);
0916 set_timeout(rxfd);
0917 bind_packetsocket(rxfd);
0918
0919 memset(correct_payload, 0, sizeof(correct_payload));
0920
0921 if (strcmp(testname, "data") == 0) {
0922 printf("pure data packet of same size: ");
0923 correct_payload[0] = PAYLOAD_LEN * 2;
0924 check_recv_pkts(rxfd, correct_payload, 1);
0925
0926 printf("large data packets followed by a smaller one: ");
0927 correct_payload[0] = PAYLOAD_LEN * 1.5;
0928 check_recv_pkts(rxfd, correct_payload, 1);
0929
0930 printf("small data packets followed by a larger one: ");
0931 correct_payload[0] = PAYLOAD_LEN / 2;
0932 correct_payload[1] = PAYLOAD_LEN;
0933 check_recv_pkts(rxfd, correct_payload, 2);
0934 } else if (strcmp(testname, "ack") == 0) {
0935 printf("duplicate ack and pure ack: ");
0936 check_recv_pkts(rxfd, correct_payload, 3);
0937 } else if (strcmp(testname, "flags") == 0) {
0938 correct_payload[0] = PAYLOAD_LEN * 3;
0939 correct_payload[1] = PAYLOAD_LEN * 2;
0940
0941 printf("psh flag ends coalescing: ");
0942 check_recv_pkts(rxfd, correct_payload, 2);
0943
0944 correct_payload[0] = PAYLOAD_LEN * 2;
0945 correct_payload[1] = 0;
0946 correct_payload[2] = PAYLOAD_LEN * 2;
0947 printf("syn flag ends coalescing: ");
0948 check_recv_pkts(rxfd, correct_payload, 3);
0949
0950 printf("rst flag ends coalescing: ");
0951 check_recv_pkts(rxfd, correct_payload, 3);
0952
0953 printf("urg flag ends coalescing: ");
0954 check_recv_pkts(rxfd, correct_payload, 3);
0955 } else if (strcmp(testname, "tcp") == 0) {
0956 correct_payload[0] = PAYLOAD_LEN;
0957 correct_payload[1] = PAYLOAD_LEN;
0958 correct_payload[2] = PAYLOAD_LEN;
0959 correct_payload[3] = PAYLOAD_LEN;
0960
0961 printf("changed checksum does not coalesce: ");
0962 check_recv_pkts(rxfd, correct_payload, 2);
0963
0964 printf("Wrong Seq number doesn't coalesce: ");
0965 check_recv_pkts(rxfd, correct_payload, 2);
0966
0967 printf("Different timestamp doesn't coalesce: ");
0968 correct_payload[0] = PAYLOAD_LEN * 2;
0969 check_recv_pkts(rxfd, correct_payload, 4);
0970
0971 printf("Different options doesn't coalesce: ");
0972 correct_payload[0] = PAYLOAD_LEN * 2;
0973 check_recv_pkts(rxfd, correct_payload, 2);
0974 } else if (strcmp(testname, "ip") == 0) {
0975 correct_payload[0] = PAYLOAD_LEN;
0976 correct_payload[1] = PAYLOAD_LEN;
0977
0978 printf("different ECN doesn't coalesce: ");
0979 check_recv_pkts(rxfd, correct_payload, 2);
0980
0981 printf("different tos doesn't coalesce: ");
0982 check_recv_pkts(rxfd, correct_payload, 2);
0983
0984 if (proto == PF_INET) {
0985 printf("different ttl doesn't coalesce: ");
0986 check_recv_pkts(rxfd, correct_payload, 2);
0987
0988 printf("ip options doesn't coalesce: ");
0989 correct_payload[2] = PAYLOAD_LEN;
0990 check_recv_pkts(rxfd, correct_payload, 3);
0991
0992 printf("fragmented ip4 doesn't coalesce: ");
0993 check_recv_pkts(rxfd, correct_payload, 2);
0994 } else if (proto == PF_INET6) {
0995
0996
0997
0998 printf("fragmented ip6 doesn't coalesce: ");
0999 correct_payload[0] = PAYLOAD_LEN * 2;
1000 check_recv_pkts(rxfd, correct_payload, 2);
1001 }
1002 } else if (strcmp(testname, "large") == 0) {
1003 int offset = proto == PF_INET ? 20 : 0;
1004 int remainder = (MAX_PAYLOAD + offset) % MSS;
1005
1006 correct_payload[0] = (MAX_PAYLOAD + offset);
1007 correct_payload[1] = remainder;
1008 printf("Shouldn't coalesce if exceed IP max pkt size: ");
1009 check_recv_pkts(rxfd, correct_payload, 2);
1010
1011
1012 correct_payload[0] = correct_payload[0] - remainder;
1013 correct_payload[1] = remainder + 1;
1014 correct_payload[2] = remainder + 1;
1015 check_recv_pkts(rxfd, correct_payload, 3);
1016 } else {
1017 error(1, 0, "Test case error, should never trigger");
1018 }
1019
1020 if (close(rxfd))
1021 error(1, 0, "socket close");
1022 }
1023
1024 static void parse_args(int argc, char **argv)
1025 {
1026 static const struct option opts[] = {
1027 { "daddr", required_argument, NULL, 'd' },
1028 { "dmac", required_argument, NULL, 'D' },
1029 { "iface", required_argument, NULL, 'i' },
1030 { "ipv4", no_argument, NULL, '4' },
1031 { "ipv6", no_argument, NULL, '6' },
1032 { "rx", no_argument, NULL, 'r' },
1033 { "saddr", required_argument, NULL, 's' },
1034 { "smac", required_argument, NULL, 'S' },
1035 { "test", required_argument, NULL, 't' },
1036 { "verbose", no_argument, NULL, 'v' },
1037 { 0, 0, 0, 0 }
1038 };
1039 int c;
1040
1041 while ((c = getopt_long(argc, argv, "46d:D:i:rs:S:t:v", opts, NULL)) != -1) {
1042 switch (c) {
1043 case '4':
1044 proto = PF_INET;
1045 ethhdr_proto = htons(ETH_P_IP);
1046 break;
1047 case '6':
1048 proto = PF_INET6;
1049 ethhdr_proto = htons(ETH_P_IPV6);
1050 break;
1051 case 'd':
1052 addr4_dst = addr6_dst = optarg;
1053 break;
1054 case 'D':
1055 dmac = optarg;
1056 break;
1057 case 'i':
1058 ifname = optarg;
1059 break;
1060 case 'r':
1061 tx_socket = false;
1062 break;
1063 case 's':
1064 addr4_src = addr6_src = optarg;
1065 break;
1066 case 'S':
1067 smac = optarg;
1068 break;
1069 case 't':
1070 testname = optarg;
1071 break;
1072 case 'v':
1073 verbose = true;
1074 break;
1075 default:
1076 error(1, 0, "%s invalid option %c\n", __func__, c);
1077 break;
1078 }
1079 }
1080 }
1081
1082 int main(int argc, char **argv)
1083 {
1084 parse_args(argc, argv);
1085
1086 if (proto == PF_INET) {
1087 tcp_offset = ETH_HLEN + sizeof(struct iphdr);
1088 total_hdr_len = tcp_offset + sizeof(struct tcphdr);
1089 } else if (proto == PF_INET6) {
1090 tcp_offset = ETH_HLEN + sizeof(struct ipv6hdr);
1091 total_hdr_len = MAX_HDR_LEN;
1092 } else {
1093 error(1, 0, "Protocol family is not ipv4 or ipv6");
1094 }
1095
1096 read_MAC(src_mac, smac);
1097 read_MAC(dst_mac, dmac);
1098
1099 if (tx_socket)
1100 gro_sender();
1101 else
1102 gro_receiver();
1103
1104 fprintf(stderr, "Gro::%s test passed.\n", testname);
1105 return 0;
1106 }