]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_mbuf.c
xnu-1699.32.7.tar.gz
[apple/xnu.git] / bsd / kern / kpi_mbuf.c
CommitLineData
91447636 1/*
6d2010ae 2 * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28
29#define __KPI__
30//#include <sys/kpi_interface.h>
31
32#include <sys/param.h>
33#include <sys/mbuf.h>
34#include <sys/socket.h>
35#include <kern/debug.h>
36#include <libkern/OSAtomic.h>
37#include <kern/kalloc.h>
38#include <string.h>
2d21ac55 39#include <netinet/in.h>
b0d623f7
A
40
41#include "net/net_str_id.h"
91447636 42
6d2010ae
A
43static const mbuf_flags_t mbuf_flags_mask = (MBUF_EXT | MBUF_PKTHDR | MBUF_EOR |
44 MBUF_LOOP | MBUF_BCAST | MBUF_MCAST | MBUF_FRAG | MBUF_FIRSTFRAG |
45 MBUF_LASTFRAG | MBUF_PROMISC | MBUF_HASFCS);
91447636
A
46
47void* mbuf_data(mbuf_t mbuf)
48{
2d21ac55 49 return mbuf->m_data;
91447636
A
50}
51
52void* mbuf_datastart(mbuf_t mbuf)
53{
54 if (mbuf->m_flags & M_EXT)
55 return mbuf->m_ext.ext_buf;
56 if (mbuf->m_flags & M_PKTHDR)
57 return mbuf->m_pktdat;
58 return mbuf->m_dat;
59}
60
61errno_t mbuf_setdata(mbuf_t mbuf, void* data, size_t len)
62{
63 size_t start = (size_t)((char*)mbuf_datastart(mbuf));
64 size_t maxlen = mbuf_maxlen(mbuf);
65
66 if ((size_t)data < start || ((size_t)data) + len > start + maxlen)
67 return EINVAL;
68 mbuf->m_data = data;
69 mbuf->m_len = len;
70
71 return 0;
72}
73
74errno_t mbuf_align_32(mbuf_t mbuf, size_t len)
75{
76 if ((mbuf->m_flags & M_EXT) != 0 && m_mclhasreference(mbuf))
77 return ENOTSUP;
78 mbuf->m_data = mbuf_datastart(mbuf);
79 mbuf->m_data += ((mbuf_trailingspace(mbuf) - len) &~ (sizeof(u_int32_t) - 1));
80
81 return 0;
82}
83
6d2010ae
A
84/* This function is used to provide mcl_to_paddr via symbol indirection,
85 * please avoid any change in behavior or remove the indirection in
86 * config/Unsupported*
87 */
91447636
A
88addr64_t mbuf_data_to_physical(void* ptr)
89{
0b4c1975 90 return (addr64_t)(uintptr_t)mcl_to_paddr(ptr);
91447636
A
91}
92
93errno_t mbuf_get(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf)
94{
95 /* Must set *mbuf to NULL in failure case */
96 *mbuf = m_get(how, type);
97
98 return (*mbuf == NULL) ? ENOMEM : 0;
99}
100
101errno_t mbuf_gethdr(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf)
102{
103 /* Must set *mbuf to NULL in failure case */
104 *mbuf = m_gethdr(how, type);
105
106 return (*mbuf == NULL) ? ENOMEM : 0;
107}
108
2d21ac55
A
109errno_t
110mbuf_attachcluster(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf,
111 caddr_t extbuf, void (*extfree)(caddr_t , u_int, caddr_t),
112 size_t extsize, caddr_t extarg)
113{
6d2010ae 114 if (mbuf == NULL || extbuf == NULL || extfree == NULL || extsize == 0)
2d21ac55
A
115 return (EINVAL);
116
6d2010ae 117 if ((*mbuf = m_clattach(*mbuf, type, extbuf,
2d21ac55
A
118 extfree, extsize, extarg, how)) == NULL)
119 return (ENOMEM);
120
121 return (0);
122}
91447636 123
2d21ac55
A
124errno_t
125mbuf_alloccluster(mbuf_how_t how, size_t *size, caddr_t *addr)
126{
127 if (size == NULL || *size == 0 || addr == NULL)
128 return (EINVAL);
129
130 *addr = NULL;
131
132 /* Jumbo cluster pool not available? */
6d2010ae 133 if (*size > MBIGCLBYTES && njcl == 0)
2d21ac55
A
134 return (ENOTSUP);
135
136 if (*size <= MCLBYTES && (*addr = m_mclalloc(how)) != NULL)
137 *size = MCLBYTES;
6d2010ae 138 else if (*size > MCLBYTES && *size <= MBIGCLBYTES &&
2d21ac55 139 (*addr = m_bigalloc(how)) != NULL)
6d2010ae
A
140 *size = MBIGCLBYTES;
141 else if (*size > MBIGCLBYTES && *size <= M16KCLBYTES &&
2d21ac55
A
142 (*addr = m_16kalloc(how)) != NULL)
143 *size = M16KCLBYTES;
144 else
145 *size = 0;
146
147 if (*addr == NULL)
148 return (ENOMEM);
149
150 return (0);
151}
152
153void
154mbuf_freecluster(caddr_t addr, size_t size)
155{
6d2010ae 156 if (size != MCLBYTES && size != MBIGCLBYTES && size != M16KCLBYTES)
2d21ac55
A
157 panic("%s: invalid size (%ld) for cluster %p", __func__,
158 size, (void *)addr);
159
160 if (size == MCLBYTES)
161 m_mclfree(addr);
6d2010ae
A
162 else if (size == MBIGCLBYTES)
163 m_bigfree(addr, MBIGCLBYTES, NULL);
2d21ac55
A
164 else if (njcl > 0)
165 m_16kfree(addr, M16KCLBYTES, NULL);
166 else
167 panic("%s: freeing jumbo cluster to an empty pool", __func__);
168}
169
170errno_t
171mbuf_getcluster(mbuf_how_t how, mbuf_type_t type, size_t size, mbuf_t* mbuf)
91447636
A
172{
173 /* Must set *mbuf to NULL in failure case */
174 errno_t error = 0;
2d21ac55 175 int created = 0;
91447636
A
176
177 if (mbuf == NULL)
178 return EINVAL;
179 if (*mbuf == NULL) {
180 *mbuf = m_get(how, type);
181 if (*mbuf == NULL)
182 return ENOMEM;
183 created = 1;
184 }
185 /*
2d21ac55
A
186 * At the time this code was written, m_{mclget,mbigget,m16kget}
187 * would always return the same value that was passed in to it.
91447636
A
188 */
189 if (size == MCLBYTES) {
190 *mbuf = m_mclget(*mbuf, how);
6d2010ae 191 } else if (size == MBIGCLBYTES) {
91447636 192 *mbuf = m_mbigget(*mbuf, how);
2d21ac55
A
193 } else if (size == M16KCLBYTES) {
194 if (njcl > 0) {
195 *mbuf = m_m16kget(*mbuf, how);
196 } else {
197 /* Jumbo cluster pool not available? */
198 error = ENOTSUP;
199 goto out;
200 }
91447636
A
201 } else {
202 error = EINVAL;
203 goto out;
204 }
205 if (*mbuf == NULL || ((*mbuf)->m_flags & M_EXT) == 0)
206 error = ENOMEM;
207out:
208 if (created && error != 0) {
91447636
A
209 mbuf_free(*mbuf);
210 *mbuf = NULL;
211 }
212 return error;
213}
214
215errno_t mbuf_mclget(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf)
216{
217 /* Must set *mbuf to NULL in failure case */
218 errno_t error = 0;
219 int created = 0;
220 if (mbuf == NULL) return EINVAL;
221 if (*mbuf == NULL) {
222 error = mbuf_get(how, type, mbuf);
223 if (error)
224 return error;
225 created = 1;
226 }
227
228 /*
229 * At the time this code was written, m_mclget would always
230 * return the same value that was passed in to it.
231 */
232 *mbuf = m_mclget(*mbuf, how);
233
234 if (created && ((*mbuf)->m_flags & M_EXT) == 0) {
235 mbuf_free(*mbuf);
236 *mbuf = NULL;
237 }
238 if (*mbuf == NULL || ((*mbuf)->m_flags & M_EXT) == 0)
239 error = ENOMEM;
240 return error;
241}
242
243
244errno_t mbuf_getpacket(mbuf_how_t how, mbuf_t *mbuf)
245{
246 /* Must set *mbuf to NULL in failure case */
247 errno_t error = 0;
248
249 *mbuf = m_getpacket_how(how);
250
251 if (*mbuf == NULL) {
252 if (how == MBUF_WAITOK)
253 error = ENOMEM;
254 else
255 error = EWOULDBLOCK;
256 }
257
258 return error;
259}
260
6d2010ae
A
261/* This function is used to provide m_free via symbol indirection, please avoid
262 * any change in behavior or remove the indirection in config/Unsupported*
263 */
91447636
A
264mbuf_t mbuf_free(mbuf_t mbuf)
265{
266 return m_free(mbuf);
267}
268
6d2010ae
A
269/* This function is used to provide m_freem via symbol indirection, please avoid
270 * any change in behavior or remove the indirection in config/Unsupported*
271 */
91447636
A
272void mbuf_freem(mbuf_t mbuf)
273{
274 m_freem(mbuf);
275}
276
277int mbuf_freem_list(mbuf_t mbuf)
278{
279 return m_freem_list(mbuf);
280}
281
2d21ac55 282size_t mbuf_leadingspace(const mbuf_t mbuf)
91447636
A
283{
284 return m_leadingspace(mbuf);
285}
286
6d2010ae
A
287/* This function is used to provide m_trailingspace via symbol indirection,
288 * please avoid any change in behavior or remove the indirection in
289 * config/Unsupported*
290 */
2d21ac55 291size_t mbuf_trailingspace(const mbuf_t mbuf)
91447636
A
292{
293 return m_trailingspace(mbuf);
294}
295
296/* Manipulation */
2d21ac55 297errno_t mbuf_copym(const mbuf_t src, size_t offset, size_t len,
91447636
A
298 mbuf_how_t how, mbuf_t *new_mbuf)
299{
300 /* Must set *mbuf to NULL in failure case */
301 *new_mbuf = m_copym(src, offset, len, how);
302
303 return (*new_mbuf == NULL) ? ENOMEM : 0;
304}
305
2d21ac55 306errno_t mbuf_dup(const mbuf_t src, mbuf_how_t how, mbuf_t *new_mbuf)
91447636
A
307{
308 /* Must set *new_mbuf to NULL in failure case */
309 *new_mbuf = m_dup(src, how);
310
311 return (*new_mbuf == NULL) ? ENOMEM : 0;
312}
313
314errno_t mbuf_prepend(mbuf_t *orig, size_t len, mbuf_how_t how)
315{
316 /* Must set *orig to NULL in failure case */
317 *orig = m_prepend_2(*orig, len, how);
318
319 return (*orig == NULL) ? ENOMEM : 0;
320}
321
322errno_t mbuf_split(mbuf_t src, size_t offset,
323 mbuf_how_t how, mbuf_t *new_mbuf)
324{
325 /* Must set *new_mbuf to NULL in failure case */
326 *new_mbuf = m_split(src, offset, how);
327
328 return (*new_mbuf == NULL) ? ENOMEM : 0;
329}
330
331errno_t mbuf_pullup(mbuf_t *mbuf, size_t len)
332{
333 /* Must set *mbuf to NULL in failure case */
334 *mbuf = m_pullup(*mbuf, len);
335
336 return (*mbuf == NULL) ? ENOMEM : 0;
337}
338
339errno_t mbuf_pulldown(mbuf_t src, size_t *offset, size_t len, mbuf_t *location)
340{
341 /* Must set *location to NULL in failure case */
342 int new_offset;
343 *location = m_pulldown(src, *offset, len, &new_offset);
344 *offset = new_offset;
345
346 return (*location == NULL) ? ENOMEM : 0;
347}
348
6d2010ae
A
349/* This function is used to provide m_adj via symbol indirection, please avoid
350 * any change in behavior or remove the indirection in config/Unsupported*
351 */
91447636
A
352void mbuf_adj(mbuf_t mbuf, int len)
353{
354 m_adj(mbuf, len);
355}
356
2d21ac55
A
357errno_t mbuf_adjustlen(mbuf_t m, int amount)
358{
359 /* Verify m_len will be valid after adding amount */
360 if (amount > 0) {
361 int used = (size_t)mbuf_data(m) - (size_t)mbuf_datastart(m) +
362 m->m_len;
363
364 if ((size_t)(amount + used) > mbuf_maxlen(m))
365 return EINVAL;
366 }
367 else if (-amount > m->m_len) {
368 return EINVAL;
369 }
370
371 m->m_len += amount;
372 return 0;
373}
374
b0d623f7
A
375mbuf_t
376mbuf_concatenate(mbuf_t dst, mbuf_t src)
377{
378 if (dst == NULL)
379 return (NULL);
380
381 m_cat(dst, src);
382
383 /* return dst as is in the current implementation */
384 return (dst);
385}
2d21ac55 386errno_t mbuf_copydata(const mbuf_t m0, size_t off, size_t len, void* out_data)
91447636
A
387{
388 /* Copied m_copydata, added error handling (don't just panic) */
389 int count;
2d21ac55 390 mbuf_t m = m0;
91447636
A
391
392 while (off > 0) {
393 if (m == 0)
394 return EINVAL;
395 if (off < (size_t)m->m_len)
396 break;
397 off -= m->m_len;
398 m = m->m_next;
399 }
400 while (len > 0) {
401 if (m == 0)
402 return EINVAL;
403 count = m->m_len - off > len ? len : m->m_len - off;
404 bcopy(mtod(m, caddr_t) + off, out_data, count);
405 len -= count;
406 out_data = ((char*)out_data) + count;
407 off = 0;
408 m = m->m_next;
409 }
410
411 return 0;
412}
413
91447636
A
414int mbuf_mclhasreference(mbuf_t mbuf)
415{
416 if ((mbuf->m_flags & M_EXT))
417 return m_mclhasreference(mbuf);
418 else
419 return 0;
420}
421
422
423/* mbuf header */
2d21ac55 424mbuf_t mbuf_next(const mbuf_t mbuf)
91447636
A
425{
426 return mbuf->m_next;
427}
428
429errno_t mbuf_setnext(mbuf_t mbuf, mbuf_t next)
430{
431 if (next && ((next)->m_nextpkt != NULL ||
432 (next)->m_type == MT_FREE)) return EINVAL;
433 mbuf->m_next = next;
434
435 return 0;
436}
437
2d21ac55 438mbuf_t mbuf_nextpkt(const mbuf_t mbuf)
91447636
A
439{
440 return mbuf->m_nextpkt;
441}
442
443void mbuf_setnextpkt(mbuf_t mbuf, mbuf_t nextpkt)
444{
445 mbuf->m_nextpkt = nextpkt;
446}
447
2d21ac55 448size_t mbuf_len(const mbuf_t mbuf)
91447636
A
449{
450 return mbuf->m_len;
451}
452
453void mbuf_setlen(mbuf_t mbuf, size_t len)
454{
455 mbuf->m_len = len;
456}
457
2d21ac55 458size_t mbuf_maxlen(const mbuf_t mbuf)
91447636
A
459{
460 if (mbuf->m_flags & M_EXT)
461 return mbuf->m_ext.ext_size;
462 return &mbuf->m_dat[MLEN] - ((char*)mbuf_datastart(mbuf));
463}
464
2d21ac55 465mbuf_type_t mbuf_type(const mbuf_t mbuf)
91447636
A
466{
467 return mbuf->m_type;
468}
469
470errno_t mbuf_settype(mbuf_t mbuf, mbuf_type_t new_type)
471{
472 if (new_type == MBUF_TYPE_FREE) return EINVAL;
473
474 m_mchtype(mbuf, new_type);
475
476 return 0;
477}
478
2d21ac55 479mbuf_flags_t mbuf_flags(const mbuf_t mbuf)
91447636
A
480{
481 return mbuf->m_flags & mbuf_flags_mask;
482}
483
484errno_t mbuf_setflags(mbuf_t mbuf, mbuf_flags_t flags)
485{
486 if ((flags & ~mbuf_flags_mask) != 0) return EINVAL;
487 mbuf->m_flags = flags |
488 (mbuf->m_flags & ~mbuf_flags_mask);
489
490 return 0;
491}
492
493errno_t mbuf_setflags_mask(mbuf_t mbuf, mbuf_flags_t flags, mbuf_flags_t mask)
494{
495 if (((flags | mask) & ~mbuf_flags_mask) != 0) return EINVAL;
496
497 mbuf->m_flags = (flags & mask) | (mbuf->m_flags & ~mask);
498
499 return 0;
500}
501
2d21ac55 502errno_t mbuf_copy_pkthdr(mbuf_t dest, const mbuf_t src)
91447636
A
503{
504 if (((src)->m_flags & M_PKTHDR) == 0)
505 return EINVAL;
506
507 m_copy_pkthdr(dest, src);
508
509 return 0;
510}
511
2d21ac55 512size_t mbuf_pkthdr_len(const mbuf_t mbuf)
91447636
A
513{
514 return mbuf->m_pkthdr.len;
515}
516
517void mbuf_pkthdr_setlen(mbuf_t mbuf, size_t len)
518{
519 mbuf->m_pkthdr.len = len;
520}
521
2d21ac55
A
522void mbuf_pkthdr_adjustlen(mbuf_t mbuf, int amount)
523{
524 mbuf->m_pkthdr.len += amount;
525}
526
527ifnet_t mbuf_pkthdr_rcvif(const mbuf_t mbuf)
91447636
A
528{
529 // If we reference count ifnets, we should take a reference here before returning
530 return mbuf->m_pkthdr.rcvif;
531}
532
533errno_t mbuf_pkthdr_setrcvif(mbuf_t mbuf, ifnet_t ifnet)
534{
535 /* May want to walk ifnet list to determine if interface is valid */
536 mbuf->m_pkthdr.rcvif = (struct ifnet*)ifnet;
537 return 0;
538}
539
2d21ac55 540void* mbuf_pkthdr_header(const mbuf_t mbuf)
91447636
A
541{
542 return mbuf->m_pkthdr.header;
543}
544
545void mbuf_pkthdr_setheader(mbuf_t mbuf, void *header)
546{
547 mbuf->m_pkthdr.header = (void*)header;
548}
549
91447636
A
550void
551mbuf_inbound_modified(mbuf_t mbuf)
552{
553 /* Invalidate hardware generated checksum flags */
554 mbuf->m_pkthdr.csum_flags = 0;
555}
556
557extern void in_cksum_offset(struct mbuf* m, size_t ip_offset);
558extern void in_delayed_cksum_offset(struct mbuf *m, int ip_offset);
559
560void
b0d623f7 561mbuf_outbound_finalize(mbuf_t mbuf, u_int32_t protocol_family, size_t protocol_offset)
91447636 562{
3a60a9f5 563 if ((mbuf->m_pkthdr.csum_flags &
6d2010ae 564 (CSUM_DELAY_DATA | CSUM_DELAY_IP | CSUM_TCP_SUM16 | CSUM_DELAY_IPV6_DATA)) == 0)
91447636
A
565 return;
566
567 /* Generate the packet in software, client needs it */
568 switch (protocol_family) {
569 case PF_INET:
3a60a9f5
A
570 if (mbuf->m_pkthdr.csum_flags & CSUM_TCP_SUM16) {
571 /*
572 * If you're wondering where this lovely code comes
573 * from, we're trying to undo what happens in ip_output.
574 * Look for CSUM_TCP_SUM16 in ip_output.
575 */
576 u_int16_t first, second;
577 mbuf->m_pkthdr.csum_flags &= ~CSUM_TCP_SUM16;
578 mbuf->m_pkthdr.csum_flags |= CSUM_TCP;
579 first = mbuf->m_pkthdr.csum_data >> 16;
580 second = mbuf->m_pkthdr.csum_data & 0xffff;
581 mbuf->m_pkthdr.csum_data = first - second;
582 }
91447636
A
583 if (mbuf->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
584 in_delayed_cksum_offset(mbuf, protocol_offset);
585 }
586
587 if (mbuf->m_pkthdr.csum_flags & CSUM_DELAY_IP) {
588 in_cksum_offset(mbuf, protocol_offset);
589 }
590
591 mbuf->m_pkthdr.csum_flags &= ~(CSUM_DELAY_DATA | CSUM_DELAY_IP);
592 break;
6d2010ae
A
593
594 case PF_INET6:
595
596 if (mbuf->m_pkthdr.csum_flags & CSUM_DELAY_IPV6_DATA) {
597 in_delayed_cksum_offset(mbuf, protocol_offset);
598 }
599 mbuf->m_pkthdr.csum_flags &= ~CSUM_DELAY_IPV6_DATA;
600 break;
601
91447636
A
602
603 default:
604 /*
605 * Not sure what to do here if anything.
6d2010ae 606 * Hardware checksum code looked pretty IPv4/IPv6 specific.
91447636 607 */
6d2010ae
A
608 if ((mbuf->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_DELAY_IP | CSUM_DELAY_IPV6_DATA)) != 0)
609 panic("mbuf_outbound_finalize - CSUM flags set for non-IPv4 or IPv6 packet (%u)!\n", protocol_family);
91447636
A
610 }
611}
612
613errno_t
614mbuf_set_vlan_tag(
615 mbuf_t mbuf,
616 u_int16_t vlan)
617{
618 mbuf->m_pkthdr.csum_flags |= CSUM_VLAN_TAG_VALID;
619 mbuf->m_pkthdr.vlan_tag = vlan;
620
621 return 0;
622}
623
624errno_t
625mbuf_get_vlan_tag(
626 mbuf_t mbuf,
627 u_int16_t *vlan)
628{
629 if ((mbuf->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) == 0)
630 return ENXIO; // No vlan tag set
631
632 *vlan = mbuf->m_pkthdr.vlan_tag;
633
634 return 0;
635}
636
637errno_t
638mbuf_clear_vlan_tag(
639 mbuf_t mbuf)
640{
641 mbuf->m_pkthdr.csum_flags &= ~CSUM_VLAN_TAG_VALID;
642 mbuf->m_pkthdr.vlan_tag = 0;
643
644 return 0;
645}
646
647static const mbuf_csum_request_flags_t mbuf_valid_csum_request_flags =
6d2010ae
A
648 MBUF_CSUM_REQ_IP | MBUF_CSUM_REQ_TCP | MBUF_CSUM_REQ_UDP |
649 MBUF_CSUM_REQ_SUM16 | MBUF_CSUM_REQ_TCPIPV6 | MBUF_CSUM_REQ_UDPIPV6;
91447636
A
650
651errno_t
652mbuf_set_csum_requested(
653 mbuf_t mbuf,
654 mbuf_csum_request_flags_t request,
655 u_int32_t value)
656{
657 request &= mbuf_valid_csum_request_flags;
658 mbuf->m_pkthdr.csum_flags = (mbuf->m_pkthdr.csum_flags & 0xffff0000) | request;
659 mbuf->m_pkthdr.csum_data = value;
660
661 return 0;
662}
663
b0d623f7
A
664static const mbuf_tso_request_flags_t mbuf_valid_tso_request_flags =
665 MBUF_TSO_IPV4 | MBUF_TSO_IPV6;
666
667errno_t
668mbuf_get_tso_requested(
669 mbuf_t mbuf,
670 mbuf_tso_request_flags_t *request,
671 u_int32_t *value)
672{
673 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 ||
674 request == NULL || value == NULL)
675 return EINVAL;
676
677 *request = mbuf->m_pkthdr.csum_flags;
678 *request &= mbuf_valid_tso_request_flags;
679 if (*request && value != NULL)
680 *value = mbuf->m_pkthdr.tso_segsz;
681
682 return 0;
683}
684
91447636
A
685errno_t
686mbuf_get_csum_requested(
687 mbuf_t mbuf,
688 mbuf_csum_request_flags_t *request,
689 u_int32_t *value)
690{
691 *request = mbuf->m_pkthdr.csum_flags;
692 *request &= mbuf_valid_csum_request_flags;
693 if (value != NULL) {
694 *value = mbuf->m_pkthdr.csum_data;
695 }
696
697 return 0;
698}
699
700errno_t
701mbuf_clear_csum_requested(
702 mbuf_t mbuf)
703{
704 mbuf->m_pkthdr.csum_flags &= 0xffff0000;
705 mbuf->m_pkthdr.csum_data = 0;
706
707 return 0;
708}
709
710static const mbuf_csum_performed_flags_t mbuf_valid_csum_performed_flags =
711 MBUF_CSUM_DID_IP | MBUF_CSUM_IP_GOOD | MBUF_CSUM_DID_DATA |
712 MBUF_CSUM_PSEUDO_HDR | MBUF_CSUM_TCP_SUM16;
713
714errno_t
715mbuf_set_csum_performed(
716 mbuf_t mbuf,
717 mbuf_csum_performed_flags_t performed,
718 u_int32_t value)
719{
720 performed &= mbuf_valid_csum_performed_flags;
721 mbuf->m_pkthdr.csum_flags = (mbuf->m_pkthdr.csum_flags & 0xffff0000) | performed;
722 mbuf->m_pkthdr.csum_data = value;
723
724 return 0;
725}
726
727errno_t
728mbuf_get_csum_performed(
729 mbuf_t mbuf,
730 mbuf_csum_performed_flags_t *performed,
731 u_int32_t *value)
732{
733 *performed = mbuf->m_pkthdr.csum_flags & mbuf_valid_csum_performed_flags;
734 *value = mbuf->m_pkthdr.csum_data;
735
736 return 0;
737}
738
739errno_t
740mbuf_clear_csum_performed(
741 mbuf_t mbuf)
742{
743 mbuf->m_pkthdr.csum_flags &= 0xffff0000;
744 mbuf->m_pkthdr.csum_data = 0;
745
746 return 0;
747}
748
2d21ac55
A
749errno_t
750mbuf_inet_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length,
751 u_int16_t *csum)
752{
753 if (mbuf == NULL || length == 0 || csum == NULL ||
754 (u_int32_t)mbuf->m_pkthdr.len < (offset + length))
755 return (EINVAL);
756
757 *csum = inet_cksum(mbuf, protocol, offset, length);
758 return (0);
759}
760
761#if INET6
762errno_t
763mbuf_inet6_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length,
764 u_int16_t *csum)
765{
766 if (mbuf == NULL || length == 0 || csum == NULL ||
767 (u_int32_t)mbuf->m_pkthdr.len < (offset + length))
768 return (EINVAL);
769
770 *csum = inet6_cksum(mbuf, protocol, offset, length);
771 return (0);
772}
773#else /* INET6 */
774errno_t
775mbuf_inet6_cksum(__unused mbuf_t mbuf, __unused int protocol,
776 __unused u_int32_t offset, __unused u_int32_t length,
777 __unused u_int16_t *csum)
778{
779 panic("mbuf_inet6_cksum() doesn't exist on this platform\n");
780 return (0);
781}
782
783u_int16_t
784inet6_cksum(__unused struct mbuf *m, __unused unsigned int nxt,
785 __unused unsigned int off, __unused unsigned int len)
786{
787 panic("inet6_cksum() doesn't exist on this platform\n");
788 return (0);
789}
790
791void nd6_lookup_ipv6(void);
792void
793nd6_lookup_ipv6(void)
794{
795 panic("nd6_lookup_ipv6() doesn't exist on this platform\n");
796}
797
798int
799in6addr_local(__unused struct in6_addr *a)
800{
801 panic("in6addr_local() doesn't exist on this platform\n");
802 return (0);
803}
804
805void nd6_storelladdr(void);
806void
807nd6_storelladdr(void)
808{
809 panic("nd6_storelladdr() doesn't exist on this platform\n");
810}
811#endif /* INET6 */
812
91447636
A
813/*
814 * Mbuf tag KPIs
815 */
816
b0d623f7 817#define MTAG_FIRST_ID FIRST_KPI_STR_ID
91447636
A
818
819errno_t
820mbuf_tag_id_find(
821 const char *string,
822 mbuf_tag_id_t *out_id)
823{
b0d623f7 824 return net_str_id_find_internal(string, out_id, NSI_MBUF_TAG, 1);
91447636
A
825}
826
827errno_t
828mbuf_tag_allocate(
829 mbuf_t mbuf,
830 mbuf_tag_id_t id,
831 mbuf_tag_type_t type,
832 size_t length,
833 mbuf_how_t how,
834 void** data_p)
835{
836 struct m_tag *tag;
b0d623f7 837 u_int32_t mtag_id_first, mtag_id_last;
91447636
A
838
839 if (data_p != NULL)
840 *data_p = NULL;
841
842 /* Sanity check parameters */
b0d623f7
A
843 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last, NSI_MBUF_TAG);
844 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 || id < mtag_id_first ||
845 id > mtag_id_last || length < 1 || (length & 0xffff0000) != 0 ||
91447636
A
846 data_p == NULL) {
847 return EINVAL;
848 }
849
850 /* Make sure this mtag hasn't already been allocated */
851 tag = m_tag_locate(mbuf, id, type, NULL);
852 if (tag != NULL) {
853 return EEXIST;
854 }
855
856 /* Allocate an mtag */
6d2010ae 857 tag = m_tag_create(id, type, length, how, mbuf);
91447636
A
858 if (tag == NULL) {
859 return how == M_WAITOK ? ENOMEM : EWOULDBLOCK;
860 }
861
862 /* Attach the mtag and set *data_p */
863 m_tag_prepend(mbuf, tag);
864 *data_p = tag + 1;
865
866 return 0;
867}
868
869errno_t
870mbuf_tag_find(
871 mbuf_t mbuf,
872 mbuf_tag_id_t id,
873 mbuf_tag_type_t type,
874 size_t* length,
875 void** data_p)
876{
877 struct m_tag *tag;
b0d623f7 878 u_int32_t mtag_id_first, mtag_id_last;
91447636
A
879
880 if (length != NULL)
881 *length = 0;
882 if (data_p != NULL)
883 *data_p = NULL;
884
885 /* Sanity check parameters */
b0d623f7
A
886 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last, NSI_MBUF_TAG);
887 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 || id < mtag_id_first ||
888 id > mtag_id_last || length == NULL || data_p == NULL) {
91447636
A
889 return EINVAL;
890 }
891
892 /* Locate an mtag */
893 tag = m_tag_locate(mbuf, id, type, NULL);
894 if (tag == NULL) {
895 return ENOENT;
896 }
897
898 /* Copy out the pointer to the data and the lenght value */
899 *length = tag->m_tag_len;
900 *data_p = tag + 1;
901
902 return 0;
903}
904
905void
906mbuf_tag_free(
907 mbuf_t mbuf,
908 mbuf_tag_id_t id,
909 mbuf_tag_type_t type)
910{
911 struct m_tag *tag;
b0d623f7 912 u_int32_t mtag_id_first, mtag_id_last;
91447636 913
b0d623f7
A
914 /* Sanity check parameters */
915 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last, NSI_MBUF_TAG);
916 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 || id < mtag_id_first ||
917 id > mtag_id_last)
91447636
A
918 return;
919
920 tag = m_tag_locate(mbuf, id, type, NULL);
921 if (tag == NULL) {
922 return;
923 }
924
925 m_tag_delete(mbuf, tag);
926 return;
927}
928
929/* mbuf stats */
930void mbuf_stats(struct mbuf_stat *stats)
931{
932 stats->mbufs = mbstat.m_mbufs;
933 stats->clusters = mbstat.m_clusters;
934 stats->clfree = mbstat.m_clfree;
935 stats->drops = mbstat.m_drops;
936 stats->wait = mbstat.m_wait;
937 stats->drain = mbstat.m_drain;
938 __builtin_memcpy(stats->mtypes, mbstat.m_mtypes, sizeof(stats->mtypes));
939 stats->mcfail = mbstat.m_mcfail;
940 stats->mpfail = mbstat.m_mpfail;
941 stats->msize = mbstat.m_msize;
942 stats->mclbytes = mbstat.m_mclbytes;
943 stats->minclsize = mbstat.m_minclsize;
944 stats->mlen = mbstat.m_mlen;
945 stats->mhlen = mbstat.m_mhlen;
946 stats->bigclusters = mbstat.m_bigclusters;
947 stats->bigclfree = mbstat.m_bigclfree;
948 stats->bigmclbytes = mbstat.m_bigmclbytes;
949}
950
951errno_t
952mbuf_allocpacket(mbuf_how_t how, size_t packetlen, unsigned int *maxchunks, mbuf_t *mbuf)
953{
954 errno_t error;
955 struct mbuf *m;
956 unsigned int numpkts = 1;
957 unsigned int numchunks = maxchunks ? *maxchunks : 0;
958
959 if (packetlen == 0) {
960 error = EINVAL;
961 goto out;
962 }
963 m = m_allocpacket_internal(&numpkts, packetlen, maxchunks ? &numchunks : NULL, how, 1, 0);
964 if (m == 0) {
965 if (maxchunks && *maxchunks && numchunks > *maxchunks)
966 error = ENOBUFS;
967 else
968 error = ENOMEM;
969 } else {
2d21ac55
A
970 if (maxchunks)
971 *maxchunks = numchunks;
972 error = 0;
973 *mbuf = m;
974 }
975out:
976 return error;
977}
978
979errno_t
980mbuf_allocpacket_list(unsigned int numpkts, mbuf_how_t how, size_t packetlen, unsigned int *maxchunks, mbuf_t *mbuf)
981{
982 errno_t error;
983 struct mbuf *m;
984 unsigned int numchunks = maxchunks ? *maxchunks : 0;
985
986 if (numpkts == 0) {
987 error = EINVAL;
988 goto out;
989 }
990 if (packetlen == 0) {
991 error = EINVAL;
992 goto out;
993 }
994 m = m_allocpacket_internal(&numpkts, packetlen, maxchunks ? &numchunks : NULL, how, 1, 0);
995 if (m == 0) {
996 if (maxchunks && *maxchunks && numchunks > *maxchunks)
997 error = ENOBUFS;
998 else
999 error = ENOMEM;
1000 } else {
1001 if (maxchunks)
1002 *maxchunks = numchunks;
91447636
A
1003 error = 0;
1004 *mbuf = m;
1005 }
1006out:
1007 return error;
1008}
1009
1010
2d21ac55 1011
91447636
A
1012/*
1013 * mbuf_copyback differs from m_copyback in a few ways:
1014 * 1) mbuf_copyback will allocate clusters for new mbufs we append
1015 * 2) mbuf_copyback will grow the last mbuf in the chain if possible
1016 * 3) mbuf_copyback reports whether or not the operation succeeded
1017 * 4) mbuf_copyback allows the caller to specify M_WAITOK or M_NOWAIT
1018 */
1019errno_t
1020mbuf_copyback(
1021 mbuf_t m,
1022 size_t off,
1023 size_t len,
1024 const void *data,
1025 mbuf_how_t how)
1026{
1027 size_t mlen;
1028 mbuf_t m_start = m;
1029 mbuf_t n;
1030 int totlen = 0;
1031 errno_t result = 0;
1032 const char *cp = data;
1033
1034 if (m == NULL || len == 0 || data == NULL)
1035 return EINVAL;
1036
1037 while (off > (mlen = m->m_len)) {
1038 off -= mlen;
1039 totlen += mlen;
1040 if (m->m_next == 0) {
1041 n = m_getclr(how, m->m_type);
1042 if (n == 0) {
1043 result = ENOBUFS;
1044 goto out;
1045 }
1046 n->m_len = MIN(MLEN, len + off);
1047 m->m_next = n;
1048 }
1049 m = m->m_next;
1050 }
1051
1052 while (len > 0) {
1053 mlen = MIN(m->m_len - off, len);
1054 if (mlen < len && m->m_next == NULL && mbuf_trailingspace(m) > 0) {
1055 size_t grow = MIN(mbuf_trailingspace(m), len - mlen);
1056 mlen += grow;
1057 m->m_len += grow;
1058 }
1059 bcopy(cp, off + (char*)mbuf_data(m), (unsigned)mlen);
1060 cp += mlen;
1061 len -= mlen;
1062 mlen += off;
1063 off = 0;
1064 totlen += mlen;
1065 if (len == 0)
1066 break;
1067 if (m->m_next == 0) {
1068 n = m_get(how, m->m_type);
1069 if (n == NULL) {
1070 result = ENOBUFS;
1071 goto out;
1072 }
1073 if (len > MINCLSIZE) {
1074 /* cluter allocation failure is okay, we can grow chain */
1075 mbuf_mclget(how, m->m_type, &n);
1076 }
1077 n->m_len = MIN(mbuf_maxlen(n), len);
1078 m->m_next = n;
1079 }
1080 m = m->m_next;
1081 }
1082
1083out:
1084 if ((m_start->m_flags & M_PKTHDR) && (m_start->m_pkthdr.len < totlen))
1085 m_start->m_pkthdr.len = totlen;
1086
1087 return result;
1088}
2d21ac55 1089
b0d623f7
A
1090u_int32_t
1091mbuf_get_mlen(void)
1092{
1093 return (_MLEN);
1094}
2d21ac55 1095
b0d623f7
A
1096u_int32_t
1097mbuf_get_mhlen(void)
2d21ac55 1098{
b0d623f7 1099 return (_MHLEN);
2d21ac55 1100}
d1ecb069 1101
6d2010ae
A
1102u_int32_t
1103mbuf_get_minclsize(void)
d1ecb069 1104{
6d2010ae 1105 return (MHLEN + MLEN);
d1ecb069 1106}
d41d1dae
A
1107
1108mbuf_traffic_class_t
1109mbuf_get_traffic_class(mbuf_t m)
1110{
6d2010ae 1111 mbuf_traffic_class_t prio = MBUF_TC_BE;
d41d1dae
A
1112
1113 if (m == NULL || !(m->m_flags & M_PKTHDR))
1114 return (prio);
1115
1116 if (m->m_pkthdr.prio <= MBUF_TC_VO)
1117 prio = m->m_pkthdr.prio;
1118
1119 return (prio);
d41d1dae
A
1120}
1121
1122errno_t
1123mbuf_set_traffic_class(mbuf_t m, mbuf_traffic_class_t tc)
1124{
d41d1dae
A
1125 errno_t error = 0;
1126
1127 if (m == NULL || !(m->m_flags & M_PKTHDR))
1128 return EINVAL;
1129
1130 switch (tc) {
1131 case MBUF_TC_BE:
1132 case MBUF_TC_BK:
1133 case MBUF_TC_VI:
1134 case MBUF_TC_VO:
1135 m->m_pkthdr.prio = tc;
1136 break;
1137 default:
1138 error = EINVAL;
1139 break;
1140 }
1141 return error;
d41d1dae 1142}