1 /*****************************************************************************
2  * ip.h: Internet Protocol (IP)
3  *****************************************************************************
4  * Copyright (C) 2015 VideoLAN
5  *
6  * Authors: Benjamin Cohen <bencoh@notk.org>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sublicense, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject
14  * to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *****************************************************************************/
27 
28 /*
29  * Normative references:
30  *  - IETF RFC 791 INTERNET PROTOCOL (September 1981)
31  *  - IETF RFC 790 ASSIGNED NUMBERS (September 1981)
32  */
33 
34 #ifndef __BITSTREAM_IETF_IP_H__
35 #define __BITSTREAM_IETF_IP_H__
36 
37 #include <stdint.h>
38 
39 #ifdef __cplusplus
40 extern "C"
41 {
42 #endif
43 
44 /*
45  * Reminder: IP header
46     0                   1                   2                   3
47     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
48    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49    |Version|  IHL  |Type of Service|          Total Length         |
50    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51    |         Identification        |Flags|      Fragment Offset    |
52    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53    |  Time to Live |    Protocol   |         Header Checksum       |
54    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55    |                       Source Address                          |
56    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57    |                    Destination Address                        |
58    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59    |                    Options                    |    Padding    |
60    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 */
62 
63 #define IP_HEADER_MINSIZE   20
64 
65 #define IP_PROTO_ICMP       1
66 #define IP_PROTO_TCP        6
67 #define IP_PROTO_UDP        17
68 
ip_set_version(uint8_t * p_ip,uint8_t version)69 static inline void ip_set_version(uint8_t *p_ip, uint8_t version)
70 {
71     p_ip[0] &= ~0xf0;
72     p_ip[0] |= (version & 0xf) << 4;
73 }
74 
ip_get_version(const uint8_t * p_ip)75 static inline uint8_t ip_get_version(const uint8_t *p_ip)
76 {
77     return (p_ip[0] >> 4) & 0xf;
78 }
79 
ip_set_ihl(uint8_t * p_ip,uint8_t ihl)80 static inline void ip_set_ihl(uint8_t *p_ip, uint8_t ihl)
81 {
82     p_ip[0] &= ~0xf;
83     p_ip[0] |= (ihl & 0xf);
84 }
85 
ip_get_ihl(const uint8_t * p_ip)86 static inline uint8_t ip_get_ihl(const uint8_t *p_ip)
87 {
88     return p_ip[0] & 0xf;
89 }
90 
ip_set_tos(uint8_t * p_ip,uint8_t tos)91 static inline void ip_set_tos(uint8_t *p_ip, uint8_t tos)
92 {
93     p_ip[1] = tos;
94 }
95 
ip_get_tos(const uint8_t * p_ip)96 static inline uint8_t ip_get_tos(const uint8_t *p_ip)
97 {
98     return p_ip[1];
99 }
100 
ip_set_len(uint8_t * p_ip,uint16_t len)101 static inline void ip_set_len(uint8_t *p_ip, uint16_t len)
102 {
103     p_ip[2] = (len & 0xff00) >> 8;
104     p_ip[3] = (len & 0xff);
105 }
106 
ip_get_len(const uint8_t * p_ip)107 static inline uint16_t ip_get_len(const uint8_t *p_ip)
108 {
109     return (p_ip[2] << 8) | p_ip[3];
110 }
111 
ip_set_id(uint8_t * p_ip,uint16_t id)112 static inline void ip_set_id(uint8_t *p_ip, uint16_t id)
113 {
114 
115     p_ip[4] = (id & 0xff00) >> 8;
116     p_ip[5] = (id & 0xff);
117 }
118 
ip_get_id(const uint8_t * p_ip)119 static inline uint16_t ip_get_id(const uint8_t *p_ip)
120 {
121     return (p_ip[4] << 8) | p_ip[5];
122 }
123 
ip_set_flag_reserved(uint8_t * p_ip,uint8_t flag)124 static inline void ip_set_flag_reserved(uint8_t *p_ip, uint8_t flag)
125 {
126     p_ip[6] &= ~0x80;
127     p_ip[6] |= (flag & 1) << 7;
128 }
129 
ip_get_flag_reservered(const uint8_t * p_ip)130 static inline uint8_t ip_get_flag_reservered(const uint8_t *p_ip)
131 {
132     return (p_ip[6] & 0x80);
133 }
134 
ip_set_flag_df(uint8_t * p_ip,uint8_t flag)135 static inline void ip_set_flag_df(uint8_t *p_ip, uint8_t flag)
136 {
137     p_ip[6] &= ~0x40;
138     p_ip[6] |= (flag & 1) << 6;
139 }
140 
ip_get_flag_df(const uint8_t * p_ip)141 static inline uint8_t ip_get_flag_df(const uint8_t *p_ip)
142 {
143     return (p_ip[6] & 0x40);
144 }
145 
ip_set_flag_mf(uint8_t * p_ip,uint8_t flag)146 static inline void ip_set_flag_mf(uint8_t *p_ip, uint8_t flag)
147 {
148     p_ip[6] &= ~0x20;
149     p_ip[6] |= (flag & 1) << 5;
150 }
151 
ip_get_flag_mf(const uint8_t * p_ip)152 static inline uint8_t ip_get_flag_mf(const uint8_t *p_ip)
153 {
154     return (p_ip[6] & 0x20);
155 }
156 
ip_set_frag_offset(uint8_t * p_ip,uint16_t offset)157 static inline void ip_set_frag_offset(uint8_t *p_ip, uint16_t offset)
158 {
159     p_ip[6] &= ~0x1f;
160     p_ip[6] |= (offset & 0x1f00) >> 8;
161     p_ip[7] = (offset & 0xff);
162 }
163 
ip_get_frag_offset(const uint8_t * p_ip)164 static inline uint8_t ip_get_frag_offset(const uint8_t *p_ip)
165 {
166     return ((p_ip[6] & 0x1f) << 8 | p_ip[7]);
167 }
168 
ip_set_ttl(uint8_t * p_ip,uint8_t ttl)169 static inline void ip_set_ttl(uint8_t *p_ip, uint8_t ttl)
170 {
171     p_ip[8] = ttl;
172 }
173 
ip_get_ttl(const uint8_t * p_ip)174 static inline uint8_t ip_get_ttl(const uint8_t *p_ip)
175 {
176     return p_ip[8];
177 }
178 
ip_set_proto(uint8_t * p_ip,uint8_t proto)179 static inline void ip_set_proto(uint8_t *p_ip, uint8_t proto)
180 {
181     p_ip[9] = proto;
182 }
183 
ip_get_proto(const uint8_t * p_ip)184 static inline uint8_t ip_get_proto(const uint8_t *p_ip)
185 {
186     return p_ip[9];
187 }
188 
ip_set_cksum(uint8_t * p_ip,uint16_t cksum)189 static inline void ip_set_cksum(uint8_t *p_ip, uint16_t cksum)
190 {
191     p_ip[10] = (cksum & 0xff00) >> 8;
192     p_ip[11] = (cksum & 0xff);
193 }
194 
ip_get_cksum(const uint8_t * p_ip)195 static inline uint16_t ip_get_cksum(const uint8_t *p_ip)
196 {
197     return (p_ip[10] << 8) | p_ip[11];
198 }
199 
ip_set_srcaddr(uint8_t * p_ip,uint32_t addr)200 static inline void ip_set_srcaddr(uint8_t *p_ip, uint32_t addr)
201 {
202     p_ip[12] = (addr & 0xff000000) >> 24;
203     p_ip[13] = (addr & 0x00ff0000) >> 16;
204     p_ip[14] = (addr & 0x0000ff00) >>  8;
205     p_ip[15] = (addr & 0x000000ff);
206 }
207 
ip_get_srcaddr(const uint8_t * p_ip)208 static inline uint32_t ip_get_srcaddr(const uint8_t *p_ip)
209 {
210     return (p_ip[12] << 24) | (p_ip[13] << 16) | (p_ip[14] << 8) | p_ip[15];
211 }
212 
ip_srcaddr(uint8_t * p_ip)213 static inline uint8_t *ip_srcaddr(uint8_t *p_ip)
214 {
215     return p_ip + 12;
216 }
217 
ip_set_dstaddr(uint8_t * p_ip,uint32_t addr)218 static inline void ip_set_dstaddr(uint8_t *p_ip, uint32_t addr)
219 {
220     p_ip[16] = (addr & 0xff000000) >> 24;
221     p_ip[17] = (addr & 0x00ff0000) >> 16;
222     p_ip[18] = (addr & 0x0000ff00) >>  8;
223     p_ip[19] = (addr & 0x000000ff);
224 }
225 
ip_dstaddr(uint8_t * p_ip)226 static inline uint8_t *ip_dstaddr(uint8_t *p_ip)
227 {
228     return p_ip + 16;
229 }
230 
ip_get_dstaddr(const uint8_t * p_ip)231 static inline uint32_t ip_get_dstaddr(const uint8_t *p_ip)
232 {
233     return (p_ip[16] << 24) | (p_ip[17] << 16) | (p_ip[18] << 8) | p_ip[19];
234 }
235 
ip_payload(uint8_t * p_ip)236 static inline uint8_t *ip_payload(uint8_t *p_ip)
237 {
238     return p_ip + 4 * ip_get_ihl(p_ip); /* ihl is in 32b words */
239 }
240 
241 #ifdef __cplusplus
242 }
243 #endif
244 
245 #endif
246