Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / net / tcp.c
blob1d90f1ec5d0cec9595a09549aeeefe6fa29a5202
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010,2011 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/net.h>
20 #include <grub/net/ip.h>
21 #include <grub/net/tcp.h>
22 #include <grub/net/netbuff.h>
23 #include <grub/time.h>
24 #include <grub/priority_queue.h>
26 #define TCP_SYN_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL
27 #define TCP_SYN_RETRANSMISSION_COUNT GRUB_NET_TRIES
28 #define TCP_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL
29 #define TCP_RETRANSMISSION_COUNT GRUB_NET_TRIES
31 struct unacked
33 struct unacked *next;
34 struct unacked **prev;
35 struct grub_net_buff *nb;
36 grub_uint64_t last_try;
37 int try_count;
40 enum
42 TCP_FIN = 0x1,
43 TCP_SYN = 0x2,
44 TCP_RST = 0x4,
45 TCP_PUSH = 0x8,
46 TCP_ACK = 0x10,
47 TCP_URG = 0x20,
50 struct grub_net_tcp_socket
52 struct grub_net_tcp_socket *next;
53 struct grub_net_tcp_socket **prev;
55 int established;
56 int i_closed;
57 int they_closed;
58 int in_port;
59 int out_port;
60 int errors;
61 int they_reseted;
62 int i_reseted;
63 int i_stall;
64 grub_uint32_t my_start_seq;
65 grub_uint32_t my_cur_seq;
66 grub_uint32_t their_start_seq;
67 grub_uint32_t their_cur_seq;
68 grub_uint16_t my_window;
69 struct unacked *unack_first;
70 struct unacked *unack_last;
71 grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock, struct grub_net_buff *nb,
72 void *recv);
73 void (*error_hook) (grub_net_tcp_socket_t sock, void *recv);
74 void (*fin_hook) (grub_net_tcp_socket_t sock, void *recv);
75 void *hook_data;
76 grub_net_network_level_address_t out_nla;
77 grub_net_link_level_address_t ll_target_addr;
78 struct grub_net_network_level_interface *inf;
79 grub_net_packets_t packs;
80 grub_priority_queue_t pq;
83 struct grub_net_tcp_listen
85 struct grub_net_tcp_listen *next;
86 struct grub_net_tcp_listen **prev;
88 grub_uint16_t port;
89 const struct grub_net_network_level_interface *inf;
91 grub_err_t (*listen_hook) (grub_net_tcp_listen_t listen,
92 grub_net_tcp_socket_t sock,
93 void *data);
94 void *hook_data;
97 struct tcphdr
99 grub_uint16_t src;
100 grub_uint16_t dst;
101 grub_uint32_t seqnr;
102 grub_uint32_t ack;
103 grub_uint16_t flags;
104 grub_uint16_t window;
105 grub_uint16_t checksum;
106 grub_uint16_t urgent;
107 } GRUB_PACKED;
109 struct tcp_pseudohdr
111 grub_uint32_t src;
112 grub_uint32_t dst;
113 grub_uint8_t zero;
114 grub_uint8_t proto;
115 grub_uint16_t tcp_length;
116 } GRUB_PACKED;
118 struct tcp6_pseudohdr
120 grub_uint64_t src[2];
121 grub_uint64_t dst[2];
122 grub_uint32_t tcp_length;
123 grub_uint8_t zero[3];
124 grub_uint8_t proto;
125 } GRUB_PACKED;
127 static struct grub_net_tcp_socket *tcp_sockets;
128 static struct grub_net_tcp_listen *tcp_listens;
130 #define FOR_TCP_SOCKETS(var) FOR_LIST_ELEMENTS (var, tcp_sockets)
131 #define FOR_TCP_LISTENS(var) FOR_LIST_ELEMENTS (var, tcp_listens)
133 grub_net_tcp_listen_t
134 grub_net_tcp_listen (grub_uint16_t port,
135 const struct grub_net_network_level_interface *inf,
136 grub_err_t (*listen_hook) (grub_net_tcp_listen_t listen,
137 grub_net_tcp_socket_t sock,
138 void *data),
139 void *hook_data)
141 grub_net_tcp_listen_t ret;
142 ret = grub_malloc (sizeof (*ret));
143 if (!ret)
144 return NULL;
145 ret->listen_hook = listen_hook;
146 ret->hook_data = hook_data;
147 ret->port = port;
148 ret->inf = inf;
149 grub_list_push (GRUB_AS_LIST_P (&tcp_listens), GRUB_AS_LIST (ret));
150 return ret;
153 void
154 grub_net_tcp_stop_listen (grub_net_tcp_listen_t listen)
156 grub_list_remove (GRUB_AS_LIST (listen));
159 static inline void
160 tcp_socket_register (grub_net_tcp_socket_t sock)
162 grub_list_push (GRUB_AS_LIST_P (&tcp_sockets),
163 GRUB_AS_LIST (sock));
166 static void
167 error (grub_net_tcp_socket_t sock)
169 struct unacked *unack, *next;
171 if (sock->error_hook)
172 sock->error_hook (sock, sock->hook_data);
174 for (unack = sock->unack_first; unack; unack = next)
176 next = unack->next;
177 grub_netbuff_free (unack->nb);
178 grub_free (unack);
181 sock->unack_first = NULL;
182 sock->unack_last = NULL;
185 static grub_err_t
186 tcp_send (struct grub_net_buff *nb, grub_net_tcp_socket_t socket)
188 grub_err_t err;
189 grub_uint8_t *nbd;
190 struct unacked *unack;
191 struct tcphdr *tcph;
192 grub_size_t size;
194 tcph = (struct tcphdr *) nb->data;
196 tcph->seqnr = grub_cpu_to_be32 (socket->my_cur_seq);
197 size = (nb->tail - nb->data - (grub_be_to_cpu16 (tcph->flags) >> 12) * 4);
198 if (grub_be_to_cpu16 (tcph->flags) & TCP_FIN)
199 size++;
200 socket->my_cur_seq += size;
201 tcph->src = grub_cpu_to_be16 (socket->in_port);
202 tcph->dst = grub_cpu_to_be16 (socket->out_port);
203 tcph->checksum = 0;
204 tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
205 &socket->inf->address,
206 &socket->out_nla);
207 nbd = nb->data;
208 if (size)
210 unack = grub_malloc (sizeof (*unack));
211 if (!unack)
212 return grub_errno;
214 unack->next = NULL;
215 unack->nb = nb;
216 unack->try_count = 1;
217 unack->last_try = grub_get_time_ms ();
218 if (!socket->unack_last)
219 socket->unack_first = socket->unack_last = unack;
220 else
221 socket->unack_last->next = unack;
224 err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla),
225 &(socket->ll_target_addr), nb,
226 GRUB_NET_IP_TCP);
227 if (err)
228 return err;
229 nb->data = nbd;
230 if (!size)
231 grub_netbuff_free (nb);
232 return GRUB_ERR_NONE;
235 void
236 grub_net_tcp_close (grub_net_tcp_socket_t sock,
237 int discard_received)
239 struct grub_net_buff *nb_fin;
240 struct tcphdr *tcph_fin;
241 grub_err_t err;
243 if (discard_received != GRUB_NET_TCP_CONTINUE_RECEIVING)
245 sock->recv_hook = NULL;
246 sock->error_hook = NULL;
247 sock->fin_hook = NULL;
250 if (discard_received == GRUB_NET_TCP_ABORT)
251 sock->i_reseted = 1;
253 if (sock->i_closed)
254 return;
256 sock->i_closed = 1;
258 nb_fin = grub_netbuff_alloc (sizeof (*tcph_fin)
259 + GRUB_NET_OUR_MAX_IP_HEADER_SIZE
260 + GRUB_NET_MAX_LINK_HEADER_SIZE);
261 if (!nb_fin)
262 return;
263 err = grub_netbuff_reserve (nb_fin, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
264 + GRUB_NET_MAX_LINK_HEADER_SIZE);
265 if (err)
267 grub_netbuff_free (nb_fin);
268 grub_dprintf ("net", "error closing socket\n");
269 grub_errno = GRUB_ERR_NONE;
270 return;
273 err = grub_netbuff_put (nb_fin, sizeof (*tcph_fin));
274 if (err)
276 grub_netbuff_free (nb_fin);
277 grub_dprintf ("net", "error closing socket\n");
278 grub_errno = GRUB_ERR_NONE;
279 return;
281 tcph_fin = (void *) nb_fin->data;
282 tcph_fin->ack = grub_cpu_to_be32 (sock->their_cur_seq);
283 tcph_fin->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_FIN
284 | TCP_ACK);
285 tcph_fin->window = grub_cpu_to_be16_compile_time (0);
286 tcph_fin->urgent = 0;
287 err = tcp_send (nb_fin, sock);
288 if (err)
290 grub_netbuff_free (nb_fin);
291 grub_dprintf ("net", "error closing socket\n");
292 grub_errno = GRUB_ERR_NONE;
294 return;
297 static void
298 ack_real (grub_net_tcp_socket_t sock, int res)
300 struct grub_net_buff *nb_ack;
301 struct tcphdr *tcph_ack;
302 grub_err_t err;
304 nb_ack = grub_netbuff_alloc (sizeof (*tcph_ack) + 128);
305 if (!nb_ack)
306 return;
307 err = grub_netbuff_reserve (nb_ack, 128);
308 if (err)
310 grub_netbuff_free (nb_ack);
311 grub_dprintf ("net", "error closing socket\n");
312 grub_errno = GRUB_ERR_NONE;
313 return;
316 err = grub_netbuff_put (nb_ack, sizeof (*tcph_ack));
317 if (err)
319 grub_netbuff_free (nb_ack);
320 grub_dprintf ("net", "error closing socket\n");
321 grub_errno = GRUB_ERR_NONE;
322 return;
324 tcph_ack = (void *) nb_ack->data;
325 if (res)
327 tcph_ack->ack = grub_cpu_to_be32_compile_time (0);
328 tcph_ack->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_RST);
329 tcph_ack->window = grub_cpu_to_be16_compile_time (0);
331 else
333 tcph_ack->ack = grub_cpu_to_be32 (sock->their_cur_seq);
334 tcph_ack->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_ACK);
335 tcph_ack->window = !sock->i_stall ? grub_cpu_to_be16 (sock->my_window)
336 : 0;
338 tcph_ack->urgent = 0;
339 tcph_ack->src = grub_cpu_to_be16 (sock->in_port);
340 tcph_ack->dst = grub_cpu_to_be16 (sock->out_port);
341 err = tcp_send (nb_ack, sock);
342 if (err)
344 grub_dprintf ("net", "error acking socket\n");
345 grub_errno = GRUB_ERR_NONE;
349 static void
350 ack (grub_net_tcp_socket_t sock)
352 ack_real (sock, 0);
355 static void
356 reset (grub_net_tcp_socket_t sock)
358 ack_real (sock, 1);
361 void
362 grub_net_tcp_retransmit (void)
364 grub_net_tcp_socket_t sock;
365 grub_uint64_t ctime = grub_get_time_ms ();
366 grub_uint64_t limit_time = ctime - TCP_RETRANSMISSION_TIMEOUT;
368 FOR_TCP_SOCKETS (sock)
370 struct unacked *unack;
371 for (unack = sock->unack_first; unack; unack = unack->next)
373 struct tcphdr *tcph;
374 grub_uint8_t *nbd;
375 grub_err_t err;
377 if (unack->last_try > limit_time)
378 continue;
380 if (unack->try_count > TCP_RETRANSMISSION_COUNT)
382 error (sock);
383 break;
385 unack->try_count++;
386 unack->last_try = ctime;
387 nbd = unack->nb->data;
388 tcph = (struct tcphdr *) nbd;
390 if ((tcph->flags & grub_cpu_to_be16_compile_time (TCP_ACK))
391 && tcph->ack != grub_cpu_to_be32 (sock->their_cur_seq))
393 tcph->checksum = 0;
394 tcph->checksum = grub_net_ip_transport_checksum (unack->nb,
395 GRUB_NET_IP_TCP,
396 &sock->inf->address,
397 &sock->out_nla);
400 err = grub_net_send_ip_packet (sock->inf, &(sock->out_nla),
401 &(sock->ll_target_addr), unack->nb,
402 GRUB_NET_IP_TCP);
403 unack->nb->data = nbd;
404 if (err)
406 grub_dprintf ("net", "TCP retransmit failed: %s\n", grub_errmsg);
407 grub_errno = GRUB_ERR_NONE;
413 grub_uint16_t
414 grub_net_ip_transport_checksum (struct grub_net_buff *nb,
415 grub_uint16_t proto,
416 const grub_net_network_level_address_t *src,
417 const grub_net_network_level_address_t *dst)
419 grub_uint16_t a, b = 0;
420 grub_uint32_t c;
421 a = ~grub_be_to_cpu16 (grub_net_ip_chksum ((void *) nb->data,
422 nb->tail - nb->data));
424 switch (dst->type)
426 case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
428 struct tcp_pseudohdr ph;
429 ph.src = src->ipv4;
430 ph.dst = dst->ipv4;
431 ph.zero = 0;
432 ph.tcp_length = grub_cpu_to_be16 (nb->tail - nb->data);
433 ph.proto = proto;
434 b = ~grub_be_to_cpu16 (grub_net_ip_chksum ((void *) &ph, sizeof (ph)));
435 break;
437 case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
439 struct tcp6_pseudohdr ph;
440 grub_memcpy (ph.src, src->ipv6, sizeof (ph.src));
441 grub_memcpy (ph.dst, dst->ipv6, sizeof (ph.dst));
442 grub_memset (ph.zero, 0, sizeof (ph.zero));
443 ph.tcp_length = grub_cpu_to_be32 (nb->tail - nb->data);
444 ph.proto = proto;
445 b = ~grub_be_to_cpu16 (grub_net_ip_chksum ((void *) &ph, sizeof (ph)));
446 break;
448 case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
449 b = 0;
450 break;
452 c = (grub_uint32_t) a + (grub_uint32_t) b;
453 if (c >= 0xffff)
454 c -= 0xffff;
455 return grub_cpu_to_be16 (~c);
458 /* FIXME: overflow. */
459 static int
460 cmp (const void *a__, const void *b__)
462 struct grub_net_buff *a_ = *(struct grub_net_buff **) a__;
463 struct grub_net_buff *b_ = *(struct grub_net_buff **) b__;
464 struct tcphdr *a = (struct tcphdr *) a_->data;
465 struct tcphdr *b = (struct tcphdr *) b_->data;
466 /* We want the first elements to be on top. */
467 if (grub_be_to_cpu32 (a->seqnr) < grub_be_to_cpu32 (b->seqnr))
468 return +1;
469 if (grub_be_to_cpu32 (a->seqnr) > grub_be_to_cpu32 (b->seqnr))
470 return -1;
471 return 0;
474 static void
475 destroy_pq (grub_net_tcp_socket_t sock)
477 struct grub_net_buff **nb_p;
478 while ((nb_p = grub_priority_queue_top (sock->pq)))
480 grub_netbuff_free (*nb_p);
481 grub_priority_queue_pop (sock->pq);
484 grub_priority_queue_destroy (sock->pq);
487 grub_err_t
488 grub_net_tcp_accept (grub_net_tcp_socket_t sock,
489 grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock,
490 struct grub_net_buff *nb,
491 void *data),
492 void (*error_hook) (grub_net_tcp_socket_t sock,
493 void *data),
494 void (*fin_hook) (grub_net_tcp_socket_t sock,
495 void *data),
496 void *hook_data)
498 struct grub_net_buff *nb_ack;
499 struct tcphdr *tcph;
500 grub_err_t err;
502 sock->recv_hook = recv_hook;
503 sock->error_hook = error_hook;
504 sock->fin_hook = fin_hook;
505 sock->hook_data = hook_data;
506 nb_ack = grub_netbuff_alloc (sizeof (*tcph)
507 + GRUB_NET_OUR_MAX_IP_HEADER_SIZE
508 + GRUB_NET_MAX_LINK_HEADER_SIZE);
509 if (!nb_ack)
510 return grub_errno;
511 err = grub_netbuff_reserve (nb_ack, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
512 + GRUB_NET_MAX_LINK_HEADER_SIZE);
513 if (err)
515 grub_netbuff_free (nb_ack);
516 return err;
519 err = grub_netbuff_put (nb_ack, sizeof (*tcph));
520 if (err)
522 grub_netbuff_free (nb_ack);
523 return err;
525 tcph = (void *) nb_ack->data;
526 tcph->ack = grub_cpu_to_be32 (sock->their_cur_seq);
527 tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN | TCP_ACK);
528 tcph->window = grub_cpu_to_be16 (sock->my_window);
529 tcph->urgent = 0;
530 sock->established = 1;
531 tcp_socket_register (sock);
532 err = tcp_send (nb_ack, sock);
533 if (err)
534 return err;
535 sock->my_cur_seq++;
536 return GRUB_ERR_NONE;
539 grub_net_tcp_socket_t
540 grub_net_tcp_open (char *server,
541 grub_uint16_t out_port,
542 grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock,
543 struct grub_net_buff *nb,
544 void *data),
545 void (*error_hook) (grub_net_tcp_socket_t sock,
546 void *data),
547 void (*fin_hook) (grub_net_tcp_socket_t sock,
548 void *data),
549 void *hook_data)
551 grub_err_t err;
552 grub_net_network_level_address_t addr;
553 struct grub_net_network_level_interface *inf;
554 grub_net_network_level_address_t gateway;
555 grub_net_tcp_socket_t socket;
556 static grub_uint16_t in_port = 21550;
557 struct grub_net_buff *nb;
558 struct tcphdr *tcph;
559 int i;
560 grub_uint8_t *nbd;
561 grub_net_link_level_address_t ll_target_addr;
563 err = grub_net_resolve_address (server, &addr);
564 if (err)
565 return NULL;
567 if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
568 && addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6)
570 grub_error (GRUB_ERR_BUG, "not an IP address");
571 return NULL;
574 err = grub_net_route_address (addr, &gateway, &inf);
575 if (err)
576 return NULL;
578 err = grub_net_link_layer_resolve (inf, &gateway, &ll_target_addr);
579 if (err)
580 return NULL;
582 socket = grub_zalloc (sizeof (*socket));
583 if (socket == NULL)
584 return NULL;
586 socket->out_port = out_port;
587 socket->inf = inf;
588 socket->out_nla = addr;
589 socket->ll_target_addr = ll_target_addr;
590 socket->in_port = in_port++;
591 socket->recv_hook = recv_hook;
592 socket->error_hook = error_hook;
593 socket->fin_hook = fin_hook;
594 socket->hook_data = hook_data;
596 nb = grub_netbuff_alloc (sizeof (*tcph) + 128);
597 if (!nb)
598 return NULL;
599 err = grub_netbuff_reserve (nb, 128);
600 if (err)
602 grub_netbuff_free (nb);
603 return NULL;
606 err = grub_netbuff_put (nb, sizeof (*tcph));
607 if (err)
609 grub_netbuff_free (nb);
610 return NULL;
612 socket->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *), cmp);
613 if (!socket->pq)
615 grub_netbuff_free (nb);
616 return NULL;
619 tcph = (void *) nb->data;
620 socket->my_start_seq = grub_get_time_ms ();
621 socket->my_cur_seq = socket->my_start_seq + 1;
622 socket->my_window = 8192;
623 tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq);
624 tcph->ack = grub_cpu_to_be32_compile_time (0);
625 tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN);
626 tcph->window = grub_cpu_to_be16 (socket->my_window);
627 tcph->urgent = 0;
628 tcph->src = grub_cpu_to_be16 (socket->in_port);
629 tcph->dst = grub_cpu_to_be16 (socket->out_port);
630 tcph->checksum = 0;
631 tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
632 &socket->inf->address,
633 &socket->out_nla);
635 tcp_socket_register (socket);
637 nbd = nb->data;
638 for (i = 0; i < TCP_SYN_RETRANSMISSION_COUNT; i++)
640 int j;
641 nb->data = nbd;
642 err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla),
643 &(socket->ll_target_addr), nb,
644 GRUB_NET_IP_TCP);
645 if (err)
647 grub_list_remove (GRUB_AS_LIST (socket));
648 grub_free (socket);
649 grub_netbuff_free (nb);
650 return NULL;
652 for (j = 0; (j < TCP_SYN_RETRANSMISSION_TIMEOUT / 50
653 && !socket->established); j++)
654 grub_net_poll_cards (50, &socket->established);
655 if (socket->established)
656 break;
658 if (!socket->established)
660 grub_list_remove (GRUB_AS_LIST (socket));
661 if (socket->they_reseted)
662 grub_error (GRUB_ERR_NET_PORT_CLOSED,
663 N_("connection refused"));
664 else
665 grub_error (GRUB_ERR_NET_NO_ANSWER,
666 N_("connection timeout"));
668 grub_netbuff_free (nb);
669 destroy_pq (socket);
670 grub_free (socket);
671 return NULL;
674 grub_netbuff_free (nb);
675 return socket;
678 grub_err_t
679 grub_net_send_tcp_packet (const grub_net_tcp_socket_t socket,
680 struct grub_net_buff *nb, int push)
682 struct tcphdr *tcph;
683 grub_err_t err;
684 grub_ssize_t fraglen;
685 COMPILE_TIME_ASSERT (sizeof (struct tcphdr) == GRUB_NET_TCP_HEADER_SIZE);
686 if (socket->out_nla.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
687 fraglen = (socket->inf->card->mtu - GRUB_NET_OUR_IPV4_HEADER_SIZE
688 - sizeof (*tcph));
689 else
690 fraglen = 1280 - GRUB_NET_OUR_IPV6_HEADER_SIZE;
692 while (nb->tail - nb->data > fraglen)
694 struct grub_net_buff *nb2;
696 nb2 = grub_netbuff_alloc (fraglen + sizeof (*tcph)
697 + GRUB_NET_OUR_MAX_IP_HEADER_SIZE
698 + GRUB_NET_MAX_LINK_HEADER_SIZE);
699 if (!nb2)
700 return grub_errno;
701 err = grub_netbuff_reserve (nb2, GRUB_NET_MAX_LINK_HEADER_SIZE
702 + GRUB_NET_OUR_MAX_IP_HEADER_SIZE);
703 if (err)
704 return err;
705 err = grub_netbuff_put (nb2, sizeof (*tcph));
706 if (err)
707 return err;
709 tcph = (struct tcphdr *) nb2->data;
710 tcph->ack = grub_cpu_to_be32 (socket->their_cur_seq);
711 tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_ACK);
712 tcph->window = !socket->i_stall ? grub_cpu_to_be16 (socket->my_window)
713 : 0;
714 tcph->urgent = 0;
715 err = grub_netbuff_put (nb2, fraglen);
716 if (err)
717 return err;
718 grub_memcpy (tcph + 1, nb->data, fraglen);
719 err = grub_netbuff_pull (nb, fraglen);
720 if (err)
721 return err;
723 err = tcp_send (nb2, socket);
724 if (err)
725 return err;
728 err = grub_netbuff_push (nb, sizeof (*tcph));
729 if (err)
730 return err;
732 tcph = (struct tcphdr *) nb->data;
733 tcph->ack = grub_cpu_to_be32 (socket->their_cur_seq);
734 tcph->flags = (grub_cpu_to_be16_compile_time ((5 << 12) | TCP_ACK)
735 | (push ? grub_cpu_to_be16_compile_time (TCP_PUSH) : 0));
736 tcph->window = !socket->i_stall ? grub_cpu_to_be16 (socket->my_window) : 0;
737 tcph->urgent = 0;
738 return tcp_send (nb, socket);
741 grub_err_t
742 grub_net_recv_tcp_packet (struct grub_net_buff *nb,
743 struct grub_net_network_level_interface *inf,
744 const grub_net_network_level_address_t *source)
746 struct tcphdr *tcph;
747 grub_net_tcp_socket_t sock;
748 grub_err_t err;
750 /* Ignore broadcast. */
751 if (!inf)
753 grub_netbuff_free (nb);
754 return GRUB_ERR_NONE;
757 tcph = (struct tcphdr *) nb->data;
758 if ((grub_be_to_cpu16 (tcph->flags) >> 12) < 5)
760 grub_dprintf ("net", "TCP header too short: %u\n",
761 grub_be_to_cpu16 (tcph->flags) >> 12);
762 grub_netbuff_free (nb);
763 return GRUB_ERR_NONE;
765 if (nb->tail - nb->data < (grub_ssize_t) ((grub_be_to_cpu16 (tcph->flags)
766 >> 12) * sizeof (grub_uint32_t)))
768 grub_dprintf ("net", "TCP packet too short: %" PRIuGRUB_SIZE "\n",
769 (grub_size_t) (nb->tail - nb->data));
770 grub_netbuff_free (nb);
771 return GRUB_ERR_NONE;
774 FOR_TCP_SOCKETS (sock)
776 if (!(grub_be_to_cpu16 (tcph->dst) == sock->in_port
777 && grub_be_to_cpu16 (tcph->src) == sock->out_port
778 && inf == sock->inf
779 && grub_net_addr_cmp (source, &sock->out_nla) == 0))
780 continue;
781 if (tcph->checksum)
783 grub_uint16_t chk, expected;
784 chk = tcph->checksum;
785 tcph->checksum = 0;
786 expected = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
787 &sock->out_nla,
788 &sock->inf->address);
789 if (expected != chk)
791 grub_dprintf ("net", "Invalid TCP checksum. "
792 "Expected %x, got %x\n",
793 grub_be_to_cpu16 (expected),
794 grub_be_to_cpu16 (chk));
795 grub_netbuff_free (nb);
796 return GRUB_ERR_NONE;
798 tcph->checksum = chk;
801 if ((grub_be_to_cpu16 (tcph->flags) & TCP_SYN)
802 && (grub_be_to_cpu16 (tcph->flags) & TCP_ACK)
803 && !sock->established)
805 sock->their_start_seq = grub_be_to_cpu32 (tcph->seqnr);
806 sock->their_cur_seq = sock->their_start_seq + 1;
807 sock->established = 1;
810 if (grub_be_to_cpu16 (tcph->flags) & TCP_RST)
812 sock->they_reseted = 1;
814 error (sock);
816 grub_netbuff_free (nb);
818 return GRUB_ERR_NONE;
821 if (grub_be_to_cpu16 (tcph->flags) & TCP_ACK)
823 struct unacked *unack, *next;
824 grub_uint32_t acked = grub_be_to_cpu32 (tcph->ack);
825 for (unack = sock->unack_first; unack; unack = next)
827 grub_uint32_t seqnr;
828 struct tcphdr *unack_tcph;
829 next = unack->next;
830 seqnr = grub_be_to_cpu32 (((struct tcphdr *) unack->nb->data)
831 ->seqnr);
832 unack_tcph = (struct tcphdr *) unack->nb->data;
833 seqnr += (unack->nb->tail - unack->nb->data
834 - (grub_be_to_cpu16 (unack_tcph->flags) >> 12) * 4);
835 if (grub_be_to_cpu16 (unack_tcph->flags) & TCP_FIN)
836 seqnr++;
838 if (seqnr > acked)
839 break;
840 grub_netbuff_free (unack->nb);
841 grub_free (unack);
843 sock->unack_first = unack;
844 if (!sock->unack_first)
845 sock->unack_last = NULL;
848 if (grub_be_to_cpu32 (tcph->seqnr) < sock->their_cur_seq)
850 ack (sock);
851 grub_netbuff_free (nb);
852 return GRUB_ERR_NONE;
854 if (sock->i_reseted && (nb->tail - nb->data
855 - (grub_be_to_cpu16 (tcph->flags)
856 >> 12) * sizeof (grub_uint32_t)) > 0)
858 reset (sock);
861 err = grub_priority_queue_push (sock->pq, &nb);
862 if (err)
864 grub_netbuff_free (nb);
865 return err;
869 struct grub_net_buff **nb_top_p, *nb_top;
870 int do_ack = 0;
871 int just_closed = 0;
872 while (1)
874 nb_top_p = grub_priority_queue_top (sock->pq);
875 if (!nb_top_p)
876 return GRUB_ERR_NONE;
877 nb_top = *nb_top_p;
878 tcph = (struct tcphdr *) nb_top->data;
879 if (grub_be_to_cpu32 (tcph->seqnr) >= sock->their_cur_seq)
880 break;
881 grub_netbuff_free (nb_top);
882 grub_priority_queue_pop (sock->pq);
884 if (grub_be_to_cpu32 (tcph->seqnr) != sock->their_cur_seq)
885 return GRUB_ERR_NONE;
886 while (1)
888 nb_top_p = grub_priority_queue_top (sock->pq);
889 if (!nb_top_p)
890 break;
891 nb_top = *nb_top_p;
892 tcph = (struct tcphdr *) nb_top->data;
894 if (grub_be_to_cpu32 (tcph->seqnr) != sock->their_cur_seq)
895 break;
896 grub_priority_queue_pop (sock->pq);
898 err = grub_netbuff_pull (nb_top, (grub_be_to_cpu16 (tcph->flags)
899 >> 12) * sizeof (grub_uint32_t));
900 if (err)
902 grub_netbuff_free (nb_top);
903 return err;
906 sock->their_cur_seq += (nb_top->tail - nb_top->data);
907 if (grub_be_to_cpu16 (tcph->flags) & TCP_FIN)
909 sock->they_closed = 1;
910 just_closed = 1;
911 sock->their_cur_seq++;
912 do_ack = 1;
914 /* If there is data, puts packet in socket list. */
915 if ((nb_top->tail - nb_top->data) > 0)
917 grub_net_put_packet (&sock->packs, nb_top);
918 do_ack = 1;
920 else
921 grub_netbuff_free (nb_top);
923 if (do_ack)
924 ack (sock);
925 while (sock->packs.first)
927 nb = sock->packs.first->nb;
928 if (sock->recv_hook)
929 sock->recv_hook (sock, sock->packs.first->nb, sock->hook_data);
930 else
931 grub_netbuff_free (nb);
932 grub_net_remove_packet (sock->packs.first);
935 if (sock->fin_hook && just_closed)
936 sock->fin_hook (sock, sock->hook_data);
939 return GRUB_ERR_NONE;
941 if (grub_be_to_cpu16 (tcph->flags) & TCP_SYN)
943 grub_net_tcp_listen_t listen;
945 FOR_TCP_LISTENS (listen)
947 if (!(grub_be_to_cpu16 (tcph->dst) == listen->port
948 && (inf == listen->inf || listen->inf == NULL)))
949 continue;
950 sock = grub_zalloc (sizeof (*sock));
951 if (sock == NULL)
952 return grub_errno;
954 sock->out_port = grub_be_to_cpu16 (tcph->src);
955 sock->in_port = grub_be_to_cpu16 (tcph->dst);
956 sock->inf = inf;
957 sock->out_nla = *source;
958 sock->their_start_seq = grub_be_to_cpu32 (tcph->seqnr);
959 sock->their_cur_seq = sock->their_start_seq + 1;
960 sock->my_cur_seq = sock->my_start_seq = grub_get_time_ms ();
961 sock->my_window = 8192;
963 sock->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *),
964 cmp);
965 if (!sock->pq)
967 grub_netbuff_free (nb);
968 return grub_errno;
971 err = listen->listen_hook (listen, sock, listen->hook_data);
973 grub_netbuff_free (nb);
974 return err;
978 grub_netbuff_free (nb);
979 return GRUB_ERR_NONE;
982 void
983 grub_net_tcp_stall (grub_net_tcp_socket_t sock)
985 if (sock->i_stall)
986 return;
987 sock->i_stall = 1;
988 ack (sock);
991 void
992 grub_net_tcp_unstall (grub_net_tcp_socket_t sock)
994 if (!sock->i_stall)
995 return;
996 sock->i_stall = 0;
997 ack (sock);