2 * Netgrind -- TCP Layer Analyser
4 * (c) 2003 Martin Mares <mj@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU General Public License.
14 #include "netgrind/pkt.h"
15 #include "netgrind/netgrind.h"
20 #include <netinet/in.h>
21 #include <netinet/ip.h>
22 #include <netinet/tcp.h>
26 struct pkt_stats stat_tcp_in, stat_tcp_invalid, stat_tcp_badsum, stat_tcp_unmatched,
29 static byte *pipe_state_names[] = { "IDLE", "SYNSENT", "SYNACK", "ESTAB", "FINSENT", "FINISH" };
31 static uns num_flows, max_flows;
32 static struct flow **flow_hash;
33 static struct flow **flow_heap;
35 static uns flow_calc_hash(u32 saddr, u32 daddr, u32 sport, u32 dport)
37 saddr = (saddr >> 16) | (saddr << 16);
38 daddr = (daddr >> 8) | (daddr << 24);
41 return (saddr + daddr + sport + dport) % max_flows;
44 #define FLOW_HEAP_LESS(a,b) (a->timeout < b->timeout)
45 #define FLOW_HEAP_SWAP(h,a,b,t) do { t=h[a]; h[a]=h[b]; h[b]=t; h[a]->heap_pos=a; h[b]->heap_pos=b; } while(0)
47 static void flow_rehash(void)
50 struct flow **ohash = flow_hash;
55 max_flows = nextprime(2*max_flows);
58 DBG("Rehashing to %d buckets\n", max_flows);
59 flow_hash = xmalloc_zero(sizeof(struct flow *) * max_flows);
60 flow_heap = xmalloc_zero(sizeof(struct flow *) * (max_flows+1));
62 for (uns i=0; i<omax; i++)
64 struct flow *f = ohash[i];
67 struct flow *n = f->hash_next;
68 uns h = flow_calc_hash(f->saddr, f->daddr, f->sport, f->dport);
69 f->hash_next = flow_hash[h];
71 flow_heap[++num_flows] = f;
72 f->heap_pos = num_flows;
78 HEAP_INIT(struct flow *, flow_heap, num_flows, FLOW_HEAP_LESS, FLOW_HEAP_SWAP);
81 static struct flow *flow_lookup(u32 saddr, u32 daddr, u32 sport, u32 dport)
83 uns h = flow_calc_hash(saddr, daddr, sport, dport);
84 for (struct flow *f = flow_hash[h]; f; f=f->hash_next)
85 if (f->saddr == saddr && f->daddr == daddr &&
86 f->sport == sport && f->dport == dport)
91 static struct flow *flow_create(u32 saddr, u32 daddr, u32 sport, u32 dport)
93 if (num_flows >= max_flows)
95 uns h = flow_calc_hash(saddr, daddr, sport, dport);
96 struct flow *f = xmalloc_zero(sizeof(struct flow));
102 f->hash_next = flow_hash[h];
104 flow_heap[++num_flows] = f;
105 f->heap_pos = num_flows;
109 static void flow_set_timeout(struct flow *f, u32 when)
112 HEAP_CHANGE(struct flow *, flow_heap, num_flows, FLOW_HEAP_LESS, FLOW_HEAP_SWAP, f->heap_pos);
115 static uns flow_now(struct pkt *p)
117 return p->timestamp >> 20;
120 static u64 flow_now_to_time(uns now)
122 return (u64)now << 20;
125 static inline int tcp_seq_le(u32 a, u32 b)
127 return ((b - a) < 0x80000000);
130 static inline int tcp_seq_lt(u32 a, u32 b)
132 return (a != b && tcp_seq_le(a, b));
135 static void tcp_time_step(uns now)
137 while (num_flows && flow_heap[1]->timeout <= now)
139 struct flow *f = flow_heap[1];
140 HEAP_DELMIN(struct flow *, flow_heap, num_flows, FLOW_HEAP_LESS, FLOW_HEAP_SWAP);
141 DBG("TIMEOUT for flow %p(%s/%s)\n", f, pipe_state_names[f->pipe[0].state], pipe_state_names[f->pipe[1].state]);
142 if (f->pipe[0].state != FLOW_FINISHED || f->pipe[1].state != FLOW_FINISHED)
143 f->appl->close(f, (now == ~0U) ? CAUSE_DOOMSDAY : CAUSE_TIMEOUT, flow_now_to_time(now));
144 uns h = flow_calc_hash(f->saddr, f->daddr, f->sport, f->dport);
145 struct flow **gg = &flow_hash[h];
154 gg = &(*gg)->hash_next;
160 static void tcp_enqueue_data(struct pipe *b, struct pkt *p)
162 struct pkt *q, *prev, *new;
166 if (tcp_seq_lt(b->last_acked_seq, p->seq) && p->seq - b->last_acked_seq >= 0x40000)
168 DBG(" OUT OF WINDOW (last-ack=%u)\n", b->last_acked_seq);
172 prev = (struct pkt *) &b->queue.head;
173 last_seq = b->last_acked_seq;
176 if (tcp_seq_lt(p->seq, last_seq))
178 if (tcp_seq_le(p->seq + pkt_len(p), last_seq))
184 pkt_pop(p, p->seq + pkt_len(p) - last_seq);
188 q = list_next(&b->queue, &prev->n);
189 if (q && tcp_seq_le(q->seq, p->seq))
191 /* next packet starts before us => skip it */
193 last_seq = q->seq + pkt_len(q);
198 if (q && tcp_seq_lt(q->seq, p->seq + pkt_len(p)))
200 /* overlap with next packet => split */
202 uns keeplen = q->seq - p->seq;
203 uns newlen = pkt_len(p) - keeplen;
204 new = pkt_new(0, newlen);
205 memcpy(pkt_append(new, newlen), pkt_unappend(p, newlen), newlen);
206 new->seq = p->seq + keeplen;
209 list_insert(&p->n, &prev->n);
211 last_seq = p->seq + pkt_len(p);
218 void tcp_got_packet(struct iphdr *iph, struct pkt *p)
228 uns now = flow_now(p);
232 pkt_account(&stat_tcp_in, p);
233 if (!(tcph = pkt_peek(p, sizeof(*tcph))))
235 uns hdrlen = 4*tcph->doff;
236 if (hdrlen < sizeof(*tcph) || hdrlen > pkt_len(p))
238 fakehdr.src = iph->saddr;
239 fakehdr.dst = iph->daddr;
241 fakehdr.proto = IPPROTO_TCP;
242 fakehdr.len = htons(pkt_len(p));
243 uns sum = tcpip_calc_checksum(&fakehdr, sizeof(fakehdr), 0);
244 sum = tcpip_calc_checksum(p->data, pkt_len(p), sum);
245 if (!tcpip_verify_checksum(sum))
247 pkt_account(&stat_tcp_badsum, p);
250 /* XXX: Check TCP options? */
253 u32 seq = ntohl(tcph->seq);
254 u32 ack = ntohl(tcph->ack_seq);
255 DBG("TCP %08x %08x %04x %04x seq=%u+%u ack=%u%s%s%s%s%s%s\n",
256 ntohl(iph->saddr), ntohl(iph->daddr), ntohs(tcph->source), ntohs(tcph->dest), seq, pkt_len(p), ack,
257 (tcph->fin ? " FIN" : ""),
258 (tcph->syn ? " SYN" : ""),
259 (tcph->rst ? " RST" : ""),
260 (tcph->psh ? " PSH" : ""),
261 (tcph->ack ? " ACK" : ""),
262 (tcph->urg ? " URG" : ""));
266 if (f = flow_lookup(iph->saddr, iph->daddr, tcph->source, tcph->dest))
271 else if (f = flow_lookup(iph->daddr, iph->saddr, tcph->dest, tcph->source))
278 /* Flow not found, if it's a SYN packet, go create it */
279 if (tcph->syn && !tcph->ack && !tcph->rst && !tcph->fin)
281 f = flow_create(iph->saddr, iph->daddr, tcph->source, tcph->dest);
282 f->appl = &appl_asave;
283 f->appl->open(f, p->timestamp);
286 list_init(&a->queue);
287 a->syn_or_fin_seq = a->last_acked_seq = seq;
288 a->state = FLOW_SYN_SENT;
289 list_init(&b->queue);
290 b->state = FLOW_IDLE;
291 DBG("\t%p NEW\n", f);
294 DBG("\tUnmatched\n");
295 pkt_account(&stat_tcp_unmatched, p);
299 DBG("\t%p %s (%s/%s) ", f, (a == &f->pipe[0] ? "A->B" : "B->A"), pipe_state_names[f->pipe[0].state], pipe_state_names[f->pipe[1].state]);
300 if (a->state == FLOW_FINISHED && b->state == FLOW_FINISHED)
303 pkt_account(&stat_tcp_on_closed, p);
310 f->appl->close(f, CAUSE_RESET, p->timestamp);
311 a->state = b->state = FLOW_FINISHED;
312 flow_set_timeout(f, now + 300); /* FIXME */
316 flow_set_timeout(f, now + 600); /* FIXME */
320 if (tcph->fin || pkt_len(p))
324 if (b->state == FLOW_SYN_SENT && b->syn_or_fin_seq+1 == ack)
327 a->last_acked_seq = ack;
328 a->syn_or_fin_seq = seq;
329 a->state = FLOW_SYN_SENT_ACK;
330 b->last_acked_seq = seq;
333 else if (b->state == FLOW_ESTABLISHED)
339 goto dup; /* otherwise SYN on already existing connection gets ignored */
344 if (tcp_seq_le(ack, a->last_acked_seq))
349 a->last_acked_seq = ack;
350 while ((q = list_head(&a->queue)) && tcp_seq_le(q->seq+pkt_len(q), ack))
353 q->timestamp = p->timestamp;
354 DBG("data(%Ld-%Ld), ", a->stat_in.bytes, a->stat_in.bytes+pkt_len(q)-1);
355 pkt_account(&a->stat_in, q);
356 f->appl->input(f, (a == &f->pipe[0]), q);
358 if (b->state == FLOW_SYN_SENT_ACK && b->syn_or_fin_seq+1 == ack)
360 a->state = b->state = FLOW_ESTABLISHED;
363 else if (b->state == FLOW_FIN_SENT && b->syn_or_fin_seq+1 == ack)
365 b->state = FLOW_FINISHED;
366 if (a->state == FLOW_FINISHED)
368 DBG("CLOSED BOTH WAYS\n");
369 f->appl->close(f, CAUSE_CLOSE, p->timestamp);
370 flow_set_timeout(f, now + 300); /* FIXME */
374 DBG("CLOSED ONE-WAY, ");
376 else if ((q = list_head(&a->queue)) && tcp_seq_lt(ack, q->seq))
378 DBG("DAMNED, ACK FOR UNCAUGHT DATA!\n");
381 else if (b->state == FLOW_SYN_SENT_ACK || b->state == FLOW_SYN_SENT)
388 if (a->state == FLOW_ESTABLISHED)
390 a->state = FLOW_FIN_SENT;
391 a->syn_or_fin_seq = seq;
392 DBG("FIN SENT, waiting for FIN ACK, ");
394 else if (a->state == FLOW_FIN_SENT)
406 if (b->state == FLOW_ESTABLISHED || b->state == FLOW_FIN_SENT || b->state == FLOW_FINISHED)
409 tcp_enqueue_data(b, p);
430 pkt_account(&stat_tcp_invalid, p);
439 void tcp_cleanup(void)