2 * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
13 #include <string.h> /* for memcpy */
16 #include <netinet/if_ether.h>
17 #include <netinet/ip.h>
18 #include <netinet/tcp.h>
23 * \defgroup pktbuff User-space network packet buffer
25 * This library provides the user-space network packet buffer. This abstraction
26 * is strongly inspired by Linux kernel network buffer, the so-called sk_buff.
32 * pktb_alloc - allocate a new packet buffer
33 * \param family Indicate what family, eg. AF_BRIDGE, AF_INET, AF_INET6, ...
34 * \param data Pointer to packet data
35 * \param len Packet length
36 * \param extra Extra memory in the tail to be allocated (for mangling)
38 * This function returns a packet buffer that contains the packet data and
39 * some extra memory room in the tail (in case of requested).
41 * \return a pointer to a new queue handle or NULL on failure.
44 pktb_alloc(int family, void *data, size_t len, size_t extra)
46 struct pkt_buff *pktb;
49 pktb = calloc(1, sizeof(struct pkt_buff) + len + extra);
53 /* Better make sure alignment is correct. */
54 pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff);
55 memcpy(pkt_data, data, len);
58 pktb->data_len = len + extra;
60 pktb->head = pkt_data;
61 pktb->data = pkt_data;
62 pktb->tail = pktb->head + len;
66 pktb->network_header = pktb->data;
69 struct ethhdr *ethhdr = (struct ethhdr *)pktb->data;
71 pktb->mac_header = pktb->data;
73 switch(ethhdr->h_proto) {
75 pktb->network_header = pktb->data + ETH_HLEN;
78 /* This protocol is unsupported. */
87 EXPORT_SYMBOL(pktb_alloc);
90 * pktb_data - return pointer to the beginning of the packet buffer
91 * \param pktb Pointer to packet buffer
93 uint8_t *pktb_data(struct pkt_buff *pktb)
97 EXPORT_SYMBOL(pktb_data);
100 * pktb_len - return length of the packet buffer
101 * \param pktb Pointer to packet buffer
103 uint32_t pktb_len(struct pkt_buff *pktb)
107 EXPORT_SYMBOL(pktb_len);
110 * pktb_free - release packet buffer
111 * \param pktb Pointer to packet buffer
113 void pktb_free(struct pkt_buff *pktb)
117 EXPORT_SYMBOL(pktb_free);
120 * pktb_push - update pointer to the beginning of the packet buffer
121 * \param pktb Pointer to packet buffer
123 void pktb_push(struct pkt_buff *pktb, unsigned int len)
128 EXPORT_SYMBOL(pktb_push);
131 * pktb_pull - update pointer to the beginning of the packet buffer
132 * \param pktb Pointer to packet buffer
134 void pktb_pull(struct pkt_buff *pktb, unsigned int len)
139 EXPORT_SYMBOL(pktb_pull);
142 * pktb_put - add extra bytes to the tail of the packet buffer
143 * \param pktb Pointer to packet buffer
145 void pktb_put(struct pkt_buff *pktb, unsigned int len)
150 EXPORT_SYMBOL(pktb_put);
153 * pktb_trim - set new length for this packet buffer
154 * \param pktb Pointer to packet buffer
156 void pktb_trim(struct pkt_buff *pktb, unsigned int len)
160 EXPORT_SYMBOL(pktb_trim);
163 * pktb_tailroom - get room in bytes in the tail of the packet buffer
164 * \param pktb Pointer to packet buffer
166 unsigned int pktb_tailroom(struct pkt_buff *pktb)
168 return pktb->data_len - pktb->len;
170 EXPORT_SYMBOL(pktb_tailroom);
173 * pktb_mac_header - return pointer to layer 2 header (if any)
174 * \param pktb Pointer to packet buffer
176 uint8_t *pktb_mac_header(struct pkt_buff *pktb)
178 return pktb->mac_header;
180 EXPORT_SYMBOL(pktb_mac_header);
183 * pktb_network_header - return pointer to layer 3 header
184 * \param pktb Pointer to packet buffer
186 uint8_t *pktb_network_header(struct pkt_buff *pktb)
188 return pktb->network_header;
190 EXPORT_SYMBOL(pktb_network_header);
193 * pktb_transport_header - return pointer to layer 4 header (if any)
194 * \param pktb Pointer to packet buffer
196 uint8_t *pktb_transport_header(struct pkt_buff *pktb)
198 return pktb->transport_header;
200 EXPORT_SYMBOL(pktb_transport_header);
202 static int pktb_expand_tail(struct pkt_buff *pkt, int extra)
204 /* No room in packet, cannot mangle it. We don't support dynamic
205 * reallocation. Instead, increase the size of the extra room in
206 * the tail in pktb_alloc.
208 if (pkt->len + extra > pkt->data_len)
212 pkt->tail = pkt->tail + extra;
216 static int enlarge_pkt(struct pkt_buff *pkt, unsigned int extra)
218 if (pkt->len + extra > 65535)
221 if (!pktb_expand_tail(pkt, extra - pktb_tailroom(pkt)))
227 int pktb_mangle(struct pkt_buff *pkt,
228 unsigned int dataoff,
229 unsigned int match_offset,
230 unsigned int match_len,
231 const char *rep_buffer,
232 unsigned int rep_len)
236 if (rep_len > match_len &&
237 rep_len - match_len > pktb_tailroom(pkt) &&
238 !enlarge_pkt(pkt, rep_len - match_len))
241 data = pkt->network_header + dataoff;
243 /* move post-replacement */
244 memmove(data + match_offset + rep_len,
245 data + match_offset + match_len,
246 pkt->tail - (pkt->network_header + dataoff +
247 match_offset + match_len));
249 /* insert data from buffer */
250 memcpy(data + match_offset, rep_buffer, rep_len);
252 /* update pkt info */
253 if (rep_len > match_len)
254 pktb_put(pkt, rep_len - match_len);
256 pktb_trim(pkt, pkt->len + rep_len - match_len);
261 EXPORT_SYMBOL(pktb_mangle);
264 * pktb_mangled - return true if packet has been mangled
265 * \param pktb Pointer to packet buffer
267 bool pktb_mangled(const struct pkt_buff *pkt)
271 EXPORT_SYMBOL(pktb_mangled);