1 /* $NetBSD: npf_nbuf_test.c,v 1.6 2016/12/26 23:05:05 christos Exp $ */ 2 3 /* 4 * NPF nbuf interface test. 5 * 6 * Public Domain. 7 */ 8 9 #ifdef _KERNEL 10 #include <sys/types.h> 11 #include <sys/kmem.h> 12 #endif 13 14 #include "npf_impl.h" 15 #include "npf_test.h" 16 17 #define MBUF_CHAIN_LEN 128 18 19 CTASSERT((MBUF_CHAIN_LEN % sizeof(uint32_t)) == 0); 20 21 static void 22 mbuf_consistency_check(nbuf_t *nbuf) 23 { 24 struct mbuf *m = nbuf_head_mbuf(nbuf); 25 26 while (m) { 27 assert(m->m_type != MT_FREE); 28 m = m->m_next; 29 } 30 } 31 32 static char * 33 parse_nbuf_chain(struct mbuf *m) 34 { 35 ifnet_t *dummy_ifp = npf_test_addif(IFNAME_TEST, false, false); 36 char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP); 37 nbuf_t nbuf; 38 void *nptr; 39 int n; 40 41 nbuf_init(npf_getkernctx(), &nbuf, m, dummy_ifp); 42 43 nptr = nbuf_advance(&nbuf, (random() % 16) + 1, (random() % 16) + 1); 44 mbuf_consistency_check(&nbuf); 45 assert(nptr != NULL); 46 nbuf_reset(&nbuf); 47 48 for (n = 0; ; ) { 49 char d[4 + 1]; 50 51 nptr = nbuf_ensure_contig(&nbuf, sizeof(uint32_t)); 52 if (nptr == NULL) { 53 break; 54 } 55 mbuf_consistency_check(&nbuf); 56 memcpy(&d, nptr, sizeof(uint32_t)); 57 58 d[sizeof(d) - 1] = '\0'; 59 strcat(s, d); 60 61 if (n + sizeof(uint32_t) == MBUF_CHAIN_LEN) { 62 assert(nbuf_advance(&nbuf, sizeof(uint32_t) - 1, 0)); 63 assert(!nbuf_advance(&nbuf, 1, 0)); 64 break; 65 } 66 if (!nbuf_advance(&nbuf, sizeof(uint32_t), 0)) { 67 break; 68 } 69 n += sizeof(uint32_t); 70 } 71 mbuf_consistency_check(&nbuf); 72 return s; 73 } 74 75 static char * 76 mbuf_getstring(struct mbuf *m) 77 { 78 char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP); 79 u_int tlen = 0; 80 81 while (m) { 82 int len = m->m_len; 83 char *d = m->m_data; 84 while (len--) { 85 s[tlen++] = *d++; 86 } 87 m = m->m_next; 88 } 89 return s; 90 } 91 92 static struct mbuf * 93 mbuf_alloc_with_off(size_t off, int len) 94 { 95 struct mbuf *m; 96 97 KASSERT(off + len < MLEN); 98 m = m_get(M_WAITOK, MT_DATA); 99 m->m_data = (char *)m->m_data + off; 100 m->m_len = len; 101 return m; 102 } 103 104 /* 105 * Create an mbuf chain, each of 1 byte size. 106 */ 107 static struct mbuf * 108 mbuf_bytesize(size_t clen) 109 { 110 struct mbuf *m0 = NULL, *m = NULL; 111 u_int i, n; 112 113 /* Chain of clen (e.g. 128) mbufs, each storing 1 byte of data. */ 114 for (i = 0, n = 0; i < clen; i++) { 115 /* Range of offset: 0 .. 15. */ 116 m0 = mbuf_alloc_with_off(n & 0xf, 1); 117 118 /* Fill data with letters from 'a' to 'z'. */ 119 memset(m0->m_data, 'a' + n, 1); 120 n = ('a' + n) < 'z' ? n + 1 : 0; 121 122 /* Next mbuf.. */ 123 m0->m_next = m; 124 m = m0; 125 } 126 127 m0 = m_gethdr(M_WAITOK, MT_HEADER); 128 m0->m_pkthdr.len = clen; 129 m0->m_len = 0; 130 m0->m_next = m; 131 return m0; 132 } 133 134 /* 135 * Generate random amount of mbufs, with random offsets and lengths. 136 */ 137 static struct mbuf * 138 mbuf_random_len(size_t chain_len) 139 { 140 struct mbuf *m0 = NULL, *m = NULL; 141 u_int tlen = 0, n = 0; 142 143 while (tlen < chain_len) { 144 u_int off, len; 145 char *d; 146 147 /* Random offset and length range: 1 .. 16. */ 148 off = (random() % 16) + 1; 149 len = (random() % 16) + 1; 150 151 /* Do not exceed 128 bytes of total length. */ 152 if (tlen + len > chain_len) { 153 len = chain_len - tlen; 154 } 155 tlen += len; 156 157 /* Consistently fill data with letters from 'a' to 'z'. */ 158 m0 = mbuf_alloc_with_off(off, len); 159 d = m0->m_data; 160 while (len--) { 161 *d++ = ('a' + n); 162 n = ('a' + n) < 'z' ? n + 1 : 0; 163 } 164 165 /* Next mbuf.. */ 166 m0->m_next = m; 167 m = m0; 168 } 169 KASSERT(tlen == chain_len); 170 171 m0 = m_gethdr(M_WAITOK, MT_HEADER); 172 m0->m_pkthdr.len = tlen; 173 m0->m_next = m; 174 m0->m_len = 0; 175 return m0; 176 } 177 178 static bool 179 validate_mbuf_data(bool verbose, char *bufa, char *bufb) 180 { 181 bool ret = (strcmp(bufa, bufb) == 0); 182 183 if (verbose) { 184 printf("Buffer A: %s\nBuffer B: %s\n", bufa, bufb); 185 } 186 kmem_free(bufa, MBUF_CHAIN_LEN + 1); 187 kmem_free(bufb, MBUF_CHAIN_LEN + 1); 188 return ret; 189 } 190 191 bool 192 npf_nbuf_test(bool verbose) 193 { 194 struct mbuf *m1, *m2; 195 char *bufa, *bufb; 196 bool fail = false; 197 198 m1 = mbuf_random_len(MBUF_CHAIN_LEN); 199 bufa = mbuf_getstring(m1); 200 bufb = parse_nbuf_chain(m1); 201 fail |= !validate_mbuf_data(verbose, bufa, bufb); 202 203 m2 = mbuf_bytesize(MBUF_CHAIN_LEN); 204 bufa = mbuf_getstring(m2); 205 bufb = parse_nbuf_chain(m2); 206 fail |= !validate_mbuf_data(verbose, bufa, bufb); 207 208 return !fail; 209 } 210