-
Notifications
You must be signed in to change notification settings - Fork 0
/
tcp_sum.c
executable file
·106 lines (85 loc) · 3 KB
/
tcp_sum.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/* TCP checksum support--this is not used directly by students */
#include <stddef.h>
#include <assert.h>
#include <netinet/in.h>
#include "mysock_impl.h"
#include "transport.h"
#include "tcp_sum.h"
/* computes checksum for TCP segment, based on description in RFCs 793 and
* 1071, and Berkeley in_cksum().
*/
uint16_t _mysock_tcp_checksum(uint32_t src_addr /*network byte order*/,
uint32_t dst_addr /*network byte order*/,
const void *packet,
size_t len /*host byte order*/)
{
struct
{
uint32_t src_addr;
uint32_t dst_addr;
uint8_t zero;
uint8_t protocol;
uint16_t len;
} __attribute__ ((packed)) pseudo_header =
{
src_addr, dst_addr, 0, IPPROTO_TCP, htons(len)
};
unsigned int k;
int32_t sum = 0;
assert(packet && len >= sizeof(struct tcphdr));
assert(sizeof(pseudo_header) == 12);
assert(src_addr > 0);
assert(dst_addr > 0);
/* process 96-bit pseudo header */
for (k = 0; k < sizeof(pseudo_header) / sizeof(uint16_t); ++k)
sum += ((uint16_t *) &pseudo_header)[k];
/* process TCP header and payload */
assert(((long)packet & 2) == 0);
assert((offsetof(struct tcphdr, th_sum) & 2) == 0);
for (k = 0; k < (len >> 1); ++k)
{
if (k == (offsetof(struct tcphdr, th_sum) >> 1))
continue; /* th_sum == 0 during checksum computation */
sum += ((uint16_t *) packet)[k];
}
if (len & 1)
{
uint16_t tmp = 0;
*(uint8_t *) &tmp = ((uint8_t *) packet)[len - 1];
sum += tmp;
}
/* fold 32-bit sum to 16 bits */
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (uint16_t) ~sum;
}
/* update checksum in the given STCP segment */
void _mysock_set_checksum(const mysock_context_t *ctx,
void *packet, size_t len)
{
assert(ctx && packet);
assert(len >= sizeof(struct tcphdr));
assert(ctx->network_state.peer_addr.sa_family == AF_INET);
((struct tcphdr *) packet)->th_sum = _mysock_tcp_checksum(
_network_get_local_addr((network_context_t *)
&ctx->network_state), /*src*/
((struct sockaddr_in *) &ctx->network_state.peer_addr)-> /*dst*/
sin_addr.s_addr,
packet, len);
}
/* returns TRUE if checksum is correct, FALSE otherwise */
bool_t _mysock_verify_checksum(const mysock_context_t *ctx,
const void *packet, size_t len)
{
uint16_t my_sum;
assert(ctx && packet);
assert(len >= sizeof(struct tcphdr));
assert(ctx->network_state.peer_addr.sa_family == AF_INET);
my_sum = _mysock_tcp_checksum(
((struct sockaddr_in *) &ctx->network_state.peer_addr)-> /*src*/
sin_addr.s_addr,
_network_get_local_addr((network_context_t *)
&ctx->network_state), /*dst*/
packet, len);
return my_sum == ((struct tcphdr *) packet)->th_sum;
}