1/* $NetBSD: npf_state_test.c,v 1.1.2.4 2012/11/18 21:48:56 riz Exp $ */ 2 3/* 4 * NPF state tracking test. 5 * 6 * Public Domain. 7 */ 8 9#include <sys/types.h> 10#include <sys/kmem.h> 11 12#include "npf_impl.h" 13#include "npf_test.h" 14 15typedef struct { 16 int tcpfl; /* TCP flags. */ 17 int tlen; /* TCP data length. */ 18 uint32_t seq; /* SEQ number. */ 19 uint32_t ack; /* ACK number. */ 20 uint32_t win; /* TCP Window. */ 21 int flags; /* Direction et al. */ 22} tcp_meta_t; 23 24#define S TH_SYN 25#define A TH_ACK 26#define F TH_FIN 27#define OUT 0x1 28#define IN 0x2 29#define ERR 0x4 30#define CLEAR .flags = 0 31 32static const tcp_meta_t packet_sequence[] = { 33 /* 34 * TCP data SEQ ACK WIN 35 */ 36 37 /* Out of order ACK. */ 38 { S, 0, 9999, 0, 4096, OUT }, 39 { S|A, 0, 9, 10000, 2048, IN }, 40 { A, 0, 10000, 10, 4096, OUT }, 41 /* --- */ 42 { A, 0, 10, 10000, 2048, IN }, 43 { A, 1000, 10000, 10, 4096, OUT }, 44 { A, 1000, 11000, 10, 4096, OUT }, 45 { A, 0, 10, 12000, 2048, IN }, 46 { A, 0, 10, 13000, 2048, IN }, 47 { A, 1000, 12000, 10, 4096, OUT }, 48 { A, 0, 10, 11000, 1048, IN }, 49 /* --- */ 50 { A, 1000, 14000, 10, 4096, OUT }, 51 { A, 0, 10, 13000, 2048, IN }, 52 { CLEAR }, 53 54 /* Retransmission after out of order ACK and missing ACK. */ 55 { S, 0, 9999, 0, 1000, OUT }, 56 { S|A, 0, 9, 10000, 4000, IN }, 57 { A, 0, 10000, 10, 1000, OUT }, 58 /* --- */ 59 { A, 1000, 10000, 10, 1000, OUT }, 60 { A, 0, 10, 11000, 4000, IN }, 61 { A, 1000, 11000, 10, 1000, OUT }, 62 { A, 1000, 12000, 10, 1000, OUT }, 63 { A, 1000, 13000, 10, 1000, OUT }, 64 { A, 1000, 14000, 10, 1000, OUT }, 65 /* --- Assume the first was delayed; second was lost after us. */ 66 { A, 0, 10, 15000, 4000, IN }, 67 { A, 0, 10, 15000, 2000, IN }, 68 /* --- */ 69 { A, 1000, 12000, 10, 1000, OUT }, 70 { CLEAR }, 71 72 /* FIN exchange with retransmit. */ 73 { S, 0, 999, 0, 1000, OUT }, 74 { S|A, 0, 9, 1000, 2000, IN }, 75 { A, 0, 1000, 10, 1000, OUT }, 76 /* --- */ 77 { F, 0, 10, 1000, 2000, IN }, 78 { F, 0, 1000, 10, 1000, OUT }, 79 { A, 0, 1000, 11, 1000, OUT }, 80 /* --- */ 81 { F, 0, 1000, 11, 1000, OUT }, 82 { F, 0, 1000, 11, 1000, OUT }, 83 { A, 0, 11, 1001, 2000, OUT }, 84 { CLEAR }, 85 86 /* Out of window. */ 87 { S, 0, 9, 0, 8760, OUT }, 88 { S|A, 0, 9999, 10, 1000, IN }, 89 { A, 0, 10, 10000, 8760, OUT }, 90 /* --- */ 91 { A, 1460, 10000, 10, 1000, IN }, 92 { A, 1460, 11460, 10, 1000, IN }, 93 { A, 0, 10, 12920, 8760, OUT }, 94 { A, 1460, 12920, 10, 1000, IN }, 95 { A, 0, 10, 14380, 8760, OUT }, 96 { A, 1460, 17300, 10, 1000, IN }, 97 { A, 0, 10, 14380, 8760, OUT }, 98 { A, 1460, 18760, 10, 1000, IN }, 99 { A, 0, 10, 14380, 8760, OUT }, 100 { A, 1460, 20220, 10, 1000, IN }, 101 { A, 0, 10, 14380, 8760, OUT }, 102 { A, 1460, 21680, 10, 1000, IN }, 103 { A, 0, 10, 14380, 8760, OUT }, 104 /* --- */ 105 { A, 1460, 14380, 10, 1000, IN }, 106 { A, 1460, 23140, 10, 1000, IN|ERR }, 107 { CLEAR }, 108 109}; 110 111#undef S 112#undef A 113#undef F 114 115static struct mbuf * 116construct_packet(const tcp_meta_t *p) 117{ 118 struct mbuf *m = mbuf_construct(IPPROTO_TCP); 119 struct ip *ip; 120 struct tcphdr *th; 121 122 th = mbuf_return_hdrs(m, false, &ip); 123 124 /* Imitate TCP payload, set TCP sequence numbers, flags and window. */ 125 ip->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr) + p->tlen); 126 th->th_seq = htonl(p->seq); 127 th->th_ack = htonl(p->ack); 128 th->th_flags = p->tcpfl; 129 th->th_win = htons(p->win); 130 return m; 131} 132 133static bool 134process_packet(const int i, npf_state_t *nst, bool *snew) 135{ 136 const tcp_meta_t *p = &packet_sequence[i]; 137 npf_cache_t npc = { .npc_info = 0 }; 138 nbuf_t nbuf; 139 int ret; 140 141 if (p->flags == 0) { 142 npf_state_destroy(nst); 143 *snew = true; 144 return true; 145 } 146 147 const void *dummy_ifp = (void *)0xdeadbeef; 148 nbuf_init(&nbuf, construct_packet(p), dummy_ifp); 149 ret = npf_cache_all(&npc, &nbuf); 150 KASSERT((ret & NPC_IPFRAG) == 0); 151 152 if (*snew) { 153 ret = npf_state_init(&npc, &nbuf, nst); 154 KASSERT(ret == true); 155 *snew = false; 156 } 157 ret = npf_state_inspect(&npc, &nbuf, nst, p->flags == OUT); 158 m_freem(nbuf.nb_mbuf); 159 160 return ret ? true : (p->flags & ERR) != 0; 161} 162 163bool 164npf_state_test(bool verbose) 165{ 166 npf_state_t nst; 167 bool snew = true; 168 bool ok = true; 169 170 for (u_int i = 0; i < __arraycount(packet_sequence); i++) { 171 if (process_packet(i, &nst, &snew)) { 172 continue; 173 } 174 if (verbose) { 175 printf("Failed on packet %d, state dump:\n", i); 176 npf_state_dump(&nst); 177 } 178 ok = false; 179 } 180 return ok; 181} 182