Fixed ZDE build - missing header file
[ZeXOS.git] / kernel / core / net / tcp6.c
blobae6adc205c03da1a52a8da8c9ada933066e106d2
1 /*
2 * ZeX/OS
3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <system.h>
23 #include <string.h>
24 #include <dev.h>
25 #include <net/eth.h>
26 #include <net/net.h>
27 #include <net/if.h>
28 #include <net/packet.h>
29 #include <net/ip.h>
30 #include <net/ndp.h>
31 #include <net/tcp.h>
32 #include <net/tun.h>
33 #include <net/socket.h>
34 #include <mutex.h>
35 #include <errno.h>
36 #include <fd.h>
38 /* Mutex for socket function */
39 MUTEX_CREATE (mutex_tcp6_accept);
40 MUTEX_CREATE (mutex_tcp6_read_cache);
42 proto_tcp6_conn_t proto_tcp6_conn_list;
43 proto_tcp6_backlog_t proto_tcp6_backlog_list;
45 extern netif_t netif_list;
47 static unsigned short proto_tcp6_dup;
48 static unsigned proto_tcp6_seq;
49 static proto_ipv6_t proto_ipv6_prealloc;
50 static proto_tcp_t proto_tcp_prealloc;
51 static packet_t packet_prealloc;
52 static char buf_tcp_prealloc[NET_PACKET_MTU + sizeof (proto_tcp_t) + 1];
54 /* prototype */
55 proto_tcp6_conn_t *net_proto_tcp6_conn_check (net_ipv6 ip_source, net_port port_source, net_ipv6 ip_dest, net_port port_dest, unsigned char *ret);
56 int net_proto_tcp6_conn_add ();
57 int net_proto_tcp6_conn_set (proto_tcp6_conn_t *conn, netif_t *eth, net_port port_source, net_ipv6 ip_dest, net_port port_dest);
58 int net_proto_tcp6_conn_estabilish (proto_tcp6_conn_t *conn, netif_t *eth, net_ipv6 ip_dest, net_port port_dest);
59 int net_proto_tcp6_conn_estabilish_reply (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old);
60 int net_proto_tcp6_read_cache (proto_tcp6_conn_t *conn, char *data, unsigned len);
61 int net_proto_tcp6_read_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old, unsigned len);
62 int net_proto_tcp6_write (netif_t *eth, net_ipv6 dest, proto_tcp_t *tcp, char *data, unsigned len);
63 int net_proto_tcp6_write_data (proto_tcp6_conn_t *conn, char *data, unsigned len);
64 int net_proto_tcp6_write_data_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old);
65 int net_proto_tcp6_conn_disconnected (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old);
66 int net_proto_tcp6_conn_close (proto_tcp6_conn_t *conn);
67 unsigned net_proto_tcp6_conn_del (proto_tcp6_conn_t *conn);
68 proto_tcp6_conn_t *net_proto_tcp6_conn_find (int fd);
69 int net_proto_tcp6_backlog_add (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq);
70 int net_proto_tcp6_conn_invite (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq);
72 /** TCPv6 protocol
73 * User-friendly socket functions
75 int net_proto_tcp6_socket (fd_t *fd)
77 return net_proto_tcp6_conn_add (fd);
80 extern unsigned long timer_ticks;
81 int net_proto_tcp6_connect (int fd, sockaddr_in6 *addr)
83 int ret = -1;
85 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
87 if (!conn)
88 return -1;
90 netif_t *netif;
91 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
92 ret = net_proto_tcp6_conn_estabilish (conn, netif, addr->sin6_addr, addr->sin6_port);
94 unsigned long stime = timer_ticks;
96 /* blocking mode */
97 if (!(conn->flags & O_NONBLOCK)) {
98 if (!ret)
99 return -1;
101 while (1) {
102 schedule ();
104 /* timeout for 3s */
105 if ((stime+3000) < timer_ticks)
106 return -1;
108 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHED)
109 break;
111 /* when connection cant be accepted succefully first time, try it again */
112 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHERROR) {
113 ret = net_proto_tcp6_conn_estabilish (conn, netif, addr->sin6_addr, addr->sin6_port);
114 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
117 } else
118 /* non-blocking mode */
119 return -1;
121 ret = 0;
124 return ret;
127 int net_proto_tcp6_send (int fd, char *msg, unsigned size)
129 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
131 if (!conn)
132 return -1;
134 unsigned len = size;
136 unsigned mtu_tcp = NET_PACKET_MTU - sizeof (proto_tcp_t) - sizeof (net_ipv6) - 16;
138 check:
139 if (size > mtu_tcp) {
140 int r = net_proto_tcp_send (fd, msg, mtu_tcp);
142 if (r <= 0)
143 return r;
145 msg += mtu_tcp;
146 size -= mtu_tcp;
148 goto check;
151 int ret = net_proto_tcp6_write_data (conn, msg, size);
153 if (ret) {
154 unsigned long stime = timer_ticks;
156 /* blocking mode */
157 if (!(conn->flags & O_NONBLOCK)) {
158 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
159 schedule ();
161 /* timeout for 350ms */
162 if ((stime+350) < timer_ticks)
163 return -1;
165 } else {
166 /* non-blocking mode */
167 /* TODO: ? */
168 //#ifdef TEST
169 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
170 schedule ();
172 /* timeout for 100ms */
173 if ((stime+100) < timer_ticks)
174 return -1;
176 //#endif
180 return len;
183 int net_proto_tcp6_recv (int fd, char *msg, unsigned size)
185 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
187 if (!conn)
188 return -3;
190 int ret = 0;
192 //kprintf ("recv () - %d\n", fd);
194 /* blocking mode */
195 if (!(conn->flags & O_NONBLOCK)) {
196 unsigned long stime = timer_ticks;
198 while (!conn->len/* || conn->state != PROTO_TCP_CONN_STATE_READY*/) {
199 if ((stime+10000) < timer_ticks)
200 return -1;
202 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
203 if (net_proto_tcp6_conn_del (conn));
204 return -1;
207 schedule ();
209 } else {
210 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
211 if (net_proto_tcp6_conn_del (conn));
212 return -1;
215 if (!conn->len)
216 return 0;
219 if ((conn->len-conn->offset) > size) {
220 memcpy (msg, conn->data+conn->offset, size);
221 //printf ("msg: %d %d\n", conn->offset, size);
222 conn->offset += size;
224 ret = size;
225 } else {
226 ret = conn->len-conn->offset;
228 memcpy (msg, conn->data+conn->offset, conn->len-conn->offset);
229 //printf ("msg2: %d %d\n", conn->offset, size);
230 conn->len = 0;
231 conn->offset = 0;
233 kfree (conn->data);
236 //kprintf ("recv () - %d -- DATA: %d\n", fd, ret);
238 return ret;
241 int net_proto_tcp6_close (int fd)
243 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
245 if (!conn)
246 return -1;
248 if (conn->state == PROTO_TCP_CONN_STATE_DISCONNECTED)
249 return 0;
251 int ret = net_proto_tcp6_conn_close (conn);
253 return ret;
256 int net_proto_tcp6_fcntl (int fd, int cmd, long arg)
258 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
260 if (!conn)
261 return -1;
263 switch (cmd) {
264 case F_GETFL:
265 return conn->flags;
266 case F_SETFL:
267 conn->flags = arg;
268 return 0;
271 return -1;
274 int net_proto_tcp6_bind (int fd, sockaddr_in6 *addr, socklen_t len)
276 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
278 if (!conn)
279 return -1;
281 netif_t *netif;
282 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
283 net_proto_tcp6_conn_set (conn, netif, addr->sin6_port, 0, 0);
284 conn->bind = 1;
285 return 0;
288 return -1;
291 int net_proto_tcp6_listen (int fd, int backlog)
293 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
295 if (!conn)
296 return -1;
298 return 0;
301 int net_proto_tcp6_accept (int fd, sockaddr_in6 *addr, socklen_t *addrlen)
303 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
305 if (!conn)
306 return -1;
308 unsigned i = 0;
310 proto_tcp6_backlog_t *backlog = 0;
312 /* blocking mode */
313 if (!(conn->flags & O_NONBLOCK)) {
314 while (!i) {
315 for (backlog = proto_tcp6_backlog_list.next; backlog != &proto_tcp6_backlog_list; backlog = backlog->next) {
316 if (backlog->conn == conn) {
317 i = 1;
318 break;
322 schedule ();
324 } else {
325 /* non-blocking mode */
326 for (backlog = proto_tcp6_backlog_list.next; backlog != &proto_tcp6_backlog_list; backlog = backlog->next) {
327 if (backlog->conn == conn) {
328 i = 1;
329 break;
334 //printf ("accept ()\n");
336 if (!i)
337 return -1;
339 net_ipv6 ip;
340 memcpy (ip, backlog->ip, sizeof (net_ipv6));
342 net_port port = backlog->port;
343 unsigned seq = backlog->seq;
345 int ret = net_proto_tcp6_conn_invite (conn, ip, port, seq);
347 /* remove from queue accepted connection */
348 backlog->next->prev = backlog->prev;
349 backlog->prev->next = backlog->next;
351 kfree (backlog);
353 if (ret < 1)
354 return ret;
356 fd_t *fd_new = fd_create (FD_SOCK);
358 if (!fd_new)
359 return 0;
361 net_proto_tcp6_conn_add (fd_new);
363 proto_tcp6_conn_t *conn_new = net_proto_tcp6_conn_find (fd_new->id);
365 if (!conn_new)
366 return -1;
368 net_proto_tcp6_conn_set (conn_new, conn->netif, conn->port_source, conn->netif->ipv6, port);
370 memcpy (conn_new->ip_dest, ip, sizeof (net_ipv6));
372 memcpy (addr->sin6_addr, ip, sizeof (net_ipv6));
373 addr->sin6_port = port;
374 addr->sin6_family = AF_INET6;
376 return fd_new->id;
379 int net_proto_tcp6_select (int readfd, int writefd, int exceptfd)
381 int fd = -1;
383 if (readfd)
384 fd = readfd;
385 else if (writefd)
386 fd = writefd;
387 else if (exceptfd)
388 fd = exceptfd;
390 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
392 if (!conn)
393 return -1;
395 /* check for incoming connections */
396 if (conn->bind) {
397 proto_tcp6_backlog_t *backlog = 0;
399 for (backlog = proto_tcp6_backlog_list.next; backlog != &proto_tcp6_backlog_list; backlog = backlog->next) {
400 if (backlog->conn == conn)
401 return 1;
404 return 0;
407 /* Is socket closed ? */
408 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
409 return 1;
411 /* Are some data available ? */
412 if (conn->len)
413 return 1;
415 return 0;
418 /** TCP protocol
419 * Hardcore code - syn, ack, psh, fin, etc :P
421 unsigned net_proto_tcp6_handler (packet_t *packet, proto_ipv6_t *ip, char *buf, unsigned len, unsigned flags)
423 proto_tcp_t *tcp = (proto_tcp_t *) buf;
425 unsigned char ret = 0;
427 /* First check ip address and ports, that we want this data */
428 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_check (ip->ip_dest, tcp->port_dest, ip->ip_source, tcp->port_source, &ret);
430 //printf ("hmm: %d - %d - %d\n", len, swap16 (tcp->port_dest), ret);
432 if (!conn && ret == 0)
433 return 1;
435 //printf ("tcp6->flags: 0x%x, ret: %d, conn: 0x%x, fd: %d\n", tcp->flags, ret, conn, conn->fd);
437 /* connection from client before accept () */
438 if (ret == 1) {
439 /* client want connect to our server */
440 if (tcp->flags == 0x02) {
441 mutex_lock (&mutex_tcp6_accept);
443 unsigned ret = net_proto_tcp6_backlog_add (conn, ip->ip_source, tcp->port_source, tcp->seq);
445 mutex_unlock (&mutex_tcp6_accept);
447 return ret;
450 return 1;
453 unsigned data_cache = 0;
455 /* data received */
456 if (tcp->flags & 0x08) {
457 /* needed for calculate real offset from 4bit number */
458 unsigned offset = tcp->data_offset * 4;
459 unsigned size = len - offset;
461 //kprintf (">>>> %d : %d : %d\n", offset, size, len);
462 //mutex_lock (&mutex_tcp6_read_cache);
463 net_proto_tcp6_read_cache (conn, buf+offset, size);
464 //mutex_unlock (&mutex_tcp6_read_cache);
465 /* send ack */
466 net_proto_tcp6_read_ok (conn, ip, tcp, size);
468 data_cache = 1;
471 /* sended data was delivered succefully */
472 if (tcp->flags & 0x10) {
473 /* HACK: It is interesting, that no push flag, and there could be some data to read */
475 /* needed for calculate real offset from 4bit number */
476 unsigned offset = tcp->data_offset * 4;
477 unsigned size = len - offset;
479 /* there are data for read */
480 if (size) {
481 /* data was cached, so no need cache it again */
482 if (!data_cache) {
483 //kprintf (">>>>2 %d : %d : %d\n", offset, size, len);
484 mutex_lock (&mutex_tcp6_read_cache);
485 net_proto_tcp6_read_cache (conn, buf+offset, size);
486 mutex_unlock (&mutex_tcp6_read_cache);
487 /* send ack */
488 net_proto_tcp6_read_ok (conn, ip, tcp, size);
490 } else {
491 /* when data are'nt available, lets normal work - acknowledgement */
492 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISH) {
493 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHERROR;
494 net_proto_tcp6_write_data_ok (conn, ip, tcp);
495 } else
496 net_proto_tcp6_write_data_ok (conn, ip, tcp);
500 /* connection estabilish respond */
501 if (tcp->flags == 0x12) {
502 return net_proto_tcp6_conn_estabilish_reply (conn, ip, tcp);
505 /* another side close connection */
506 if (tcp->flags & 0x01) {
507 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection closed by remote host\n", conn->fd);
508 net_proto_tcp6_conn_disconnected (conn, ip, tcp); // FIXME: problem in server with hangind the whole program
511 /* another side close connection */
512 if (tcp->flags & 0x04) {
513 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection reseted by peer\n", conn->fd);
514 net_proto_tcp6_conn_disconnected (conn, ip, tcp);
517 return 1;
520 int net_proto_tcp6_read_cache (proto_tcp6_conn_t *conn, char *data, unsigned len)
522 if (!data || !conn || !len)
523 return 0;
525 if (!conn->len) {
526 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
528 memcpy (conn->data, data, len);
529 } else {
530 char *newdata = (char *) kmalloc (sizeof (char) * (conn->len + len + 1));
532 if (!newdata)
533 return 0;
535 memcpy (newdata, conn->data, conn->len);
536 memcpy (newdata+conn->len, data, len);
538 kfree (conn->data);
540 conn->data = newdata;
543 if (!conn->data)
544 return -1;
546 //kprintf ("DATA: %d - #'%s'#\n", len, data);
548 conn->len += len;
550 conn->data[conn->len] = '\0';
552 return conn->len;
555 int net_proto_tcp6_read_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old, unsigned len)
557 if (!ip_old || !tcp_old || !conn)
558 return 0;
560 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
562 if (!tcp)
563 return 0;
565 tcp->port_source = conn->port_source; // increase client port too
566 tcp->port_dest = conn->port_dest;
568 tcp->seq = tcp_old->ack;
570 /* this small thing did bad work when e.g. 10 10 10 fe get to calculation,
571 it returns 10 10 10 08, no 10 10 11 08 */
572 unsigned seq = swap32 (tcp_old->seq);
573 seq += len;
575 tcp->ack = swap32 (seq);
577 tcp->res = 0;
578 tcp->data_offset = 5;
579 tcp->flags = 0x10;
580 tcp->window = tcp_old->window + swap16 (64);
581 tcp->checksum = 0;
583 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
585 /*if (proto_tcp6_dup == tcp_old->checksum) {
586 printf ("Duplicated packet :)");
587 timer_wait (150);
590 if (ret) {
591 //printf ("read_ok: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
593 conn->seq = tcp->ack;
594 conn->ack = tcp->seq;
596 //printf ("read_ok2: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
598 proto_tcp6_dup = tcp_old->checksum;
600 conn->cross = 1;
603 kfree (tcp);
605 return ret;
608 int net_proto_tcp6_write (netif_t *eth, net_ipv6 dest, proto_tcp_t *tcp, char *data, unsigned len)
610 if (!eth || !tcp) {
611 printf ("!eth || !tcp\n");
612 return 0;
614 if (len)
615 if (!data) {
616 printf ("!data\n");
617 return 0;
619 mac_addr_t mac_dest;
621 if (!tun6_addr_get ()) {
622 unsigned get = ndp_cache_get (dest, &mac_dest);
624 if (!get) {
625 ndp_send_nbrequest (eth, dest);
627 unsigned i = 0;
628 /* 200ms for waiting on NDP reply */
629 while (i < 200) {
630 get = ndp_cache_get (dest, &mac_dest);
632 if (get)
633 break;
635 /* TODO: make better waiting for NDP reply */
636 timer_wait (1);
638 schedule ();
640 i ++;
643 if (!get) {
644 printf ("!get\n");
645 return 0;
648 } else {
649 /* IPv6 tunnel stuff */
650 net_ipv4 tunnel = tun6_addr_get ();
651 unsigned get = arp_cache_get (tunnel, &mac_dest);
653 if (!get) {
654 arp_send_request (eth, tunnel);
656 unsigned i = 0;
657 /* 100ms for waiting on ARP reply */
658 while (i < 100) {
659 get = arp_cache_get (tunnel, &mac_dest);
661 if (get)
662 break;
664 /* TODO: make better waiting for ARP reply */
665 timer_wait (1);
667 schedule ();
669 i ++;
672 if (!get) {
673 printf ("!get2\n");
674 return 0;
679 /* packet header */
680 packet_t *packet = &packet_prealloc;
682 if (!packet) {
683 printf ("!packet\n");
684 return 0;
687 memcpy (&packet->mac_source, eth->dev->dev_addr, 6);
688 memcpy (&packet->mac_dest, mac_dest, 6);
689 packet->type = NET_PACKET_TYPE_IPV6;
691 unsigned l = (tcp->data_offset*4);
693 /* ip layer */
694 proto_ipv6_t *ip = &proto_ipv6_prealloc;
696 if (!ip) {
697 printf ("!ip\n");
698 return 0;
701 /* there are some fixed values - yeah it is horrible */
702 ip->ver = 0x60;
703 ip->tclass = 0x0;
704 ip->flabel = 0x0;
705 ip->pl_len = swap16 (l+len);
706 ip->nhead = NET_PROTO_IP_TYPE_TCP6;
707 ip->hop = 0xff;
708 memcpy (ip->ip_source, (void *) eth->ipv6, sizeof (net_ipv6));
709 memcpy (ip->ip_dest, (void *) dest, sizeof (net_ipv6));
711 if (len+l > NET_PACKET_MTU + sizeof (proto_tcp_t)) {
712 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> data lenght is exceed: %d/%d bytes", len+l, NET_PACKET_MTU + sizeof (proto_tcp_t) + 1);
713 return 0;
716 char *buf_tcp = (char *) &buf_tcp_prealloc;
718 if (!buf_tcp) {
719 printf ("!buf_tcp\n");
720 return 0;
723 memcpy (buf_tcp, (char *) tcp, l);
725 if (len)
726 memcpy (buf_tcp+l, data, len);
728 buf_tcp[l+len] = '\0';
730 /* calculate checksum and put it to tcp header */
731 proto_tcp_t *tcp_ = (proto_tcp_t *) buf_tcp;
733 unsigned ret = 0;
735 tcp_->checksum = checksum16_ipv6 (eth->ipv6, dest, buf_tcp, l+len, NET_PROTO_IP_TYPE_TCP6);
737 /* send tcp header+data to ip layer */
738 if (!tun6_addr_get ())
739 ret = net_proto_ipv6_send (eth, packet, ip, (char *) buf_tcp, l+len);
740 else
741 ret = net_proto_tun6_send (eth, packet, ip, (char *) buf_tcp, l+len);
743 return ret;
746 int net_proto_tcp6_write_data (proto_tcp6_conn_t *conn, char *data, unsigned len)
748 if (!conn || !len || !data)
749 return 0;
751 proto_tcp_t *tcp = &proto_tcp_prealloc;
753 if (!tcp)
754 return 0;
756 tcp->port_source = conn->port_source;
757 tcp->port_dest = conn->port_dest;
759 unsigned seq = swap32 (proto_tcp6_seq);
760 seq ++;
762 //tcp->ack = swap32 (seq);
764 proto_tcp6_seq = swap32 (seq);
766 if (!conn->cross) {
767 tcp->seq = conn->seq;
768 tcp->ack = conn->ack;
769 } else {
770 tcp->seq = conn->ack;
771 tcp->ack = conn->seq;
773 conn->cross = 0;
776 //printf ("TCP -> seq: 0x%x | ack: 0x%x | proto_seq: 0x%x\n", tcp->seq, conn->ack, proto_tcp6_seq);
778 tcp->res = 0;
779 tcp->data_offset = 5;
780 tcp->flags = 0x18;
781 tcp->window = swap16 (32768);
782 tcp->checksum = 0;
784 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, data, len);
786 if (ret)
787 conn->state = PROTO_TCP_CONN_STATE_WAIT;
789 return ret;
792 int net_proto_tcp6_write_data_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old)
794 if (!ip_old || !tcp_old || !conn)
795 return 0;
797 /* cross - because we change now sides :) */
798 conn->seq = tcp_old->ack;
799 conn->ack = tcp_old->seq;
801 //printf ("data_ok: seq: 0x%x | ack: 0x%x\n", tcp_old->ack, tcp_old->seq);
803 conn->state = PROTO_TCP_CONN_STATE_READY;
805 return 1;
808 /* try connect to server */
809 int net_proto_tcp6_conn_estabilish (proto_tcp6_conn_t *conn, netif_t *eth, net_ipv6 ip_dest, net_port port_dest)
811 if (!conn)
812 return 0;
814 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
816 if (!tcp)
817 return 0;
819 tcp->port_source = swap16 (netif_port_get ()); // increase client port too
820 tcp->port_dest = port_dest;
822 /* setup new connection */
823 net_proto_tcp6_conn_set (conn, eth, tcp->port_source, ip_dest, tcp->port_dest);
825 tcp->seq = conn->seq;
826 tcp->ack = conn->ack;
828 tcp->res = 0;
829 tcp->data_offset = 5;
830 tcp->flags = 0x02;
831 tcp->window = swap16 (32792);
832 tcp->checksum = 0;
834 int ret = net_proto_tcp6_write (eth, ip_dest, tcp, 0, 0);
836 kfree (tcp);
838 if (!ret) {
839 net_proto_tcp6_conn_del (conn);
840 return 0;
843 return 1;
846 int net_proto_tcp6_conn_estabilish_reply (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old)
848 if (!ip_old || !tcp_old || !conn)
849 return 0;
851 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
853 if (!tcp)
854 return 0;
856 tcp->port_source = conn->port_source; // increase client port too
857 tcp->port_dest = conn->port_dest;
859 tcp->seq = tcp_old->ack;
860 tcp->ack = tcp_old->seq + swap32 (1);
862 tcp->res = 0;
863 tcp->data_offset = 5;
864 tcp->flags = 0x10;
865 tcp->window = tcp_old->window + swap16 (64);
866 tcp->checksum = 0;
868 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
870 if (ret) {
871 conn->seq = tcp->seq;
872 conn->ack = tcp->ack;
873 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHED;
876 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connected to server succefully\n", conn->fd);
878 kfree (tcp);
880 return ret;
883 int net_proto_tcp6_conn_disconnected (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old)
885 if (!ip_old || !tcp_old || !conn)
886 return 0;
888 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
889 return net_proto_tcp6_conn_del (conn);
891 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
893 if (!tcp)
894 return 0;
896 tcp->port_source = conn->port_source; // increase client port too
897 tcp->port_dest = conn->port_dest;
899 tcp->seq = tcp_old->ack;
900 tcp->ack = tcp_old->seq + swap32 (1);
902 tcp->res = 0;
903 tcp->data_offset = 5;
904 tcp->flags = 0x10;
905 tcp->window = tcp_old->window + swap16 (64);
906 tcp->checksum = 0;
908 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
910 kfree (tcp);
912 if (ret)
913 conn->state = PROTO_TCP_CONN_STATE_CLOSE; //ret = net_proto_tcp6_conn_del (conn);
914 else
915 return -1;
917 return ret;
920 int net_proto_tcp6_conn_close (proto_tcp6_conn_t *conn)
922 return 0; /* FIXME: close () is faster then send () sometime :-B */
924 if (!conn)
925 return 0;
927 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
928 return 0;
930 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
932 if (!tcp)
933 return 0;
935 tcp->port_source = conn->port_source; // increase client port too
936 tcp->port_dest = conn->port_dest;
938 tcp->seq = conn->seq;
939 tcp->ack = conn->ack;
941 tcp->res = 0;
942 tcp->data_offset = 5;
943 tcp->flags = 0x11;
944 tcp->window = swap16 (32832);
945 tcp->checksum = 0;
947 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
949 kfree (tcp);
951 if (ret) {
952 conn->state = PROTO_TCP_CONN_STATE_CLOSE;
955 return ret;
958 /* client wants to connect */
959 net_proto_tcp6_conn_invite (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq)
961 if (!conn)
962 return 0;
964 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
966 if (!tcp)
967 return 0;
969 tcp->port_source = conn->port_source;
970 tcp->port_dest = port;
972 tcp->seq = proto_tcp6_seq ++;
973 tcp->ack = seq + swap32 (1);
975 tcp->res = 0;
976 tcp->data_offset = 5;
977 tcp->flags = 0x12;
978 tcp->window = swap16 (5816);
979 tcp->checksum = 0;
981 int ret = net_proto_tcp6_write (conn->netif, ip, tcp, 0, 0);
983 kfree (tcp);
985 if (ret > 0)
986 conn->state = PROTO_TCP_CONN_STATE_READY;
987 else {
988 printf ("wtf ?\n");
989 return -1;
992 return 1;
995 /* Create new TCP connection */
996 int net_proto_tcp6_conn_add (fd_t *fd)
998 proto_tcp6_conn_t *conn;
1000 /* alloc and init context */
1001 conn = (proto_tcp6_conn_t *) kmalloc (sizeof (proto_tcp6_conn_t));
1003 if (!conn) {
1004 errno_set (ENOMEM);
1005 return -1;
1008 memset (conn, 0, sizeof (proto_tcp6_conn_t));
1010 conn->flags = 0;
1011 conn->bind = 0;
1013 conn->fd = fd->id;
1015 conn->cross = 0;
1017 /* add into list */
1018 conn->next = &proto_tcp6_conn_list;
1019 conn->prev = proto_tcp6_conn_list.prev;
1020 conn->prev->next = conn;
1021 conn->next->prev = conn;
1023 return conn->fd;
1026 /* Setup new connection */
1027 int net_proto_tcp6_conn_set (proto_tcp6_conn_t *conn, netif_t *eth, net_port port_source, net_ipv6 ip_dest, net_port port_dest)
1029 if (!conn || !eth)
1030 return 0;
1032 memcpy (conn->ip_source, eth->ipv6, sizeof (net_ipv6));
1033 memcpy (conn->ip_dest, ip_dest, sizeof (net_ipv6));
1035 conn->port_source = port_source;
1036 conn->port_dest = port_dest;
1038 proto_tcp6_seq += swap32 (1);
1040 conn->seq = proto_tcp6_seq ++;
1041 conn->ack = 0;
1043 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
1045 conn->netif = eth;
1047 conn->offset = 0;
1048 conn->len = 0;
1049 conn->data = 0;
1051 return 1;
1054 /* Delete existing connection from list */
1055 unsigned net_proto_tcp6_conn_del (proto_tcp6_conn_t *conn)
1057 if (!conn)
1058 return 0;
1060 conn->state = PROTO_TCP_CONN_STATE_DISCONNECTED;
1062 if (conn->len)
1063 kfree (conn->data);
1065 conn->len = 0;
1067 conn->next->prev = conn->prev;
1068 conn->prev->next = conn->next;
1070 kfree (conn);
1072 return 1;
1075 proto_tcp6_conn_t *net_proto_tcp6_conn_check (net_ipv6 ip_source, net_port port_source, net_ipv6 ip_dest, net_port port_dest, unsigned char *ret)
1077 *ret = 0;
1078 proto_tcp6_conn_t *conn = NULL;
1079 proto_tcp6_conn_t *conn_ret = NULL;
1080 //printf ("-------------------------\n");
1081 for (conn = proto_tcp6_conn_list.next; conn != &proto_tcp6_conn_list; conn = conn->next) {
1082 /*printf ("-> ");
1083 net_proto_ipv6_print (conn->ip_source);
1084 printf (" / ");
1085 net_proto_ipv6_print (ip_source);
1086 printf ("\n2> ");
1087 net_proto_ipv6_print (conn->ip_dest);
1088 printf (" / ");
1089 net_proto_ipv6_print (ip_dest);
1090 printf ("\nporty: %d / %d\n", swap16 (conn->port_source), swap16 (port_source));
1091 printf ("porty2: %d / %d\n", swap16 (conn->port_dest), swap16 (port_dest));*/
1093 if (net_proto_ipv6_cmp (conn->ip_source, ip_source) && conn->port_source == port_source) {
1094 if (net_proto_ipv6_cmp (conn->ip_dest, ip_dest) && conn->port_dest == port_dest) {
1095 *ret = 2;
1096 return conn;
1099 *ret = 1;
1101 conn_ret = conn;
1105 if (*ret == 1)
1106 if (!conn_ret->bind) {
1107 conn_ret = 0;
1109 for (conn = proto_tcp6_conn_list.next; conn != &proto_tcp6_conn_list; conn = conn->next) {
1110 if (conn->bind) {
1111 if (net_proto_ipv6_cmp (conn->ip_source, ip_source) && conn->port_source == port_source)
1112 conn_ret = conn;
1117 return conn_ret;
1120 proto_tcp6_conn_t *net_proto_tcp6_conn_find (int fd)
1122 proto_tcp6_conn_t *conn = NULL;
1123 for (conn = proto_tcp6_conn_list.next; conn != &proto_tcp6_conn_list; conn = conn->next) {
1124 if (conn->fd == fd)
1125 return conn;
1128 return 0;
1131 /* Create new TCP backlog stamp */
1132 int net_proto_tcp6_backlog_add (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq)
1134 if (!conn)
1135 return 0;
1137 proto_tcp6_backlog_t *backlog;
1139 /* alloc and init context */
1140 backlog = (proto_tcp6_backlog_t *) kmalloc (sizeof (proto_tcp6_backlog_t));
1142 if (!backlog)
1143 return 0;
1145 backlog->conn = conn;
1146 memcpy (backlog->ip, ip, sizeof (net_ipv6));
1147 backlog->port = port;
1148 backlog->seq = seq;
1150 /* add into list */
1151 backlog->next = &proto_tcp6_backlog_list;
1152 backlog->prev = proto_tcp6_backlog_list.prev;
1153 backlog->prev->next = backlog;
1154 backlog->next->prev = backlog;
1156 return conn->fd;
1159 /* init of tcp protocol */
1160 unsigned init_net_proto_tcp6 ()
1162 proto_tcp6_conn_list.next = &proto_tcp6_conn_list;
1163 proto_tcp6_conn_list.prev = &proto_tcp6_conn_list;
1165 proto_tcp6_backlog_list.next = &proto_tcp6_backlog_list;
1166 proto_tcp6_backlog_list.prev = &proto_tcp6_backlog_list;
1168 proto_tcp6_dup = 0x0;
1169 proto_tcp6_seq = 0x1;
1171 return 1;