1 ;;;; Lysiane Bouchard - Vincent St-Amour
4 ;; TODO say what's really in here
5 ;;; - tcp state functions
6 ;;; - procedure called when a TCP packet is received:
10 ;; specific manipulations of some subfields
11 (define (get-tcp-flags) (modulo (u8vector-ref pkt tcp-flags) 64)) ;; TODO inline ?
13 ;; called when a TCP packet is received
15 ;; 40 is the sum of the sizesof the IP and TCP headers
16 (cond ((not (= (u8vector-ref pkt tcp-header-length-offset) 80)) ;; TODO have this 80 in a variable ?
17 ;; the packet has TCP options (header longer than 20 bytes), we reject
18 ;; it. since the length is then always 20 bytes, followed by 4 reserved
19 ;; bits (which must be set to 0), we simply must check if the byte is
20 ;; equal to (20 / 4) << 4 = 80
22 (if (or (= (pkt-ref-2 tcp-checksum) 0) ; valid or no checksum ?
23 (= 65535 (compute-tcp-checksum)))
24 (let ((port (search-port (pkt-ref-2 tcp-destination-portnum)
26 (if (and port (pass-app-filter? tcp-source-portnum port))
29 (let ((target-connection
31 (and (=conn-info-pkt? tcp-source-portnum c conn-peer-portnum 2)
32 (=conn-info-pkt? ip-source-ip c conn-peer-ip 4)
33 (=conn-info-pkt? ip-destination-ip c conn-self-ip 4)))
36 (begin (set! curr-conn target-connection)
37 ;; call the current state function
38 ((vector-ref target-connection conn-state-function)))
39 ;; no matching connection was found, if we have not yet
40 ;; reached the maximum number of connections, establish a
42 (if (and (< (length (get-curr-conns)) ; TODO do something if false ?
43 (conf-ref curr-port conf-max-conns))
44 ;; the handshake must begin with a SYN
45 (exclusive-tcp-flag? SYN))
46 (begin (new-conn) ; this sets the new connection as the current one
47 (self-acknowledgement) ;; TODO was in the call to transferts controller, but does it make any sense ?
48 (increment-curr-conn-info! tcp-peer-seqnum 4 1) ;; TODO 1, really ?
49 (pass-to-another-state tcp-syn-recv)
50 (tcp-transfers-controller (+ SYN ACK) 0))))))
51 (icmp-unreachable icmp-port-unreachable)))))
54 (define (compute-tcp-checksum)
57 ;; the UDP pseudo-header uses values located before the TCP header
58 (+ ip-header (pkt-ref-2 ip-length)) ; end of the TCP data
59 ;; start with the values of the pseudo-header that are not adjacent to the
60 ;; rest of the pseudo-header
61 (add-16bits-1comp 6 ; TCP protocol ID, with leading zeroes up to 16 bits
62 (- (pkt-ref-2 ip-length) ip-header-length)))) ; TCP length
66 ;;----------tcp state functions --------------------------------------------
69 ;; each one of those function garanties the behaviour of
70 ;; the tcp protocol according to a specific standard tcp state.
72 ;; tcp state time-wait
73 (define (tcp-time-wait)
74 (tcp-state-function (lambda () #t)))
76 ;; tcp state fin-wait-2
77 (define (tcp-fin-wait-2) ;; TODO most of the thunks sent to tcp-state-function are a test (usually for a flag, maybe more) and 1-2 thunks, maybe there is a way to optimize ? however, sometimes, there are actions after the if, or more than one if
81 (if (inclusive-tcp-flag? FIN)
82 (begin (increment-curr-conn-info! tcp-peer-seqnum 4 1) ;; TODO 1, really ?
83 (pass-to-another-state tcp-time-wait)
84 (tcp-transfers-controller ACK 0))
85 (tcp-transfers-controller 0 0)))))
91 (lambda () (if (and (inclusive-tcp-flag? ACK)
93 (begin (conn-info-set! curr-conn tcp-self-ack-units 1) ;; TODO 1, really ?
94 (pass-to-another-state tcp-time-wait)
95 (tcp-transfers-controller ACK 0))))))
98 ;; tcp state fin-wait-1
99 (define (tcp-fin-wait-1)
103 (if (inclusive-tcp-flag? FIN)
105 (if (and (inclusive-tcp-flag? ACK)
107 (begin (conn-info-set! curr-conn tcp-self-ack-units 1) ;; TODO 1, really ?
108 (increment-curr-conn-info! tcp-peer-seqnum 4 1) ;; TODO 1, really ?
109 (pass-to-another-state tcp-time-wait))
110 (begin (increment-curr-conn-info! tcp-peer-seqnum 4 1) ;; TODO 1, really ?
111 (pass-to-another-state tcp-closing)))
112 (tcp-transfers-controller ACK 0)) ;; TODO make sure this does what we want
113 (begin (if (and (inclusive-tcp-flag? ACK)
115 (begin (conn-info-set! curr-conn tcp-self-ack-units 1) ;; TODO 1, really ?
116 (pass-to-another-state tcp-fin-wait-2)))
117 (tcp-transfers-controller 0 0))))))
120 ;; tcp state last-ack
121 (define (tcp-last-ack)
123 (lambda () (if (and (inclusive-tcp-flag? ACK)
125 (detach-curr-conn)))))
128 ;; tcp state close-wait
129 (define (tcp-close-wait)
132 (if (and (inclusive-tcp-flag? ACK) (valid-acknum?))
133 (self-acknowledgement))
137 ;; tcp state established
138 (define (tcp-established)
141 (if (and (inclusive-tcp-flag? ACK) (valid-acknum?))
142 ;; we have received an ACK, we can consume the data that was
144 (buf-consume (vector-ref curr-conn conn-output)
145 (self-acknowledgement)))
147 (if (inclusive-tcp-flag? FIN)
148 (begin (conn-info-set! curr-conn tcp-self-ack-units 1) ;; TODO 1, really ?
149 (increment-curr-conn-info! tcp-peer-seqnum 4 1) ;; TODO 1, really ?
150 (pass-to-another-state tcp-close-wait)
152 (tcp-send-data 0)))))
154 ;; tcp state syn-received
155 (define (tcp-syn-recv)
157 (lambda () (cond ((inclusive-tcp-flag? FIN)
159 ((and (inclusive-tcp-flag? ACK) (valid-acknum?))
161 (conn-info-set! curr-conn tcp-self-ack-units 1) ;; TODO 1, really ?
162 (pass-to-another-state tcp-established)
164 (tcp-send-data 0))))))
167 ;; Tools for TCP state functions
169 ;; some codes for the TCP flags
178 ;; set the general connection state to ABORTED
179 ;; which means the connection cannot be used anymore because of a protocol
180 ;; error or a too long inactivity period.
182 (tcp-transfers-controller RST)
183 (detach-curr-conn)) ;; TODO abstract that last call ?
185 (define (tcp-state-function phase2)
186 (if (or (> (get-curr-elapsed-time) tcp-max-life-time) ; did the connection time out ?
187 ;; were there too many retransmission attempts for this packet
189 (> (conn-info-ref curr-conn tcp-attempts-count) tcp-attempts-limit))
191 (if (not (inclusive-tcp-flag? SYN)) ;; TODO do anything if it's a syn ?
192 (cond ((not (=conn-info-pkt? tcp-seqnum curr-conn
194 ;; we have received data (the peer's seqnum is ahead), ACK it TODO is that really it ? make sure wih the standard, perhaps this means we received data that is too far ahead, and we should wait for what comes before ?
195 (tcp-transfers-controller ACK))
196 ((inclusive-tcp-flag? RST)
201 (define (pass-to-another-state new-state-function)
202 (vector-set! curr-conn conn-state-function new-state-function)
203 (conn-info-set! curr-conn tcp-attempts-count 0)
204 (set-timestamp!)) ;; TODO now we have some repetition, all the 3 flags that were tested here and which called some functions, well, these functions are now called before this, all in the same way.
207 (define (tcp-receive-data)
208 (let ((in-amount (- (pkt-ref-2 ip-length) 40))) ; 40 is the sum of the IP and TCP header lengths TODO have in a var, or make picobit optimize these arithmetic operations
210 (begin (set-timestamp!)
211 (if (<= in-amount ;; TODO was restructured, the original didn't care whether input succeeded or not and just acnowledged without checking
212 (buf-free-space (vector-ref curr-conn conn-input)))
214 ;; copy data to connection input buffer
215 (copy-u8vector->buffer! pkt
217 (vector-ref curr-conn conn-input)
219 (buf-inc-amount (vector-ref curr-conn conn-input) ;; TODO cache the buffer
221 (increment-curr-conn-info! tcp-peer-seqnum 4 in-amount)
222 (turn-tcp-flag-on ACK)))))))
224 (define (tcp-send-data flags)
226 (if (and (> (conn-info-ref curr-conn tcp-self-ack-units) 0)
227 (>= (get-curr-elapsed-time) tcp-retransmission-delay))
228 ;; a retransmission is needed
229 (conn-info-ref curr-conn tcp-self-ack-units)
230 (curr-buf-get-amount))))
233 ;; copy data to connection output buffer
234 (copy-buffer->u8vector! (vector-ref curr-conn conn-output)
238 (increment-curr-conn-info! tcp-attempts-count 1 1)
239 (conn-info-set! curr-conn tcp-self-ack-units out-amount)
240 (turn-tcp-flag-on PSH)))
241 (tcp-transfers-controller flags out-amount)))
243 ;; TODO this is disgusting, it's called with booleans and there's no way to see what's going on without jumping to the definition
244 ;; TODO maybe use symbols to say what operations we will be making, keywords would be nice
245 (define (tcp-transfers-controller flags output-length) ;; TODO rethink this part, I doubt this really needs to be this way
246 (u8vector-set! pkt tcp-flags flags)
247 (if (> (u8vector-ref pkt tcp-flags) 0) ;; TODO flags were passed, and maybe psh was set, so maybe we can tell without a ref
249 (if (> flags 0) (increment-curr-conn-info! tcp-attempts-count 1 1)) ;; TODO what ? understand the rationale behind this
251 (tcp-encapsulation output-length))))
254 ;; to know if a particular tcp-flag is set
255 (define (inclusive-tcp-flag? tcp-flag)
256 (= (modulo (quotient (get-tcp-flags) tcp-flag) 2) 1))
258 ;; to know if only a particular tcp-flag is set
259 (define (exclusive-tcp-flag? flag)
260 (= flag (get-tcp-flags)))
262 ;; valid acknowledgement number ?
263 (define (valid-acknum?)
264 (let ((new-acknum (u8vector-ref-field (vector-ref curr-conn 0)
267 (u8vector-increment! new-acknum 0 4 (conn-info-ref curr-conn tcp-self-ack-units))
268 (u8vector-equal-field? pkt tcp-acknum new-acknum 0 4)))
270 (define (turn-tcp-flag-on flag)
271 (u8vector-set! pkt tcp-flags (bitwise-ior flag (u8vector-ref pkt tcp-flags))))
274 (define (self-acknowledgement) ;; TODO that's data that was sent but not acknowledged yet
275 (let ((ack-units (conn-info-ref curr-conn tcp-self-ack-units)))
276 (increment-curr-conn-info! tcp-self-seqnum 4 ack-units)
277 (conn-info-set! curr-conn tcp-self-ack-units 0)
278 (conn-info-set! curr-conn tcp-attempts-count 0)
283 (define (tcp-encapsulation output-length)
284 (let ((len (+ tcp-header-length output-length)))
285 (integer->pkt 0 tcp-urgent-data-pointer 2)
286 (integer->pkt 0 tcp-checksum 2)
287 (integer->pkt (buf-free-space (vector-ref curr-conn conn-input))
289 ;; the header length (in bytes) converted to 32-bit words and shifted 4
290 ;; bits to the left (4 reserved bits must be set to 0) which gives :
291 ;; (* (quotient tcp-header-length 4) 16)
292 (u8vector-set! pkt tcp-header-length-offset 80)
293 (copy-curr-conn-info->pkt tcp-acknum tcp-peer-seqnum 4)
294 (copy-curr-conn-info->pkt tcp-seqnum tcp-self-seqnum 4)
295 (copy-curr-conn-info->pkt tcp-destination-portnum conn-peer-portnum 2)
296 (integer->pkt (conf-ref curr-port conf-portnum) tcp-source-portnum 2)
298 (u8vector-ref-field (vector-ref curr-conn conn-info) conn-peer-ip 4)