netsniff-ng: remove unnecessary zeroing of packet counters in init_ctx()
[netsniff-ng.git] / trafgen_l4.c
blob5a694b3712eb3e99fc5d5f6ba6c203d8050e267b
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Subject to the GPL, version 2.
4 */
6 #include <stdbool.h>
7 #include <netinet/in.h>
9 #include "die.h"
10 #include "csum.h"
11 #include "built_in.h"
12 #include "trafgen_l3.h"
13 #include "trafgen_l4.h"
14 #include "trafgen_conf.h"
15 #include "trafgen_proto.h"
17 static struct proto_field udp_fields[] = {
18 { .id = UDP_SPORT, .len = 2, .offset = 0 },
19 { .id = UDP_DPORT, .len = 2, .offset = 2 },
20 { .id = UDP_LEN, .len = 2, .offset = 4 },
21 { .id = UDP_CSUM, .len = 2, .offset = 6 },
24 static void udp_header_init(struct proto_hdr *hdr)
26 proto_lower_default_add(hdr, PROTO_IP4);
28 proto_header_fields_add(hdr, udp_fields, array_size(udp_fields));
31 static void udp_field_changed(struct proto_field *field)
33 field->hdr->is_csum_valid = false;
36 static void udp_csum_update(struct proto_hdr *hdr)
38 struct proto_hdr *lower;
39 uint16_t total_len;
40 uint16_t csum;
42 if (hdr->is_csum_valid)
43 return;
44 if (proto_hdr_field_is_set(hdr, UDP_CSUM))
45 return;
46 lower = proto_lower_header(hdr);
47 if (!lower)
48 return;
50 total_len = packet_get(hdr->pkt_id)->len - hdr->pkt_offset;
52 proto_hdr_field_set_default_be16(hdr, UDP_CSUM, 0);
54 switch (lower->ops->id) {
55 case PROTO_IP4:
56 csum = p4_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
57 total_len, IPPROTO_UDP);
58 break;
59 case PROTO_IP6:
60 csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
61 total_len, IPPROTO_UDP);
62 break;
63 default:
64 csum = 0;
65 break;
68 proto_hdr_field_set_default_be16(hdr, UDP_CSUM, bswap_16(csum));
69 hdr->is_csum_valid = true;
72 static void udp_packet_finish(struct proto_hdr *hdr)
74 struct packet *pkt = current_packet();
75 uint16_t total_len;
77 total_len = pkt->len - hdr->pkt_offset;
78 proto_hdr_field_set_default_be16(hdr, UDP_LEN, total_len);
80 udp_csum_update(hdr);
83 static const struct proto_ops udp_proto_ops = {
84 .id = PROTO_UDP,
85 .layer = PROTO_L4,
86 .header_init = udp_header_init,
87 .packet_update = udp_csum_update,
88 .packet_finish = udp_packet_finish,
89 .field_changed = udp_field_changed,
92 static struct proto_field tcp_fields[] = {
93 { .id = TCP_SPORT, .len = 2, .offset = 0 },
94 { .id = TCP_DPORT, .len = 2, .offset = 2 },
95 { .id = TCP_SEQ, .len = 4, .offset = 4 },
96 { .id = TCP_ACK_SEQ, .len = 4, .offset = 8 },
97 { .id = TCP_DOFF, .len = 2, .offset = 12, .shift = 12, .mask = 0xf000 },
98 /* reserved (4 bits) */
99 { .id = TCP_CWR, .len = 2, .offset = 12, .shift = 7, .mask = 0x0080 },
100 { .id = TCP_ECE, .len = 2, .offset = 12, .shift = 6, .mask = 0x0040 },
101 { .id = TCP_URG, .len = 2, .offset = 12, .shift = 5, .mask = 0x0020 },
102 { .id = TCP_ACK, .len = 2, .offset = 12, .shift = 4, .mask = 0x0010 },
103 { .id = TCP_PSH, .len = 2, .offset = 12, .shift = 3, .mask = 0x0008 },
104 { .id = TCP_RST, .len = 2, .offset = 12, .shift = 2, .mask = 0x0004 },
105 { .id = TCP_SYN, .len = 2, .offset = 12, .shift = 1, .mask = 0x0002 },
106 { .id = TCP_FIN, .len = 2, .offset = 12, .shift = 0, .mask = 0x0001 },
107 { .id = TCP_WINDOW, .len = 2, .offset = 14 },
108 { .id = TCP_CSUM, .len = 2, .offset = 16 },
109 { .id = TCP_URG_PTR, .len = 2, .offset = 18 },
112 static void tcp_header_init(struct proto_hdr *hdr)
114 proto_lower_default_add(hdr, PROTO_IP4);
116 proto_header_fields_add(hdr, tcp_fields, array_size(tcp_fields));
118 proto_hdr_field_set_default_be16(hdr, TCP_DOFF, 5);
121 static void tcp_field_changed(struct proto_field *field)
123 field->hdr->is_csum_valid = false;
126 static void tcp_csum_update(struct proto_hdr *hdr)
128 struct proto_hdr *lower = proto_lower_header(hdr);
129 struct packet *pkt = current_packet();
130 uint16_t total_len;
131 uint16_t csum;
133 if (hdr->is_csum_valid)
134 return;
135 if (proto_hdr_field_is_set(hdr, TCP_CSUM))
136 return;
138 if (!lower)
139 return;
141 total_len = pkt->len - hdr->pkt_offset;
143 proto_hdr_field_set_default_be16(hdr, TCP_CSUM, 0);
145 switch (lower->ops->id) {
146 case PROTO_IP4:
147 csum = p4_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
148 total_len, IPPROTO_TCP);
149 break;
150 case PROTO_IP6:
151 csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
152 total_len, IPPROTO_TCP);
153 break;
154 default:
155 csum = 0;
156 break;
159 proto_hdr_field_set_default_be16(hdr, TCP_CSUM, bswap_16(csum));
160 hdr->is_csum_valid = true;
163 static const struct proto_ops tcp_proto_ops = {
164 .id = PROTO_TCP,
165 .layer = PROTO_L4,
166 .header_init = tcp_header_init,
167 .packet_update = tcp_csum_update,
168 .packet_finish = tcp_csum_update,
169 .field_changed = tcp_field_changed,
172 static struct proto_field icmpv4_fields[] = {
173 { .id = ICMPV4_TYPE, .len = 1, .offset = 0 },
174 { .id = ICMPV4_CODE, .len = 1, .offset = 1 },
175 { .id = ICMPV4_CSUM, .len = 2, .offset = 2 },
176 /* Echo/Ping fields */
177 { .id = ICMPV4_ID, .len = 2, .offset = 4 },
178 { .id = ICMPV4_SEQ, .len = 2, .offset = 6 },
179 /* Redirect field */
180 { .id = ICMPV4_REDIR_ADDR, .len = 4, .offset = 4 },
181 /* Next-hop MTU */
182 { .id = ICMPV4_MTU, .len = 2, .offset = 6 },
185 static void icmpv4_header_init(struct proto_hdr *hdr)
187 proto_lower_default_add(hdr, PROTO_IP4);
189 proto_header_fields_add(hdr, icmpv4_fields, array_size(icmpv4_fields));
192 static void icmpv4_csum_update(struct proto_hdr *hdr)
194 struct packet *pkt;
195 uint16_t csum;
197 if (hdr->is_csum_valid)
198 return;
199 if (proto_hdr_field_is_set(hdr, ICMPV4_CSUM))
200 return;
202 pkt = packet_get(hdr->pkt_id);
204 proto_hdr_field_set_default_u16(hdr, ICMPV4_CSUM, 0);
205 csum = htons(calc_csum(proto_header_ptr(hdr), pkt->len - hdr->pkt_offset));
206 proto_hdr_field_set_default_u16(hdr, ICMPV4_CSUM, bswap_16(csum));
208 hdr->is_csum_valid = true;
211 static void icmpv4_field_changed(struct proto_field *field)
213 field->hdr->is_csum_valid = false;
216 static const struct proto_ops icmpv4_proto_ops = {
217 .id = PROTO_ICMP4,
218 .layer = PROTO_L4,
219 .header_init = icmpv4_header_init,
220 .packet_update = icmpv4_csum_update,
221 .packet_finish = icmpv4_csum_update,
222 .field_changed = icmpv4_field_changed,
225 static struct proto_field icmpv6_fields[] = {
226 { .id = ICMPV6_TYPE, .len = 1, .offset = 0 },
227 { .id = ICMPV6_CODE, .len = 1, .offset = 1 },
228 { .id = ICMPV6_CSUM, .len = 2, .offset = 2 }
231 static void icmpv6_header_init(struct proto_hdr *hdr)
233 proto_lower_default_add(hdr, PROTO_IP6);
235 proto_header_fields_add(hdr, icmpv6_fields, array_size(icmpv6_fields));
238 static void icmpv6_csum_update(struct proto_hdr *hdr)
240 struct proto_hdr *lower = proto_lower_header(hdr);
241 struct packet *pkt = packet_get(hdr->pkt_id);
242 uint16_t total_len;
243 uint16_t csum;
245 if (unlikely(!lower))
246 return;
247 if (hdr->is_csum_valid)
248 return;
249 if (proto_hdr_field_is_set(hdr, ICMPV6_CSUM))
250 return;
252 total_len = pkt->len - hdr->pkt_offset;
254 proto_hdr_field_set_be16(hdr, ICMPV6_CSUM, 0);
256 if (likely(lower->ops->id == PROTO_IP6)) {
257 csum = p6_csum((void *) proto_header_ptr(lower), proto_header_ptr(hdr),
258 total_len, IPPROTO_ICMPV6);
260 proto_hdr_field_set_be16(hdr, ICMPV6_CSUM, bswap_16(csum));
261 hdr->is_csum_valid = true;
265 static void icmpv6_field_changed(struct proto_field *field)
267 field->hdr->is_csum_valid = false;
270 static struct proto_ops icmpv6_proto_ops = {
271 .id = PROTO_ICMP6,
272 .layer = PROTO_L4,
273 .header_init = icmpv6_header_init,
274 .packet_finish = icmpv6_csum_update,
275 .packet_update = icmpv6_csum_update,
276 .field_changed = icmpv6_field_changed,
279 void protos_l4_init(void)
281 proto_ops_register(&udp_proto_ops);
282 proto_ops_register(&tcp_proto_ops);
283 proto_ops_register(&icmpv4_proto_ops);
284 proto_ops_register(&icmpv6_proto_ops);