809953b1f7d76d065a172c9ca1c3bbcad52c0815
[platform/upstream/libnetfilter_queue.git] / src / extra / pktbuff.c
1 /*
2  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
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.
8  *
9  * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
10  */
11
12 #include <stdlib.h>
13 #include <string.h> /* for memcpy */
14
15 #include <netinet/if_ether.h>
16 #include <netinet/ip.h>
17 #include <netinet/tcp.h>
18
19 #include "internal.h"
20
21 /**
22  * \defgroup pktbuff User-space network packet buffer
23  *
24  * This library provides the user-space network packet buffer. This abstraction
25  * is strongly inspired by Linux kernel network buffer, the so-called sk_buff.
26  */
27
28 /**
29  * pktb_alloc - allocate a new packet buffer
30  * \param family Indicate what family, eg. AF_BRIDGE, AF_INET, AF_INET6, ...
31  * \param data Pointer to packet data
32  * \param len Packet length
33  * \param extra Extra memory in the tail to be allocated (for mangling)
34  *
35  * This function returns a packet buffer that contains the packet data and
36  * some extra memory room in the tail (in case of requested).
37  *
38  * \return a pointer to a new queue handle or NULL on failure.
39  */
40 struct pkt_buff *
41 pktb_alloc(int family, void *data, size_t len, size_t extra)
42 {
43         struct pkt_buff *pktb;
44         void *pkt_data;
45
46         pktb = calloc(1, sizeof(struct pkt_buff) + len + extra);
47         if (pktb == NULL)
48                 return NULL;
49
50         /* Better make sure alignment is correct. */
51         pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff);
52         memcpy(pkt_data, data, len);
53
54         pktb->len = len;
55         pktb->data_len = len + extra;
56
57         pktb->head = pkt_data;
58         pktb->data = pkt_data;
59         pktb->tail = pktb->head + len;
60
61         switch(family) {
62         case AF_INET:
63                 pktb->network_header = pktb->data;
64                 break;
65         case AF_BRIDGE: {
66                 struct ethhdr *ethhdr = (struct ethhdr *)pktb->data;
67
68                 pktb->mac_header = pktb->data;
69
70                 switch(ethhdr->h_proto) {
71                 case ETH_P_IP:
72                         pktb->network_header = pktb->data + ETH_HLEN;
73                         break;
74                 default:
75                         /* This protocol is unsupported. */
76                         free(pktb);
77                         return NULL;
78                 }
79                 break;
80         }
81         }
82         return pktb;
83 }
84
85 uint8_t *pktb_data(struct pkt_buff *pktb)
86 {
87         return pktb->data;
88 }
89
90 uint32_t pktb_len(struct pkt_buff *pktb)
91 {
92         return pktb->len;
93 }
94
95 void pktb_free(struct pkt_buff *pktb)
96 {
97         free(pktb);
98 }
99
100 void pktb_push(struct pkt_buff *pktb, unsigned int len)
101 {
102         pktb->data += len;
103 }
104
105 void pktb_pull(struct pkt_buff *pktb, unsigned int len)
106 {
107         pktb->data -= len;
108 }
109
110 void pktb_put(struct pkt_buff *pktb, unsigned int len)
111 {
112         pktb->tail += len;
113 }
114
115 void pktb_trim(struct pkt_buff *pktb, unsigned int len)
116 {
117         pktb->len = len;
118 }
119
120 unsigned int pktb_tailroom(struct pkt_buff *pktb)
121 {
122         return pktb->data_len - pktb->len;
123 }
124
125 uint8_t *pktb_mac_header(struct pkt_buff *pktb)
126 {
127         return pktb->mac_header;
128 }
129
130 uint8_t *pktb_network_header(struct pkt_buff *pktb)
131 {
132         return pktb->network_header;
133 }
134
135 uint8_t *pktb_transport_header(struct pkt_buff *pktb)
136 {
137         return pktb->transport_header;
138 }
139
140 /**
141  * @}
142  */