npf_mbuf_subr.c revision 1.7 1 /* $NetBSD: npf_mbuf_subr.c,v 1.7 2018/09/29 14:41:36 rmind Exp $ */
2
3 /*
4 * NPF testing - helper routines.
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
18 #if defined(_NPF_STANDALONE)
19 struct mbuf *
20 npfkern_m_get(int flags, int space)
21 {
22 unsigned mlen = offsetof(struct mbuf, m_data0[space]);
23 struct mbuf *m;
24
25 m = calloc(1, mlen);
26 if (m) {
27 m->m_type = 1;
28 m->m_flags = flags;
29 m->m_data = m->m_data0;
30 }
31 return m;
32 }
33 #else
34 struct mbuf *
35 npfkern_m_get(int flags, int space)
36 {
37 return m_get(flags, space);
38 }
39 #endif
40
41 static void *
42 npfkern_m_getdata(const struct mbuf *m)
43 {
44 return m->m_data;
45 }
46
47 static struct mbuf *
48 npfkern_m_next(struct mbuf *m)
49 {
50 return m->m_next;
51 }
52
53 static size_t
54 npfkern_m_buflen(const struct mbuf *m)
55 {
56 return m->m_len;
57 }
58
59 size_t
60 npfkern_m_length(const struct mbuf *m)
61 {
62 const struct mbuf *m0;
63 unsigned pktlen = 0;
64
65 if ((m->m_flags & M_PKTHDR) != 0)
66 return m->m_pkthdr.len;
67 for (m0 = m; m0 != NULL; m0 = m0->m_next)
68 pktlen += m0->m_len;
69 return pktlen;
70 }
71
72 void
73 npfkern_m_freem(struct mbuf *m)
74 {
75 #ifdef _NPF_STANDALONE
76 struct mbuf *n;
77
78 do {
79 n = m->m_next;
80 m->m_type = MT_FREE;
81 free(m);
82 m = n;
83 } while (m);
84 #else
85 m_freem(m);
86 #endif
87 }
88
89 static bool
90 npfkern_m_ensure_contig(struct mbuf **m0, size_t len)
91 {
92 struct mbuf *m1;
93 unsigned tlen;
94 char *dptr;
95
96 tlen = npfkern_m_length(*m0);
97 if ((m1 = npfkern_m_get(M_PKTHDR, tlen)) == NULL) {
98 return false;
99 }
100 m1->m_pkthdr.len = m1->m_len = tlen;
101 dptr = m1->m_data;
102 for (struct mbuf *m = *m0; m != NULL; m = m->m_next) {
103 memcpy(dptr, m->m_data, m->m_len);
104 dptr += m->m_len;
105 }
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 struct icmp *ic = (struct icmp *)((uint8_t *)iphdr + hlen);
251 const size_t addlen = m_length(m_orig);
252
253 iphdr->ip_len = htons(ntohs(iphdr->ip_len) + addlen);
254 memcpy(&ic->icmp_ip, mtod(m_orig, struct ip *), addlen);
255 m->m_pkthdr.len += addlen;
256 m->m_len += addlen;
257 m_freem(m_orig);
258 }
259
260 const npf_mbufops_t npftest_mbufops = {
261 .alloc = npfkern_m_get,
262 .free = npfkern_m_freem,
263 .getdata = npfkern_m_getdata,
264 .getnext = npfkern_m_next,
265 .getlen = npfkern_m_buflen,
266 .getchainlen = npfkern_m_length,
267 .ensure_contig = npfkern_m_ensure_contig,
268 .ensure_writable = NULL,
269 };
270