npf_mbuf_subr.c revision 1.6 1 1.3 rmind /* $NetBSD: npf_mbuf_subr.c,v 1.6 2016/12/26 23:05:05 christos Exp $ */
2 1.1 rmind
3 1.1 rmind /*
4 1.1 rmind * NPF testing - helper routines.
5 1.1 rmind *
6 1.1 rmind * Public Domain.
7 1.1 rmind */
8 1.1 rmind
9 1.6 christos #ifdef _KERNEL
10 1.1 rmind #include <sys/types.h>
11 1.1 rmind #include <sys/kmem.h>
12 1.6 christos #endif
13 1.1 rmind
14 1.1 rmind #include "npf_impl.h"
15 1.1 rmind #include "npf_test.h"
16 1.1 rmind
17 1.6 christos
18 1.6 christos #if defined(_NPF_STANDALONE)
19 1.6 christos struct mbuf *
20 1.6 christos npfkern_m_get(int flags, int space)
21 1.6 christos {
22 1.6 christos unsigned mlen = offsetof(struct mbuf, m_data0[space]);
23 1.6 christos struct mbuf *m;
24 1.6 christos
25 1.6 christos m = calloc(1, sizeof(struct mbuf));
26 1.6 christos if (m) {
27 1.6 christos m->m_type = 1;
28 1.6 christos m->m_flags = flags;
29 1.6 christos m->m_data = m->m_data0;
30 1.6 christos }
31 1.6 christos return m;
32 1.6 christos }
33 1.6 christos #else
34 1.6 christos struct mbuf *
35 1.6 christos npfkern_m_get(int flags, int space)
36 1.6 christos {
37 1.6 christos return m_get(flags, space);
38 1.6 christos }
39 1.6 christos #endif
40 1.6 christos
41 1.6 christos static void *
42 1.6 christos npfkern_m_getdata(const struct mbuf *m)
43 1.6 christos {
44 1.6 christos return m->m_data;
45 1.6 christos }
46 1.6 christos
47 1.6 christos static struct mbuf *
48 1.6 christos npfkern_m_next(struct mbuf *m)
49 1.6 christos {
50 1.6 christos return m->m_next;
51 1.6 christos }
52 1.6 christos
53 1.6 christos static size_t
54 1.6 christos npfkern_m_buflen(const struct mbuf *m)
55 1.6 christos {
56 1.6 christos return m->m_len;
57 1.6 christos }
58 1.6 christos
59 1.6 christos size_t
60 1.6 christos npfkern_m_length(const struct mbuf *m)
61 1.6 christos {
62 1.6 christos const struct mbuf *m0;
63 1.6 christos unsigned pktlen = 0;
64 1.6 christos
65 1.6 christos if ((m->m_flags & M_PKTHDR) != 0)
66 1.6 christos return m->m_pkthdr.len;
67 1.6 christos for (m0 = m; m0 != NULL; m0 = m0->m_next)
68 1.6 christos pktlen += m0->m_len;
69 1.6 christos return pktlen;
70 1.6 christos }
71 1.6 christos
72 1.6 christos void
73 1.6 christos npfkern_m_freem(struct mbuf *m)
74 1.6 christos {
75 1.6 christos #ifdef _NPF_STANDALONE
76 1.6 christos struct mbuf *n;
77 1.6 christos
78 1.6 christos do {
79 1.6 christos n = m->m_next;
80 1.6 christos m->m_type = MT_FREE;
81 1.6 christos free(m);
82 1.6 christos m = n;
83 1.6 christos } while (m);
84 1.6 christos #else
85 1.6 christos m_freem(m);
86 1.6 christos #endif
87 1.6 christos }
88 1.6 christos
89 1.6 christos static bool
90 1.6 christos npfkern_m_ensure_contig(struct mbuf **m0, size_t len)
91 1.6 christos {
92 1.6 christos struct mbuf *m1;
93 1.6 christos unsigned tlen;
94 1.6 christos char *dptr;
95 1.6 christos
96 1.6 christos tlen = npfkern_m_length(*m0);
97 1.6 christos if ((m1 = npfkern_m_get(M_PKTHDR, tlen)) == NULL) {
98 1.6 christos return false;
99 1.6 christos }
100 1.6 christos m1->m_pkthdr.len = m1->m_len = tlen;
101 1.6 christos dptr = m1->m_data;
102 1.6 christos for (struct mbuf *m = *m0; m != NULL; m = m->m_next) {
103 1.6 christos memcpy(dptr, m->m_data, m->m_len);
104 1.6 christos dptr += m->m_len;
105 1.6 christos }
106 1.6 christos *m0 = m1;
107 1.6 christos return true;
108 1.6 christos }
109 1.6 christos
110 1.6 christos
111 1.1 rmind struct mbuf *
112 1.2 rmind mbuf_getwithdata(const void *data, size_t len)
113 1.1 rmind {
114 1.1 rmind struct mbuf *m;
115 1.2 rmind void *dst;
116 1.1 rmind
117 1.2 rmind m = m_gethdr(M_WAITOK, MT_HEADER);
118 1.1 rmind assert(m != NULL);
119 1.2 rmind dst = mtod(m, void *);
120 1.2 rmind memcpy(dst, data, len);
121 1.4 rmind m->m_pkthdr.len = len;
122 1.1 rmind m->m_len = len;
123 1.1 rmind return m;
124 1.1 rmind }
125 1.1 rmind
126 1.1 rmind struct mbuf *
127 1.1 rmind mbuf_construct_ether(int proto)
128 1.1 rmind {
129 1.1 rmind struct mbuf *m0, *m1;
130 1.1 rmind struct ether_header *ethdr;
131 1.1 rmind
132 1.1 rmind m0 = m_gethdr(M_WAITOK, MT_HEADER);
133 1.1 rmind ethdr = mtod(m0, struct ether_header *);
134 1.1 rmind ethdr->ether_type = htons(ETHERTYPE_IP);
135 1.4 rmind m0->m_pkthdr.len = sizeof(struct ether_header);
136 1.1 rmind m0->m_len = sizeof(struct ether_header);
137 1.1 rmind
138 1.1 rmind m1 = mbuf_construct(proto);
139 1.1 rmind m0->m_next = m1;
140 1.1 rmind m1->m_next = NULL;
141 1.1 rmind return m0;
142 1.1 rmind }
143 1.1 rmind
144 1.3 rmind static int
145 1.3 rmind mbuf_fill_proto(int proto, void *l4data)
146 1.3 rmind {
147 1.3 rmind struct tcphdr *th;
148 1.3 rmind int size = 0;
149 1.3 rmind
150 1.3 rmind switch (proto) {
151 1.3 rmind case IPPROTO_TCP:
152 1.3 rmind th = l4data;
153 1.3 rmind th->th_off = sizeof(struct tcphdr) >> 2;
154 1.3 rmind size = sizeof(struct tcphdr);
155 1.3 rmind break;
156 1.3 rmind case IPPROTO_UDP:
157 1.3 rmind size = sizeof(struct udphdr);
158 1.3 rmind break;
159 1.3 rmind case IPPROTO_ICMP:
160 1.3 rmind size = offsetof(struct icmp, icmp_data);
161 1.3 rmind break;
162 1.3 rmind }
163 1.3 rmind return size;
164 1.3 rmind }
165 1.3 rmind
166 1.1 rmind struct mbuf *
167 1.1 rmind mbuf_construct(int proto)
168 1.1 rmind {
169 1.1 rmind struct mbuf *m;
170 1.1 rmind struct ip *iphdr;
171 1.3 rmind void *l4data;
172 1.1 rmind int size;
173 1.1 rmind
174 1.1 rmind m = m_gethdr(M_WAITOK, MT_HEADER);
175 1.1 rmind iphdr = mtod(m, struct ip *);
176 1.1 rmind
177 1.1 rmind iphdr->ip_v = IPVERSION;
178 1.1 rmind iphdr->ip_hl = sizeof(struct ip) >> 2;
179 1.1 rmind iphdr->ip_off = 0;
180 1.1 rmind iphdr->ip_ttl = 64;
181 1.1 rmind iphdr->ip_p = proto;
182 1.1 rmind
183 1.1 rmind size = sizeof(struct ip);
184 1.3 rmind l4data = (void *)(iphdr + 1);
185 1.3 rmind size += mbuf_fill_proto(proto, l4data);
186 1.3 rmind iphdr->ip_len = htons(size);
187 1.3 rmind
188 1.4 rmind m->m_pkthdr.len = size;
189 1.3 rmind m->m_len = size;
190 1.3 rmind m->m_next = NULL;
191 1.3 rmind return m;
192 1.3 rmind }
193 1.3 rmind
194 1.3 rmind struct mbuf *
195 1.3 rmind mbuf_construct6(int proto)
196 1.3 rmind {
197 1.3 rmind struct mbuf *m;
198 1.3 rmind struct ip6_hdr *ip6;
199 1.3 rmind void *l4data;
200 1.3 rmind int size;
201 1.1 rmind
202 1.3 rmind m = m_gethdr(M_WAITOK, MT_HEADER);
203 1.3 rmind ip6 = mtod(m, struct ip6_hdr *);
204 1.3 rmind
205 1.3 rmind ip6->ip6_vfc = IPV6_VERSION;
206 1.3 rmind ip6->ip6_nxt = proto;
207 1.3 rmind ip6->ip6_hlim = 64;
208 1.3 rmind
209 1.3 rmind size = sizeof(struct ip6_hdr);
210 1.3 rmind l4data = (void *)(ip6 + 1);
211 1.3 rmind size += mbuf_fill_proto(proto, l4data);
212 1.3 rmind ip6->ip6_plen = htons(size);
213 1.1 rmind
214 1.4 rmind m->m_pkthdr.len = size;
215 1.1 rmind m->m_len = size;
216 1.1 rmind m->m_next = NULL;
217 1.1 rmind return m;
218 1.1 rmind }
219 1.1 rmind
220 1.1 rmind void *
221 1.1 rmind mbuf_return_hdrs(struct mbuf *m, bool ether, struct ip **ip)
222 1.1 rmind {
223 1.1 rmind struct ip *iphdr;
224 1.1 rmind
225 1.1 rmind if (ether) {
226 1.1 rmind struct mbuf *mn = m->m_next;
227 1.1 rmind iphdr = mtod(mn, struct ip *);
228 1.1 rmind } else {
229 1.1 rmind iphdr = mtod(m, struct ip *);
230 1.1 rmind }
231 1.1 rmind *ip = iphdr;
232 1.1 rmind return (void *)(iphdr + 1);
233 1.1 rmind }
234 1.1 rmind
235 1.5 rmind void *
236 1.5 rmind mbuf_return_hdrs6(struct mbuf *m, struct ip6_hdr **ip6)
237 1.5 rmind {
238 1.5 rmind struct ip6_hdr *ip6hdr = mtod(m, struct ip6_hdr *);
239 1.5 rmind
240 1.5 rmind *ip6 = ip6hdr;
241 1.5 rmind return (void *)(ip6hdr + 1);
242 1.5 rmind }
243 1.5 rmind
244 1.1 rmind void
245 1.1 rmind mbuf_icmp_append(struct mbuf *m, struct mbuf *m_orig)
246 1.1 rmind {
247 1.1 rmind struct ip *iphdr = mtod(m, struct ip *);
248 1.1 rmind const size_t hlen = iphdr->ip_hl << 2;
249 1.1 rmind struct icmp *ic = (struct icmp *)((uint8_t *)iphdr + hlen);
250 1.4 rmind const size_t addlen = m_length(m_orig);
251 1.1 rmind
252 1.1 rmind iphdr->ip_len = htons(ntohs(iphdr->ip_len) + addlen);
253 1.1 rmind memcpy(&ic->icmp_ip, mtod(m_orig, struct ip *), addlen);
254 1.4 rmind m->m_pkthdr.len += addlen;
255 1.1 rmind m->m_len += addlen;
256 1.1 rmind m_freem(m_orig);
257 1.1 rmind }
258 1.6 christos
259 1.6 christos const npf_mbufops_t npftest_mbufops = {
260 1.6 christos .alloc = npfkern_m_get,
261 1.6 christos .free = npfkern_m_freem,
262 1.6 christos .getdata = npfkern_m_getdata,
263 1.6 christos .getnext = npfkern_m_next,
264 1.6 christos .getlen = npfkern_m_buflen,
265 1.6 christos .getchainlen = npfkern_m_length,
266 1.6 christos .ensure_contig = npfkern_m_ensure_contig,
267 1.6 christos .ensure_writable = NULL,
268 1.6 christos };
269