2 * netsniff-ng - the packet sniffing beast
3 * Subject to the GPL, version 2.
7 #include <netinet/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
;
42 if (hdr
->is_csum_valid
)
44 if (proto_field_is_set(hdr
, UDP_CSUM
))
46 lower
= proto_lower_header(hdr
);
50 total_len
= packet_get(hdr
->pkt_id
)->len
- hdr
->pkt_offset
;
52 proto_field_set_default_be16(hdr
, UDP_CSUM
, 0);
54 switch (lower
->ops
->id
) {
56 csum
= p4_csum((void *) proto_header_ptr(lower
), proto_header_ptr(hdr
),
57 total_len
, IPPROTO_UDP
);
60 csum
= p6_csum((void *) proto_header_ptr(lower
), proto_header_ptr(hdr
),
61 total_len
, IPPROTO_UDP
);
68 proto_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();
77 total_len
= pkt
->len
- hdr
->pkt_offset
;
78 proto_field_set_default_be16(hdr
, UDP_LEN
, total_len
);
83 static const struct proto_ops udp_proto_ops
= {
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_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();
133 if (hdr
->is_csum_valid
)
135 if (proto_field_is_set(hdr
, TCP_CSUM
))
141 total_len
= pkt
->len
- hdr
->pkt_offset
;
143 proto_field_set_default_be16(hdr
, TCP_CSUM
, 0);
145 switch (lower
->ops
->id
) {
147 csum
= p4_csum((void *) proto_header_ptr(lower
), proto_header_ptr(hdr
),
148 total_len
, IPPROTO_TCP
);
151 csum
= p6_csum((void *) proto_header_ptr(lower
), proto_header_ptr(hdr
),
152 total_len
, IPPROTO_TCP
);
159 proto_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
= {
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 },
180 { .id
= ICMPV4_REDIR_ADDR
, .len
= 4, .offset
= 4 },
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
)
197 if (hdr
->is_csum_valid
)
199 if (proto_field_is_set(hdr
, ICMPV4_CSUM
))
202 pkt
= packet_get(hdr
->pkt_id
);
204 proto_field_set_default_u16(hdr
, ICMPV4_CSUM
, 0);
205 csum
= htons(calc_csum(proto_header_ptr(hdr
), pkt
->len
- hdr
->pkt_offset
));
206 proto_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
= {
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
);
245 if (unlikely(!lower
))
247 if (hdr
->is_csum_valid
)
249 if (proto_field_is_set(hdr
, ICMPV6_CSUM
))
252 total_len
= pkt
->len
- hdr
->pkt_offset
;
254 proto_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_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
= {
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
);