1 /* $NetBSD: npf_mbuf.c,v 1.1 2010/08/22 18:56:22 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This material is based upon work partially supported by The 8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * NPF network buffer management interface. 34 * 35 * Network buffer in NetBSD is mbuf. Internal mbuf structures are 36 * abstracted within this source. 37 */ 38 39 #ifdef _KERNEL 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: npf_mbuf.c,v 1.1 2010/08/22 18:56:22 rmind Exp $"); 42 #endif 43 44 #include <sys/param.h> 45 #include <sys/mbuf.h> 46 47 #include "npf_impl.h" 48 49 /* 50 * nbuf_dataptr: return a pointer to data in nbuf. 51 */ 52 void * 53 nbuf_dataptr(nbuf_t *nbuf) 54 { 55 const struct mbuf *m = nbuf; 56 57 return mtod(m, void *); 58 } 59 60 /* 61 * nbuf_advance: advance in mbuf or chain by specified amount of bytes. 62 * 63 * => Returns new pointer to data in mbuf and NULL if offset gets invalid. 64 * => Sets nbuf to current (after advance) mbuf in the chain. 65 */ 66 void * 67 nbuf_advance(nbuf_t **nbuf, void *n_ptr, u_int n) 68 { 69 struct mbuf *m = *nbuf; 70 u_int off, wmark; 71 uint8_t *d; 72 73 /* Offset with amount to advance. */ 74 off = (uintptr_t)n_ptr - mtod(m, uintptr_t) + n; 75 wmark = m->m_len; 76 77 /* Find the mbuf according to offset. */ 78 while (__predict_false(wmark <= off)) { 79 m = m->m_next; 80 if (__predict_false(m == NULL)) { 81 /* 82 * If out of chain, then offset is 83 * higher than packet length. 84 */ 85 return NULL; 86 } 87 wmark += m->m_len; 88 } 89 90 /* Offset in mbuf data. */ 91 d = mtod(m, uint8_t *); 92 KASSERT(off >= (wmark - m->m_len)); 93 d += (off - (wmark - m->m_len)); 94 95 *nbuf = (void *)m; 96 return d; 97 } 98 99 /* 100 * nbuf_rw_datum: read or write a datum of specified length at current 101 * offset in the nbuf chain and copy datum into passed buffer. 102 * 103 * => Datum is allowed to overlap between two or more mbufs. 104 * => Note: all data in nbuf is in network byte order. 105 * => Returns 0 on success, error code on failure. 106 * 107 * Note: this function must be static inline with constant operation 108 * parameter - we expect constant propagation. 109 */ 110 111 #define NBUF_DATA_READ 0 112 #define NBUF_DATA_WRITE 1 113 114 static inline int 115 nbuf_rw_datum(const int wr, nbuf_t *nbuf, void *n_ptr, size_t len, void *buf) 116 { 117 uint8_t *d = n_ptr, *b = buf; 118 struct mbuf *m = nbuf; 119 u_int off, wmark, end; 120 121 /* Current offset in mbuf. */ 122 off = (uintptr_t)n_ptr - mtod(m, uintptr_t); 123 KASSERT(off < m->m_len); 124 wmark = m->m_len; 125 126 /* Is datum overlapping? */ 127 end = off + len; 128 while (__predict_false(end > wmark)) { 129 u_int l; 130 131 /* Get the part of current mbuf. */ 132 l = m->m_len - off; 133 KASSERT(l < len); 134 len -= l; 135 if (wr) { 136 while (l--) 137 *d++ = *b++; 138 } else { 139 while (l--) 140 *b++ = *d++; 141 } 142 KASSERT(len > 0); 143 144 /* Take next mbuf and continue. */ 145 m = m->m_next; 146 if (__predict_false(m == NULL)) { 147 /* 148 * If out of chain, then offset with datum 149 * length exceed the packet length. 150 */ 151 return EINVAL; 152 } 153 wmark += m->m_len; 154 d = mtod(m, uint8_t *); 155 off = 0; 156 } 157 KASSERT(n_ptr == d || mtod(m, uint8_t *) == d); 158 KASSERT(len <= m->m_len); 159 160 /* Non-overlapping case: fetch the actual data. */ 161 if (wr) { 162 while (len--) 163 *d++ = *b++; 164 } else { 165 while (len--) 166 *b++ = *d++; 167 } 168 return 0; 169 } 170 171 /* 172 * nbuf_{fetch|store}_datum: read/write absraction calls on nbuf_rw_datum(). 173 */ 174 int 175 nbuf_fetch_datum(nbuf_t *nbuf, void *n_ptr, size_t len, void *buf) 176 { 177 178 return nbuf_rw_datum(NBUF_DATA_READ, nbuf, n_ptr, len, buf); 179 } 180 181 int 182 nbuf_store_datum(nbuf_t *nbuf, void *n_ptr, size_t len, void *buf) 183 { 184 185 return nbuf_rw_datum(NBUF_DATA_WRITE, nbuf, n_ptr, len, buf); 186 } 187 188 /* 189 * nbuf_add_tag: add a tag to specified network buffer. 190 * 191 * => Returns 0 on success, or errno on failure. 192 */ 193 int 194 nbuf_add_tag(nbuf_t *nbuf, uint32_t key, uint32_t val) 195 { 196 struct mbuf *m = nbuf; 197 struct m_tag *mt; 198 uint32_t *dat; 199 200 mt = m_tag_get(PACKET_TAG_NPF, sizeof(uint32_t), M_NOWAIT); 201 if (__predict_false(mt == NULL)) { 202 return ENOMEM; 203 } 204 dat = (uint32_t *)(mt + 1); 205 *dat = val; 206 m_tag_prepend(m, mt); 207 return 0; 208 } 209 210 /* 211 * nbuf_find_tag: find a tag in specified network buffer. 212 * 213 * => Returns 0 on success, or errno on failure. 214 */ 215 int 216 nbuf_find_tag(nbuf_t *nbuf, uint32_t key, void **data) 217 { 218 struct mbuf *m = nbuf; 219 struct m_tag *mt; 220 221 mt = m_tag_find(m, PACKET_TAG_NPF, NULL); 222 if (__predict_false(mt == NULL)) { 223 return EINVAL; 224 } 225 *data = (void *)(mt + 1); 226 return 0; 227 } 228