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