19ffbe6bdSrmind /*
23d9a792dSrmind * NPF nbuf interface tests.
39ffbe6bdSrmind *
49ffbe6bdSrmind * Public Domain.
59ffbe6bdSrmind */
69ffbe6bdSrmind
7f75d79ebSchristos #ifdef _KERNEL
89ffbe6bdSrmind #include <sys/types.h>
99ffbe6bdSrmind #include <sys/kmem.h>
10f75d79ebSchristos #endif
119ffbe6bdSrmind
129ffbe6bdSrmind #include "npf_impl.h"
139ffbe6bdSrmind #include "npf_test.h"
149ffbe6bdSrmind
159ffbe6bdSrmind #define MBUF_CHAIN_LEN 128
169ffbe6bdSrmind
179ffbe6bdSrmind CTASSERT((MBUF_CHAIN_LEN % sizeof(uint32_t)) == 0);
189ffbe6bdSrmind
193107fd1eSrmind static void
mbuf_consistency_check(nbuf_t * nbuf)203107fd1eSrmind mbuf_consistency_check(nbuf_t *nbuf)
213107fd1eSrmind {
223107fd1eSrmind struct mbuf *m = nbuf_head_mbuf(nbuf);
233107fd1eSrmind
243107fd1eSrmind while (m) {
253107fd1eSrmind assert(m->m_type != MT_FREE);
263107fd1eSrmind m = m->m_next;
273107fd1eSrmind }
283107fd1eSrmind }
293107fd1eSrmind
309ffbe6bdSrmind static char *
parse_nbuf_chain(struct mbuf * m)31352f1606Srmind parse_nbuf_chain(struct mbuf *m)
329ffbe6bdSrmind {
33a79812eaSrmind ifnet_t *dummy_ifp = npf_test_addif(IFNAME_TEST, false, false);
349ffbe6bdSrmind char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP);
35352f1606Srmind nbuf_t nbuf;
363107fd1eSrmind void *nptr;
37352f1606Srmind int n;
389ffbe6bdSrmind
39f75d79ebSchristos nbuf_init(npf_getkernctx(), &nbuf, m, dummy_ifp);
403107fd1eSrmind
413107fd1eSrmind nptr = nbuf_advance(&nbuf, (random() % 16) + 1, (random() % 16) + 1);
423107fd1eSrmind mbuf_consistency_check(&nbuf);
433107fd1eSrmind assert(nptr != NULL);
443107fd1eSrmind nbuf_reset(&nbuf);
453107fd1eSrmind
469ffbe6bdSrmind for (n = 0; ; ) {
479ffbe6bdSrmind char d[4 + 1];
489ffbe6bdSrmind
49352f1606Srmind nptr = nbuf_ensure_contig(&nbuf, sizeof(uint32_t));
50352f1606Srmind if (nptr == NULL) {
51352f1606Srmind break;
529ffbe6bdSrmind }
533107fd1eSrmind mbuf_consistency_check(&nbuf);
54352f1606Srmind memcpy(&d, nptr, sizeof(uint32_t));
55352f1606Srmind
569ffbe6bdSrmind d[sizeof(d) - 1] = '\0';
579ffbe6bdSrmind strcat(s, d);
589ffbe6bdSrmind
599ffbe6bdSrmind if (n + sizeof(uint32_t) == MBUF_CHAIN_LEN) {
60352f1606Srmind assert(nbuf_advance(&nbuf, sizeof(uint32_t) - 1, 0));
61352f1606Srmind assert(!nbuf_advance(&nbuf, 1, 0));
629ffbe6bdSrmind break;
639ffbe6bdSrmind }
64352f1606Srmind if (!nbuf_advance(&nbuf, sizeof(uint32_t), 0)) {
65352f1606Srmind break;
669ffbe6bdSrmind }
679ffbe6bdSrmind n += sizeof(uint32_t);
689ffbe6bdSrmind }
693107fd1eSrmind mbuf_consistency_check(&nbuf);
70dadc88e3Srmind m_freem(nbuf_head_mbuf(&nbuf));
719ffbe6bdSrmind return s;
729ffbe6bdSrmind }
739ffbe6bdSrmind
749ffbe6bdSrmind static char *
mbuf_getstring(struct mbuf * m)759ffbe6bdSrmind mbuf_getstring(struct mbuf *m)
769ffbe6bdSrmind {
779ffbe6bdSrmind char *s = kmem_zalloc(MBUF_CHAIN_LEN + 1, KM_SLEEP);
78dadc88e3Srmind unsigned tlen = 0;
799ffbe6bdSrmind
809ffbe6bdSrmind while (m) {
819ffbe6bdSrmind int len = m->m_len;
829ffbe6bdSrmind char *d = m->m_data;
839ffbe6bdSrmind while (len--) {
849ffbe6bdSrmind s[tlen++] = *d++;
859ffbe6bdSrmind }
869ffbe6bdSrmind m = m->m_next;
879ffbe6bdSrmind }
889ffbe6bdSrmind return s;
899ffbe6bdSrmind }
909ffbe6bdSrmind
919ffbe6bdSrmind static struct mbuf *
mbuf_alloc_with_off(size_t off,int len)929ffbe6bdSrmind mbuf_alloc_with_off(size_t off, int len)
939ffbe6bdSrmind {
949ffbe6bdSrmind struct mbuf *m;
959ffbe6bdSrmind
96352f1606Srmind KASSERT(off + len < MLEN);
97352f1606Srmind m = m_get(M_WAITOK, MT_DATA);
98352f1606Srmind m->m_data = (char *)m->m_data + off;
999ffbe6bdSrmind m->m_len = len;
1009ffbe6bdSrmind return m;
1019ffbe6bdSrmind }
1029ffbe6bdSrmind
1039ffbe6bdSrmind /*
1049ffbe6bdSrmind * Create an mbuf chain, each of 1 byte size.
1059ffbe6bdSrmind */
1069ffbe6bdSrmind static struct mbuf *
mbuf_bytesize(size_t clen)1079ffbe6bdSrmind mbuf_bytesize(size_t clen)
1089ffbe6bdSrmind {
1099ffbe6bdSrmind struct mbuf *m0 = NULL, *m = NULL;
110dadc88e3Srmind unsigned i, n;
1119ffbe6bdSrmind
1129ffbe6bdSrmind /* Chain of clen (e.g. 128) mbufs, each storing 1 byte of data. */
1139ffbe6bdSrmind for (i = 0, n = 0; i < clen; i++) {
1149ffbe6bdSrmind /* Range of offset: 0 .. 15. */
1159ffbe6bdSrmind m0 = mbuf_alloc_with_off(n & 0xf, 1);
1169ffbe6bdSrmind
1179ffbe6bdSrmind /* Fill data with letters from 'a' to 'z'. */
1189ffbe6bdSrmind memset(m0->m_data, 'a' + n, 1);
119352f1606Srmind n = ('a' + n) < 'z' ? n + 1 : 0;
1209ffbe6bdSrmind
1219ffbe6bdSrmind /* Next mbuf.. */
1229ffbe6bdSrmind m0->m_next = m;
1239ffbe6bdSrmind m = m0;
1249ffbe6bdSrmind }
125352f1606Srmind
126352f1606Srmind m0 = m_gethdr(M_WAITOK, MT_HEADER);
127352f1606Srmind m0->m_pkthdr.len = clen;
128352f1606Srmind m0->m_len = 0;
129352f1606Srmind m0->m_next = m;
1309ffbe6bdSrmind return m0;
1319ffbe6bdSrmind }
1329ffbe6bdSrmind
1339ffbe6bdSrmind /*
134dadc88e3Srmind * Generate random number of mbufs, with random offsets and lengths.
1359ffbe6bdSrmind */
1369ffbe6bdSrmind static struct mbuf *
mbuf_random_len(size_t chain_len)1379ffbe6bdSrmind mbuf_random_len(size_t chain_len)
1389ffbe6bdSrmind {
1399ffbe6bdSrmind struct mbuf *m0 = NULL, *m = NULL;
140dadc88e3Srmind unsigned tlen = 0, n = 0;
1419ffbe6bdSrmind
1429ffbe6bdSrmind while (tlen < chain_len) {
143dadc88e3Srmind unsigned off, len;
1449ffbe6bdSrmind char *d;
1459ffbe6bdSrmind
1469ffbe6bdSrmind /* Random offset and length range: 1 .. 16. */
1479ffbe6bdSrmind off = (random() % 16) + 1;
1489ffbe6bdSrmind len = (random() % 16) + 1;
1499ffbe6bdSrmind
1509ffbe6bdSrmind /* Do not exceed 128 bytes of total length. */
1519ffbe6bdSrmind if (tlen + len > chain_len) {
1529ffbe6bdSrmind len = chain_len - tlen;
1539ffbe6bdSrmind }
1549ffbe6bdSrmind tlen += len;
1559ffbe6bdSrmind
1569ffbe6bdSrmind /* Consistently fill data with letters from 'a' to 'z'. */
1579ffbe6bdSrmind m0 = mbuf_alloc_with_off(off, len);
1589ffbe6bdSrmind d = m0->m_data;
1599ffbe6bdSrmind while (len--) {
1609ffbe6bdSrmind *d++ = ('a' + n);
161352f1606Srmind n = ('a' + n) < 'z' ? n + 1 : 0;
1629ffbe6bdSrmind }
1639ffbe6bdSrmind
1649ffbe6bdSrmind /* Next mbuf.. */
1659ffbe6bdSrmind m0->m_next = m;
1669ffbe6bdSrmind m = m0;
1679ffbe6bdSrmind }
168352f1606Srmind KASSERT(tlen == chain_len);
169352f1606Srmind
170352f1606Srmind m0 = m_gethdr(M_WAITOK, MT_HEADER);
171352f1606Srmind m0->m_pkthdr.len = tlen;
172352f1606Srmind m0->m_next = m;
173352f1606Srmind m0->m_len = 0;
1749ffbe6bdSrmind return m0;
1759ffbe6bdSrmind }
1769ffbe6bdSrmind
1779ffbe6bdSrmind static bool
validate_mbuf_data(char * bufa,char * bufb)178dadc88e3Srmind validate_mbuf_data(char *bufa, char *bufb)
1799ffbe6bdSrmind {
180dadc88e3Srmind bool ok = strcmp(bufa, bufb) == 0;
1819ffbe6bdSrmind
182dadc88e3Srmind if (!ok) {
1839ffbe6bdSrmind printf("Buffer A: %s\nBuffer B: %s\n", bufa, bufb);
1849ffbe6bdSrmind }
1859ffbe6bdSrmind kmem_free(bufa, MBUF_CHAIN_LEN + 1);
1869ffbe6bdSrmind kmem_free(bufb, MBUF_CHAIN_LEN + 1);
187dadc88e3Srmind return ok;
1889ffbe6bdSrmind }
1899ffbe6bdSrmind
1909ffbe6bdSrmind bool
npf_nbuf_test(bool verbose)1919ffbe6bdSrmind npf_nbuf_test(bool verbose)
1929ffbe6bdSrmind {
193*f916b9b1Srmind struct mbuf *m;
1949ffbe6bdSrmind char *bufa, *bufb;
195dadc88e3Srmind unsigned n = 10000;
196dadc88e3Srmind bool ok;
1979ffbe6bdSrmind
198dadc88e3Srmind while (n--) {
199*f916b9b1Srmind m = mbuf_random_len(MBUF_CHAIN_LEN);
200*f916b9b1Srmind bufa = mbuf_getstring(m);
201*f916b9b1Srmind bufb = parse_nbuf_chain(m);
202dadc88e3Srmind ok = validate_mbuf_data(bufa, bufb);
203dadc88e3Srmind CHECK_TRUE(ok);
204dadc88e3Srmind }
2059ffbe6bdSrmind
206*f916b9b1Srmind m = mbuf_bytesize(MBUF_CHAIN_LEN);
207*f916b9b1Srmind bufa = mbuf_getstring(m);
208*f916b9b1Srmind bufb = parse_nbuf_chain(m);
209dadc88e3Srmind ok = validate_mbuf_data(bufa, bufb);
210dadc88e3Srmind CHECK_TRUE(ok);
2119ffbe6bdSrmind
212dadc88e3Srmind (void)verbose;
213dadc88e3Srmind return true;
2149ffbe6bdSrmind }
215