* Copy bytes from a source into the specified zbuf. The caller is * responsible for performing bounds checking, etc. */
| 238 | * responsible for performing bounds checking, etc. |
| 239 | */ |
| 240 | void |
| 241 | bpf_zerocopy_append_bytes(struct bpf_d *d, caddr_t buf, u_int offset, |
| 242 | void *src, u_int len) |
| 243 | { |
| 244 | u_int count, page, poffset; |
| 245 | u_char *src_bytes; |
| 246 | struct zbuf *zb; |
| 247 | |
| 248 | KASSERT(d->bd_bufmode == BPF_BUFMODE_ZBUF, |
| 249 | ("bpf_zerocopy_append_bytes: not in zbuf mode")); |
| 250 | KASSERT(buf != NULL, ("bpf_zerocopy_append_bytes: NULL buf")); |
| 251 | |
| 252 | src_bytes = (u_char *)src; |
| 253 | zb = (struct zbuf *)buf; |
| 254 | |
| 255 | KASSERT((zb->zb_flags & ZBUF_FLAG_ASSIGNED) == 0, |
| 256 | ("bpf_zerocopy_append_bytes: ZBUF_FLAG_ASSIGNED")); |
| 257 | |
| 258 | /* |
| 259 | * Scatter-gather copy to user pages mapped into kernel address space |
| 260 | * using sf_bufs: copy up to a page at a time. |
| 261 | */ |
| 262 | offset += sizeof(struct bpf_zbuf_header); |
| 263 | page = offset / PAGE_SIZE; |
| 264 | poffset = offset % PAGE_SIZE; |
| 265 | while (len > 0) { |
| 266 | KASSERT(page < zb->zb_numpages, ("bpf_zerocopy_append_bytes:" |
| 267 | " page overflow (%d p %d np)\n", page, zb->zb_numpages)); |
| 268 | |
| 269 | count = min(len, PAGE_SIZE - poffset); |
| 270 | bcopy(src_bytes, ((u_char *)sf_buf_kva(zb->zb_pages[page])) + |
| 271 | poffset, count); |
| 272 | poffset += count; |
| 273 | if (poffset == PAGE_SIZE) { |
| 274 | poffset = 0; |
| 275 | page++; |
| 276 | } |
| 277 | KASSERT(poffset < PAGE_SIZE, |
| 278 | ("bpf_zerocopy_append_bytes: page offset overflow (%d)", |
| 279 | poffset)); |
| 280 | len -= count; |
| 281 | src_bytes += count; |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | /* |
| 286 | * Copy bytes from an mbuf chain to the specified zbuf: copying will be |
no test coverage detected