Home | History | Annotate | Line # | Download | only in libnpftest
      1 /*
      2  * NPF testing - helper routines.
      3  *
      4  * Public Domain.
      5  */
      6 
      7 #ifdef _KERNEL
      8 #include <sys/types.h>
      9 #include <sys/kmem.h>
     10 #include <net/if_ether.h>
     11 #endif
     12 
     13 #include "npf_impl.h"
     14 #include "npf_test.h"
     15 
     16 
     17 #if defined(_NPF_STANDALONE)
     18 struct mbuf *
     19 npfkern_m_get(npf_t *npf __unused, unsigned flags, size_t space)
     20 {
     21 	unsigned mlen = offsetof(struct mbuf, m_data0[space]);
     22 	struct mbuf *m;
     23 
     24 	m = calloc(1, mlen);
     25 	if (m) {
     26 		m->m_type = 1;
     27 		m->m_flags = flags;
     28 		m->m_data = m->m_data0;
     29 	}
     30 	return m;
     31 }
     32 #else
     33 struct mbuf *
     34 npfkern_m_get(npf_t *npf __unused, unsigned flags, size_t space)
     35 {
     36 	return m_get(flags, space);
     37 }
     38 #endif
     39 
     40 static void *
     41 npfkern_m_getdata(const struct mbuf *m)
     42 {
     43 	return m->m_data;
     44 }
     45 
     46 static struct mbuf *
     47 npfkern_m_next(struct mbuf *m)
     48 {
     49 	return m->m_next;
     50 }
     51 
     52 static size_t
     53 npfkern_m_buflen(const struct mbuf *m)
     54 {
     55 	return m->m_len;
     56 }
     57 
     58 size_t
     59 npfkern_m_length(const struct mbuf *m)
     60 {
     61 	const struct mbuf *m0;
     62 	unsigned pktlen = 0;
     63 
     64 	if ((m->m_flags & M_PKTHDR) != 0)
     65 		return m->m_pkthdr.len;
     66 	for (m0 = m; m0 != NULL; m0 = m0->m_next)
     67 		pktlen += m0->m_len;
     68 	return pktlen;
     69 }
     70 
     71 void
     72 npfkern_m_freem(struct mbuf *m)
     73 {
     74 #ifdef _NPF_STANDALONE
     75 	struct mbuf *n;
     76 
     77 	do {
     78 		n = m->m_next;
     79 		m->m_type = MT_FREE;
     80 		free(m);
     81 		m = n;
     82 	} while (m);
     83 #else
     84 	m_freem(m);
     85 #endif
     86 }
     87 
     88 static bool
     89 npfkern_m_ensure_contig(struct mbuf **m0, size_t len)
     90 {
     91 	struct mbuf *m1;
     92 	unsigned tlen;
     93 	char *dptr;
     94 
     95 	tlen = npfkern_m_length(*m0);
     96 	if ((m1 = npfkern_m_get(NULL, M_PKTHDR, tlen)) == NULL) {
     97 		return false;
     98 	}
     99 	m1->m_pkthdr.len = m1->m_len = tlen;
    100 	dptr = m1->m_data;
    101 	for (struct mbuf *m = *m0; m != NULL; m = m->m_next) {
    102 		memcpy(dptr, m->m_data, m->m_len);
    103 		dptr += m->m_len;
    104 	}
    105 	npfkern_m_freem(*m0);
    106 	*m0 = m1;
    107 	(void)len;
    108 	return true;
    109 }
    110 
    111 
    112 struct mbuf *
    113 mbuf_getwithdata(const void *data, size_t len)
    114 {
    115 	struct mbuf *m;
    116 	void *dst;
    117 
    118 	m = m_gethdr(M_WAITOK, MT_HEADER);
    119 	assert(m != NULL);
    120 	dst = mtod(m, void *);
    121 	memcpy(dst, data, len);
    122 	m->m_pkthdr.len = len;
    123 	m->m_len = len;
    124 	return m;
    125 }
    126 
    127 struct mbuf *
    128 mbuf_construct_ether(int proto)
    129 {
    130 	struct mbuf *m0, *m1;
    131 	struct ether_header *ethdr;
    132 
    133 	m0 = m_gethdr(M_WAITOK, MT_HEADER);
    134 	ethdr = mtod(m0, struct ether_header *);
    135 	ethdr->ether_type = htons(ETHERTYPE_IP);
    136 	m0->m_pkthdr.len = sizeof(struct ether_header);
    137 	m0->m_len = sizeof(struct ether_header);
    138 
    139 	m1 = mbuf_construct(proto);
    140 	m0->m_next = m1;
    141 	m1->m_next = NULL;
    142 	return m0;
    143 }
    144 
    145 static int
    146 mbuf_fill_proto(int proto, void *l4data)
    147 {
    148 	struct tcphdr *th;
    149 	int size = 0;
    150 
    151 	switch (proto) {
    152 	case IPPROTO_TCP:
    153 		th = l4data;
    154 		th->th_off = sizeof(struct tcphdr) >> 2;
    155 		size = sizeof(struct tcphdr);
    156 		break;
    157 	case IPPROTO_UDP:
    158 		size = sizeof(struct udphdr);
    159 		break;
    160 	case IPPROTO_ICMP:
    161 		size = offsetof(struct icmp, icmp_data);
    162 		break;
    163 	}
    164 	return size;
    165 }
    166 
    167 struct mbuf *
    168 mbuf_construct(int proto)
    169 {
    170 	struct mbuf *m;
    171 	struct ip *iphdr;
    172 	void *l4data;
    173 	int size;
    174 
    175 	m = m_gethdr(M_WAITOK, MT_HEADER);
    176 	iphdr = mtod(m, struct ip *);
    177 
    178 	iphdr->ip_v = IPVERSION;
    179 	iphdr->ip_hl = sizeof(struct ip) >> 2;
    180 	iphdr->ip_off = 0;
    181 	iphdr->ip_ttl = 64;
    182 	iphdr->ip_p = proto;
    183 
    184 	size = sizeof(struct ip);
    185 	l4data = (void *)(iphdr + 1);
    186 	size += mbuf_fill_proto(proto, l4data);
    187 	iphdr->ip_len = htons(size);
    188 
    189 	m->m_pkthdr.len = size;
    190 	m->m_len = size;
    191 	m->m_next = NULL;
    192 	return m;
    193 }
    194 
    195 struct mbuf *
    196 mbuf_construct6(int proto)
    197 {
    198 	struct mbuf *m;
    199 	struct ip6_hdr *ip6;
    200 	void *l4data;
    201 	int size;
    202 
    203 	m = m_gethdr(M_WAITOK, MT_HEADER);
    204 	ip6 = mtod(m, struct ip6_hdr *);
    205 
    206 	ip6->ip6_vfc = IPV6_VERSION;
    207 	ip6->ip6_nxt = proto;
    208 	ip6->ip6_hlim = 64;
    209 
    210 	size = sizeof(struct ip6_hdr);
    211 	l4data = (void *)(ip6 + 1);
    212 	size += mbuf_fill_proto(proto, l4data);
    213 	ip6->ip6_plen = htons(size);
    214 
    215 	m->m_pkthdr.len = size;
    216 	m->m_len = size;
    217 	m->m_next = NULL;
    218 	return m;
    219 }
    220 
    221 void *
    222 mbuf_return_hdrs(struct mbuf *m, bool ether, struct ip **ip)
    223 {
    224 	struct ip *iphdr;
    225 
    226 	if (ether) {
    227 		struct mbuf *mn = m->m_next;
    228 		iphdr = mtod(mn, struct ip *);
    229 	} else {
    230 		iphdr = mtod(m, struct ip *);
    231 	}
    232 	*ip = iphdr;
    233 	return (void *)(iphdr + 1);
    234 }
    235 
    236 void *
    237 mbuf_return_hdrs6(struct mbuf *m, struct ip6_hdr **ip6)
    238 {
    239 	struct ip6_hdr *ip6hdr = mtod(m, struct ip6_hdr *);
    240 
    241 	*ip6 = ip6hdr;
    242 	return (void *)(ip6hdr + 1);
    243 }
    244 
    245 void
    246 mbuf_icmp_append(struct mbuf *m, struct mbuf *m_orig)
    247 {
    248 	struct ip *iphdr = mtod(m, struct ip *);
    249 	const size_t hlen = iphdr->ip_hl << 2;
    250 	void *p = (uint8_t *)iphdr + hlen;
    251 	struct icmp *ic = (struct icmp *)p;
    252 	const size_t addlen = m_length(m_orig);
    253 
    254 	iphdr->ip_len = htons(ntohs(iphdr->ip_len) + addlen);
    255 	memcpy(&ic->icmp_ip, mtod(m_orig, struct ip *), addlen);
    256 	m->m_pkthdr.len += addlen;
    257 	m->m_len += addlen;
    258 	m_freem(m_orig);
    259 }
    260 
    261 struct mbuf *
    262 mbuf_get_pkt(int af, int proto, const char *src, const char *dst,
    263     int sport, int dport)
    264 {
    265 	struct mbuf *m;
    266 	struct ip *ip;
    267 	struct ip6_hdr *ip6;
    268 	struct tcphdr *th;
    269 	struct udphdr *uh;
    270 	void *p, *ipsrc, *ipdst;
    271 
    272 	switch (af) {
    273 	case AF_INET6:
    274 		m = mbuf_construct6(proto);
    275 		p = mbuf_return_hdrs6(m, &ip6);
    276 		ipsrc = &ip6->ip6_src;
    277 		ipdst = &ip6->ip6_dst;
    278 		break;
    279 	case AF_INET:
    280 	default:
    281 		m = mbuf_construct(proto);
    282 		p = mbuf_return_hdrs(m, false, &ip);
    283 		ipsrc = &ip->ip_src.s_addr;
    284 		ipdst = &ip->ip_dst.s_addr;
    285 	}
    286 
    287 	npf_inet_pton(af, src, ipsrc);
    288 	npf_inet_pton(af, dst, ipdst);
    289 
    290 	switch (proto) {
    291 	case IPPROTO_TCP:
    292 		th = p;
    293 		th->th_sport = htons(sport);
    294 		th->th_dport = htons(dport);
    295 		break;
    296 	case IPPROTO_UDP:
    297 		uh = p;
    298 		uh->uh_sport = htons(sport);
    299 		uh->uh_dport = htons(dport);
    300 		break;
    301 	default:
    302 		KASSERT(false);
    303 	}
    304 	return m;
    305 }
    306 
    307 struct mbuf *
    308 mbuf_get_frame(const char *src, const char *dst, uint16_t type)
    309 {
    310 	struct mbuf *m0;
    311 	struct ether_header *ethdr;
    312 
    313 	uint8_t saddr[ETHER_ADDR_LEN];
    314 	uint8_t daddr[ETHER_ADDR_LEN];
    315 
    316 	(void)ether_aton_r(saddr, ETHER_ADDR_LEN, src);
    317 	(void)ether_aton_r(daddr, ETHER_ADDR_LEN, dst);
    318 
    319 	m0 = m_gethdr(M_WAITOK, MT_HEADER);
    320 	ethdr = mtod(m0, struct ether_header *);
    321 	ethdr->ether_type = type;
    322 	memcpy(ethdr->ether_dhost, daddr, sizeof(ethdr->ether_dhost));
    323 	memcpy(ethdr->ether_shost, saddr, sizeof(ethdr->ether_shost));
    324 	m0->m_pkthdr.len = sizeof(struct ether_header);
    325 	m0->m_len = sizeof(struct ether_header);
    326 	m0->m_next = NULL;
    327 
    328 	return m0;
    329 }
    330 
    331 npf_cache_t *
    332 get_cached_pkt(struct mbuf *m, const char *ifname,  uint32_t layer)
    333 {
    334 	ifnet_t *ifp = npf_test_getif(ifname ? ifname : IFNAME_DUMMY);
    335 	npf_cache_t *npc = kmem_zalloc(sizeof(npf_cache_t), KM_SLEEP);
    336 	nbuf_t *nbuf = kmem_zalloc(sizeof(nbuf_t), KM_SLEEP);
    337 	int ret;
    338 
    339 	npc->npc_info = 0;
    340 	npc->npc_ctx = npf_getkernctx();
    341 
    342 	nbuf_init(npc->npc_ctx, nbuf, m, ifp);
    343 	npc->npc_nbuf = nbuf;
    344 
    345 	if (layer & NPF_RULE_LAYER_3)
    346 		ret = npf_cache_all(npc);
    347 	else
    348 		ret = npf_cache_ether(npc);
    349 	assert(ret); (void)ret;
    350 
    351 	return npc;
    352 }
    353 
    354 void
    355 put_cached_pkt(npf_cache_t *npc)
    356 {
    357 	struct mbuf *m = nbuf_head_mbuf(npc->npc_nbuf);
    358 	kmem_free(npc->npc_nbuf, sizeof(nbuf_t));
    359 	kmem_free(npc, sizeof(npf_cache_t));
    360 	m_freem(m);
    361 }
    362 
    363 const npf_mbufops_t npftest_mbufops = {
    364 	.alloc			= npfkern_m_get,
    365 	.free			= npfkern_m_freem,
    366 	.getdata		= npfkern_m_getdata,
    367 	.getnext		= npfkern_m_next,
    368 	.getlen			= npfkern_m_buflen,
    369 	.getchainlen		= npfkern_m_length,
    370 	.ensure_contig		= npfkern_m_ensure_contig,
    371 	.ensure_writable	= NULL,
    372 };
    373