New developer version 0.6.8; added select () function; added demonstrating example...
[ZeXOS.git] / kernel / core / net / tcp6.c
blob481a7067080466a2032902c3893ea053c1074e3f
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_tcp6_prealloc;
51 static packet_t packet6_prealloc;
53 /* prototype */
54 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);
55 int net_proto_tcp6_conn_add ();
56 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);
57 int net_proto_tcp6_conn_estabilish (proto_tcp6_conn_t *conn, netif_t *eth, net_ipv6 ip_dest, net_port port_dest);
58 int net_proto_tcp6_conn_estabilish_reply (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old);
59 int net_proto_tcp6_read_cache (proto_tcp6_conn_t *conn, char *data, unsigned len);
60 int net_proto_tcp6_read_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old, unsigned len);
61 int net_proto_tcp6_write (netif_t *eth, net_ipv6 dest, proto_tcp_t *tcp, char *data, unsigned len);
62 int net_proto_tcp6_write_data (proto_tcp6_conn_t *conn, char *data, unsigned len);
63 int net_proto_tcp6_write_data_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old);
64 int net_proto_tcp6_conn_disconnected (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old);
65 int net_proto_tcp6_conn_close (proto_tcp6_conn_t *conn);
66 unsigned net_proto_tcp6_conn_del (proto_tcp6_conn_t *conn);
67 proto_tcp6_conn_t *net_proto_tcp6_conn_find (int fd);
68 int net_proto_tcp6_backlog_add (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq);
69 int net_proto_tcp6_conn_invite (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq);
71 /** TCPv6 protocol
72 * User-friendly socket functions
74 int net_proto_tcp6_socket (fd_t *fd)
76 return net_proto_tcp6_conn_add (fd);
79 extern unsigned long timer_ticks;
80 int net_proto_tcp6_connect (int fd, sockaddr_in6 *addr)
82 int ret = -1;
84 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
86 if (!conn)
87 return -1;
89 netif_t *netif;
90 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
91 ret = net_proto_tcp6_conn_estabilish (conn, netif, addr->sin6_addr, addr->sin6_port);
93 unsigned long stime = timer_ticks;
95 /* blocking mode */
96 if (!(conn->flags & O_NONBLOCK)) {
97 if (!ret)
98 return -1;
100 while (1) {
101 schedule ();
103 /* timeout for 3s */
104 if ((stime+3000) < timer_ticks)
105 return -1;
107 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHED)
108 break;
110 /* when connection cant be accepted succefully first time, try it again */
111 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHERROR) {
112 ret = net_proto_tcp6_conn_estabilish (conn, netif, addr->sin6_addr, addr->sin6_port);
113 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
116 } else
117 /* non-blocking mode */
118 return -1;
120 ret = 0;
123 return ret;
126 int net_proto_tcp6_send (int fd, char *msg, unsigned size)
128 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
130 if (!conn)
131 return -1;
133 int ret = net_proto_tcp6_write_data (conn, msg, size);
135 if (ret) {
136 unsigned long stime = timer_ticks;
138 /* blocking mode */
139 if (!(conn->flags & O_NONBLOCK)) {
140 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
141 schedule ();
143 /* timeout for 8s */
144 if ((stime+8000) < timer_ticks)
145 return -1;
147 } else {
148 /* non-blocking mode */
149 /* TODO: ? */
150 #ifdef TEST
151 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
152 schedule ();
154 /* timeout for 1s */
155 if ((stime+1000) < timer_ticks)
156 return -1;
158 #endif
162 return size;
165 int net_proto_tcp6_recv (int fd, char *msg, unsigned size)
167 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
169 if (!conn)
170 return -3;
172 int ret = 0;
174 //kprintf ("recv () - %d\n", fd);
176 /* blocking mode */
177 if (!(conn->flags & O_NONBLOCK)) {
178 unsigned long stime = timer_ticks;
180 while (!conn->len/* || conn->state != PROTO_TCP_CONN_STATE_READY*/) {
181 if ((stime+10000) < timer_ticks)
182 return -1;
184 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
185 if (net_proto_tcp6_conn_del (conn));
186 return -1;
189 schedule ();
191 } else {
192 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
193 if (net_proto_tcp6_conn_del (conn));
194 return -1;
197 if (!conn->len)
198 return 0;
201 if ((conn->len-conn->offset) > size) {
202 memcpy (msg, conn->data+conn->offset, size);
203 //printf ("msg: %d %d\n", conn->offset, size);
204 conn->offset += size;
206 ret = size;
207 } else {
208 ret = conn->len-conn->offset;
210 memcpy (msg, conn->data+conn->offset, conn->len-conn->offset);
211 //printf ("msg2: %d %d\n", conn->offset, size);
212 conn->len = 0;
213 conn->offset = 0;
215 kfree (conn->data);
218 //kprintf ("recv () - %d -- DATA: %d\n", fd, ret);
220 return ret;
223 int net_proto_tcp6_close (int fd)
225 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
227 if (!conn)
228 return -1;
230 if (conn->state == PROTO_TCP_CONN_STATE_DISCONNECTED)
231 return 0;
233 int ret = net_proto_tcp6_conn_close (conn);
235 return ret;
238 int net_proto_tcp6_fcntl (int fd, int cmd, long arg)
240 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
242 if (!conn)
243 return -1;
245 switch (cmd) {
246 case F_GETFL:
247 return conn->flags;
248 case F_SETFL:
249 conn->flags = arg;
250 return 0;
253 return -1;
256 int net_proto_tcp6_bind (int fd, sockaddr_in6 *addr, socklen_t len)
258 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
260 if (!conn)
261 return -1;
263 netif_t *netif;
264 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
265 net_proto_tcp6_conn_set (conn, netif, addr->sin6_port, 0, 0);
266 conn->bind = 1;
267 return 0;
270 return -1;
273 int net_proto_tcp6_listen (int fd, int backlog)
275 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
277 if (!conn)
278 return -1;
280 return 0;
283 int net_proto_tcp6_accept (int fd, sockaddr_in6 *addr, socklen_t *addrlen)
285 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
287 if (!conn)
288 return -1;
290 unsigned i = 0;
292 proto_tcp6_backlog_t *backlog = 0;
294 /* blocking mode */
295 if (!(conn->flags & O_NONBLOCK)) {
296 while (!i) {
297 for (backlog = proto_tcp6_backlog_list.next; backlog != &proto_tcp6_backlog_list; backlog = backlog->next) {
298 if (backlog->conn == conn) {
299 i = 1;
300 break;
304 schedule ();
306 } else {
307 /* non-blocking mode */
308 for (backlog = proto_tcp6_backlog_list.next; backlog != &proto_tcp6_backlog_list; backlog = backlog->next) {
309 if (backlog->conn == conn) {
310 i = 1;
311 break;
316 //printf ("accept ()\n");
318 if (!i)
319 return -1;
321 net_ipv6 ip;
322 memcpy (ip, backlog->ip, sizeof (net_ipv6));
324 net_port port = backlog->port;
325 unsigned seq = backlog->seq;
327 int ret = net_proto_tcp6_conn_invite (conn, ip, port, seq);
329 /* remove from queue accepted connection */
330 backlog->next->prev = backlog->prev;
331 backlog->prev->next = backlog->next;
333 kfree (backlog);
335 if (ret < 1)
336 return ret;
338 fd_t *fd_new = fd_create (FD_SOCK);
340 if (!fd_new)
341 return 0;
343 net_proto_tcp6_conn_add (fd_new);
345 proto_tcp6_conn_t *conn_new = net_proto_tcp6_conn_find (fd_new->id);
347 if (!conn_new)
348 return -1;
350 net_proto_tcp6_conn_set (conn_new, conn->netif, conn->port_source, conn->netif->ipv6, port);
352 memcpy (conn_new->ip_dest, ip, sizeof (net_ipv6));
354 memcpy (addr->sin6_addr, ip, sizeof (net_ipv6));
355 addr->sin6_port = port;
356 addr->sin6_family = AF_INET6;
358 return fd_new->id;
361 int net_proto_tcp6_select (int readfd, int writefd, int exceptfd)
363 int fd = -1;
365 if (readfd)
366 fd = readfd;
367 else if (writefd)
368 fd = writefd;
369 else if (exceptfd)
370 fd = exceptfd;
372 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
374 if (!conn)
375 return -1;
377 /* check for incoming connections */
378 if (conn->bind) {
379 proto_tcp6_backlog_t *backlog = 0;
381 for (backlog = proto_tcp6_backlog_list.next; backlog != &proto_tcp6_backlog_list; backlog = backlog->next) {
382 if (backlog->conn == conn)
383 return 1;
386 return 0;
389 /* Is socket closed ? */
390 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
391 return 1;
393 /* Are some data available ? */
394 if (conn->len)
395 return 1;
397 return 0;
400 /** TCP protocol
401 * Hardcore code - syn, ack, psh, fin, etc :P
403 unsigned net_proto_tcp6_handler (packet_t *packet, proto_ipv6_t *ip, char *buf, unsigned len, unsigned flags)
405 proto_tcp_t *tcp = (proto_tcp_t *) buf;
407 unsigned char ret = 0;
409 /* First check ip address and ports, that we want this data */
410 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_check (ip->ip_dest, tcp->port_dest, ip->ip_source, tcp->port_source, &ret);
412 //printf ("hmm: %d - %d - %d\n", len, swap16 (tcp->port_dest), ret);
414 if (!conn && ret == 0)
415 return 1;
417 //printf ("tcp6->flags: 0x%x, ret: %d, conn: 0x%x, fd: %d\n", tcp->flags, ret, conn, conn->fd);
419 /* connection from client before accept () */
420 if (ret == 1) {
421 /* client want connect to our server */
422 if (tcp->flags == 0x02) {
423 mutex_lock (&mutex_tcp6_accept);
425 unsigned ret = net_proto_tcp6_backlog_add (conn, ip->ip_source, tcp->port_source, tcp->seq);
427 mutex_unlock (&mutex_tcp6_accept);
429 return ret;
432 return 1;
435 unsigned data_cache = 0;
437 /* data received */
438 if (tcp->flags & 0x08) {
439 /* needed for calculate real offset from 4bit number */
440 unsigned offset = tcp->data_offset * 4;
441 unsigned size = len - offset;
443 //kprintf (">>>> %d : %d : %d\n", offset, size, len);
444 //mutex_lock (&mutex_tcp6_read_cache);
445 net_proto_tcp6_read_cache (conn, buf+offset, size);
446 //mutex_unlock (&mutex_tcp6_read_cache);
447 /* send ack */
448 net_proto_tcp6_read_ok (conn, ip, tcp, size);
450 data_cache = 1;
453 /* sended data was delivered succefully */
454 if (tcp->flags & 0x10) {
455 /* HACK: It is interesting, that no push flag, and there could be some data to read */
457 /* needed for calculate real offset from 4bit number */
458 unsigned offset = tcp->data_offset * 4;
459 unsigned size = len - offset;
461 /* there are data for read */
462 if (size) {
463 /* data was cached, so no need cache it again */
464 if (!data_cache) {
465 //kprintf (">>>>2 %d : %d : %d\n", offset, size, len);
466 mutex_lock (&mutex_tcp6_read_cache);
467 net_proto_tcp6_read_cache (conn, buf+offset, size);
468 mutex_unlock (&mutex_tcp6_read_cache);
469 /* send ack */
470 net_proto_tcp6_read_ok (conn, ip, tcp, size);
472 } else {
473 /* when data are'nt available, lets normal work - acknowledgement */
474 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISH) {
475 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHERROR;
476 net_proto_tcp6_write_data_ok (conn, ip, tcp);
477 } else
478 net_proto_tcp6_write_data_ok (conn, ip, tcp);
482 /* connection estabilish respond */
483 if (tcp->flags == 0x12) {
484 return net_proto_tcp6_conn_estabilish_reply (conn, ip, tcp);
487 /* another side close connection */
488 if (tcp->flags & 0x01) {
489 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection closed by remote host\n", conn->fd);
490 net_proto_tcp6_conn_disconnected (conn, ip, tcp); // FIXME: problem in server with hangind the whole program
493 /* another side close connection */
494 if (tcp->flags & 0x04) {
495 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection reseted by peer\n", conn->fd);
496 net_proto_tcp6_conn_disconnected (conn, ip, tcp);
499 return 1;
502 int net_proto_tcp6_read_cache (proto_tcp6_conn_t *conn, char *data, unsigned len)
504 if (!data || !conn || !len)
505 return 0;
507 if (!conn->len) {
508 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
510 memcpy (conn->data, data, len);
511 } else {
512 char *newdata = (char *) kmalloc (sizeof (char) * (conn->len + len + 1));
514 if (!newdata)
515 return 0;
517 memcpy (newdata, conn->data, conn->len);
518 memcpy (newdata+conn->len, data, len);
520 kfree (conn->data);
522 conn->data = newdata;
525 if (!conn->data)
526 return -1;
528 //kprintf ("DATA: %d - #'%s'#\n", len, data);
530 conn->len += len;
532 conn->data[conn->len] = '\0';
534 return conn->len;
537 int net_proto_tcp6_read_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old, unsigned len)
539 if (!ip_old || !tcp_old || !conn)
540 return 0;
542 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
544 if (!tcp)
545 return 0;
547 tcp->port_source = conn->port_source; // increase client port too
548 tcp->port_dest = conn->port_dest;
550 tcp->seq = tcp_old->ack;
552 /* this small thing did bad work when e.g. 10 10 10 fe get to calculation,
553 it returns 10 10 10 08, no 10 10 11 08 */
554 unsigned seq = swap32 (tcp_old->seq);
555 seq += len;
557 tcp->ack = swap32 (seq);
559 tcp->res = 0;
560 tcp->data_offset = 5;
561 tcp->flags = 0x10;
562 tcp->window = tcp_old->window + swap16 (64);
563 tcp->checksum = 0;
565 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
567 /*if (proto_tcp6_dup == tcp_old->checksum) {
568 printf ("Duplicated packet :)");
569 timer_wait (150);
572 if (ret) {
573 //printf ("read_ok: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
575 conn->seq = tcp->ack;
576 conn->ack = tcp->seq;
578 //printf ("read_ok2: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
580 proto_tcp6_dup = tcp_old->checksum;
582 conn->cross = 1;
585 kfree (tcp);
587 return ret;
590 int net_proto_tcp6_write (netif_t *eth, net_ipv6 dest, proto_tcp_t *tcp, char *data, unsigned len)
592 if (!eth || !tcp) {
593 printf ("!eth || !tcp\n");
594 return 0;
596 if (len)
597 if (!data) {
598 printf ("!data\n");
599 return 0;
601 mac_addr_t mac_dest;
603 if (!tun6_addr_get ()) {
604 unsigned get = ndp_cache_get (dest, &mac_dest);
606 if (!get) {
607 ndp_send_nbrequest (eth, dest);
609 unsigned i = 0;
610 /* 200ms for waiting on NDP reply */
611 while (i < 200) {
612 get = ndp_cache_get (dest, &mac_dest);
614 if (get)
615 break;
617 /* TODO: make better waiting for NDP reply */
618 timer_wait (1);
620 schedule ();
622 i ++;
625 if (!get) {
626 printf ("!get\n");
627 return 0;
630 } else {
631 /* IPv6 tunnel stuff */
632 net_ipv4 tunnel = tun6_addr_get ();
633 unsigned get = arp_cache_get (tunnel, &mac_dest);
635 if (!get) {
636 arp_send_request (eth, tunnel);
638 unsigned i = 0;
639 /* 100ms for waiting on ARP reply */
640 while (i < 100) {
641 get = arp_cache_get (tunnel, &mac_dest);
643 if (get)
644 break;
646 /* TODO: make better waiting for ARP reply */
647 timer_wait (1);
649 schedule ();
651 i ++;
654 if (!get) {
655 printf ("!get2\n");
656 return 0;
661 /* packet header */
662 packet_t *packet = &packet6_prealloc;
664 if (!packet) {
665 printf ("!packet\n");
666 return 0;
669 memcpy (&packet->mac_source, eth->dev->dev_addr, 6);
670 memcpy (&packet->mac_dest, mac_dest, 6);
671 packet->type = NET_PACKET_TYPE_IPV6;
673 unsigned l = (tcp->data_offset*4);
675 /* ip layer */
676 proto_ipv6_t *ip = &proto_ipv6_prealloc;
678 if (!ip) {
679 printf ("!ip\n");
680 return 0;
683 /* there are some fixed values - yeah it is horrible */
684 ip->ver = 0x60;
685 ip->tclass = 0x0;
686 ip->flabel = 0x0;
687 ip->pl_len = swap16 (l+len);
688 ip->nhead = NET_PROTO_IP_TYPE_TCP6;
689 ip->hop = 0xff;
690 memcpy (ip->ip_source, (void *) eth->ipv6, sizeof (net_ipv6));
691 memcpy (ip->ip_dest, (void *) dest, sizeof (net_ipv6));
693 char *buf_tcp = (char *) kmalloc ((len+l+1) * sizeof (char));
695 if (!buf_tcp) {
696 printf ("!buf_tcp\n");
697 return 0;
700 memcpy (buf_tcp, (char *) tcp, l);
702 if (len)
703 memcpy (buf_tcp+l, data, len);
705 buf_tcp[l+len] = '\0';
707 /* calculate checksum and put it to tcp header */
708 proto_tcp_t *tcp_ = (proto_tcp_t *) buf_tcp;
710 unsigned ret = 0;
712 tcp_->checksum = checksum16_ipv6 (eth->ipv6, dest, buf_tcp, l+len, NET_PROTO_IP_TYPE_TCP6);
714 /* send tcp header+data to ip layer */
715 if (!tun6_addr_get ())
716 ret = net_proto_ipv6_send (eth, packet, ip, (char *) buf_tcp, l+len);
717 else
718 ret = net_proto_tun6_send (eth, packet, ip, (char *) buf_tcp, l+len);
720 kfree (buf_tcp);
722 return ret;
725 int net_proto_tcp6_write_data (proto_tcp6_conn_t *conn, char *data, unsigned len)
727 if (!conn || !len || !data)
728 return 0;
730 proto_tcp_t *tcp = &proto_tcp6_prealloc;
732 if (!tcp)
733 return 0;
735 tcp->port_source = conn->port_source;
736 tcp->port_dest = conn->port_dest;
738 unsigned seq = swap32 (proto_tcp6_seq);
739 seq ++;
741 //tcp->ack = swap32 (seq);
743 proto_tcp6_seq = swap32 (seq);
745 if (!conn->cross) {
746 tcp->seq = conn->seq;
747 tcp->ack = conn->ack;
748 } else {
749 tcp->seq = conn->ack;
750 tcp->ack = conn->seq;
752 conn->cross = 0;
755 //printf ("TCP -> seq: 0x%x | ack: 0x%x | proto_seq: 0x%x\n", tcp->seq, conn->ack, proto_tcp6_seq);
757 tcp->res = 0;
758 tcp->data_offset = 5;
759 tcp->flags = 0x18;
760 tcp->window = swap16 (32768);
761 tcp->checksum = 0;
763 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, data, len);
765 if (ret)
766 conn->state = PROTO_TCP_CONN_STATE_WAIT;
768 return ret;
771 int net_proto_tcp6_write_data_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old)
773 if (!ip_old || !tcp_old || !conn)
774 return 0;
776 /* cross - because we change now sides :) */
777 conn->seq = tcp_old->ack;
778 conn->ack = tcp_old->seq;
780 //printf ("data_ok: seq: 0x%x | ack: 0x%x\n", tcp_old->ack, tcp_old->seq);
782 conn->state = PROTO_TCP_CONN_STATE_READY;
784 return 1;
787 /* try connect to server */
788 int net_proto_tcp6_conn_estabilish (proto_tcp6_conn_t *conn, netif_t *eth, net_ipv6 ip_dest, net_port port_dest)
790 if (!conn)
791 return 0;
793 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
795 if (!tcp)
796 return 0;
798 tcp->port_source = swap16 (netif_port_get ()); // increase client port too
799 tcp->port_dest = port_dest;
801 /* setup new connection */
802 net_proto_tcp6_conn_set (conn, eth, tcp->port_source, ip_dest, tcp->port_dest);
804 tcp->seq = conn->seq;
805 tcp->ack = conn->ack;
807 tcp->res = 0;
808 tcp->data_offset = 5;
809 tcp->flags = 0x02;
810 tcp->window = swap16 (32792);
811 tcp->checksum = 0;
813 int ret = net_proto_tcp6_write (eth, ip_dest, tcp, 0, 0);
815 kfree (tcp);
817 if (!ret) {
818 net_proto_tcp6_conn_del (conn);
819 return 0;
822 return 1;
825 int net_proto_tcp6_conn_estabilish_reply (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old)
827 if (!ip_old || !tcp_old || !conn)
828 return 0;
830 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
832 if (!tcp)
833 return 0;
835 tcp->port_source = conn->port_source; // increase client port too
836 tcp->port_dest = conn->port_dest;
838 tcp->seq = tcp_old->ack;
839 tcp->ack = tcp_old->seq + swap32 (1);
841 tcp->res = 0;
842 tcp->data_offset = 5;
843 tcp->flags = 0x10;
844 tcp->window = tcp_old->window + swap16 (64);
845 tcp->checksum = 0;
847 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
849 if (ret) {
850 conn->seq = tcp->seq;
851 conn->ack = tcp->ack;
852 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHED;
855 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connected to server succefully\n", conn->fd);
857 kfree (tcp);
859 return ret;
862 int net_proto_tcp6_conn_disconnected (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old)
864 if (!ip_old || !tcp_old || !conn)
865 return 0;
867 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
868 return net_proto_tcp6_conn_del (conn);
870 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
872 if (!tcp)
873 return 0;
875 tcp->port_source = conn->port_source; // increase client port too
876 tcp->port_dest = conn->port_dest;
878 tcp->seq = tcp_old->ack;
879 tcp->ack = tcp_old->seq + swap32 (1);
881 tcp->res = 0;
882 tcp->data_offset = 5;
883 tcp->flags = 0x10;
884 tcp->window = tcp_old->window + swap16 (64);
885 tcp->checksum = 0;
887 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
889 kfree (tcp);
891 if (ret)
892 conn->state = PROTO_TCP_CONN_STATE_CLOSE; //ret = net_proto_tcp6_conn_del (conn);
893 else
894 return -1;
896 return ret;
899 int net_proto_tcp6_conn_close (proto_tcp6_conn_t *conn)
901 return 0; /* FIXME: close () is faster then send () sometime :-B */
903 if (!conn)
904 return 0;
906 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
907 return 0;
909 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
911 if (!tcp)
912 return 0;
914 tcp->port_source = conn->port_source; // increase client port too
915 tcp->port_dest = conn->port_dest;
917 tcp->seq = conn->seq;
918 tcp->ack = conn->ack;
920 tcp->res = 0;
921 tcp->data_offset = 5;
922 tcp->flags = 0x11;
923 tcp->window = swap16 (32832);
924 tcp->checksum = 0;
926 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
928 kfree (tcp);
930 if (ret) {
931 conn->state = PROTO_TCP_CONN_STATE_CLOSE;
934 return ret;
937 /* client wants to connect */
938 net_proto_tcp6_conn_invite (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq)
940 if (!conn)
941 return 0;
943 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
945 if (!tcp)
946 return 0;
948 tcp->port_source = conn->port_source;
949 tcp->port_dest = port;
951 tcp->seq = proto_tcp6_seq ++;
952 tcp->ack = seq + swap32 (1);
954 tcp->res = 0;
955 tcp->data_offset = 5;
956 tcp->flags = 0x12;
957 tcp->window = swap16 (5816);
958 tcp->checksum = 0;
960 int ret = net_proto_tcp6_write (conn->netif, ip, tcp, 0, 0);
962 kfree (tcp);
964 if (ret > 0)
965 conn->state = PROTO_TCP_CONN_STATE_READY;
966 else {
967 printf ("wtf ?\n");
968 return -1;
971 return 1;
974 /* Create new TCP connection */
975 int net_proto_tcp6_conn_add (fd_t *fd)
977 proto_tcp6_conn_t *conn;
979 /* alloc and init context */
980 conn = (proto_tcp6_conn_t *) kmalloc (sizeof (proto_tcp6_conn_t));
982 if (!conn) {
983 errno_set (ENOMEM);
984 return -1;
987 memset (conn, 0, sizeof (proto_tcp6_conn_t));
989 conn->flags = 0;
990 conn->bind = 0;
992 conn->fd = fd->id;
994 conn->cross = 0;
996 /* add into list */
997 conn->next = &proto_tcp6_conn_list;
998 conn->prev = proto_tcp6_conn_list.prev;
999 conn->prev->next = conn;
1000 conn->next->prev = conn;
1002 return conn->fd;
1005 /* Setup new connection */
1006 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)
1008 if (!conn || !eth)
1009 return 0;
1011 memcpy (conn->ip_source, eth->ipv6, sizeof (net_ipv6));
1012 memcpy (conn->ip_dest, ip_dest, sizeof (net_ipv6));
1014 conn->port_source = port_source;
1015 conn->port_dest = port_dest;
1017 proto_tcp6_seq += swap32 (1);
1019 conn->seq = proto_tcp6_seq ++;
1020 conn->ack = 0;
1022 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
1024 conn->netif = eth;
1026 conn->offset = 0;
1027 conn->len = 0;
1028 conn->data = 0;
1030 return 1;
1033 /* Delete existing connection from list */
1034 unsigned net_proto_tcp6_conn_del (proto_tcp6_conn_t *conn)
1036 if (!conn)
1037 return 0;
1039 conn->state = PROTO_TCP_CONN_STATE_DISCONNECTED;
1041 if (conn->len)
1042 kfree (conn->data);
1044 conn->len = 0;
1046 conn->next->prev = conn->prev;
1047 conn->prev->next = conn->next;
1049 kfree (conn);
1051 return 1;
1054 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)
1056 *ret = 0;
1057 proto_tcp6_conn_t *conn = NULL;
1058 proto_tcp6_conn_t *conn_ret = NULL;
1059 //printf ("-------------------------\n");
1060 for (conn = proto_tcp6_conn_list.next; conn != &proto_tcp6_conn_list; conn = conn->next) {
1061 /*printf ("-> ");
1062 net_proto_ipv6_print (conn->ip_source);
1063 printf (" / ");
1064 net_proto_ipv6_print (ip_source);
1065 printf ("\n2> ");
1066 net_proto_ipv6_print (conn->ip_dest);
1067 printf (" / ");
1068 net_proto_ipv6_print (ip_dest);
1069 printf ("\nporty: %d / %d\n", swap16 (conn->port_source), swap16 (port_source));
1070 printf ("porty2: %d / %d\n", swap16 (conn->port_dest), swap16 (port_dest));*/
1072 if (net_proto_ipv6_cmp (conn->ip_source, ip_source) && conn->port_source == port_source) {
1073 if (net_proto_ipv6_cmp (conn->ip_dest, ip_dest) && conn->port_dest == port_dest) {
1074 *ret = 2;
1075 return conn;
1078 *ret = 1;
1080 conn_ret = conn;
1084 if (*ret == 1)
1085 if (!conn_ret->bind) {
1086 conn_ret = 0;
1088 for (conn = proto_tcp6_conn_list.next; conn != &proto_tcp6_conn_list; conn = conn->next) {
1089 if (conn->bind) {
1090 if (net_proto_ipv6_cmp (conn->ip_source, ip_source) && conn->port_source == port_source)
1091 conn_ret = conn;
1096 return conn_ret;
1099 proto_tcp6_conn_t *net_proto_tcp6_conn_find (int fd)
1101 proto_tcp6_conn_t *conn = NULL;
1102 for (conn = proto_tcp6_conn_list.next; conn != &proto_tcp6_conn_list; conn = conn->next) {
1103 if (conn->fd == fd)
1104 return conn;
1107 return 0;
1110 /* Create new TCP backlog stamp */
1111 int net_proto_tcp6_backlog_add (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq)
1113 if (!conn)
1114 return 0;
1116 proto_tcp6_backlog_t *backlog;
1118 /* alloc and init context */
1119 backlog = (proto_tcp6_backlog_t *) kmalloc (sizeof (proto_tcp6_backlog_t));
1121 if (!backlog)
1122 return 0;
1124 backlog->conn = conn;
1125 memcpy (backlog->ip, ip, sizeof (net_ipv6));
1126 backlog->port = port;
1127 backlog->seq = seq;
1129 /* add into list */
1130 backlog->next = &proto_tcp6_backlog_list;
1131 backlog->prev = proto_tcp6_backlog_list.prev;
1132 backlog->prev->next = backlog;
1133 backlog->next->prev = backlog;
1135 return conn->fd;
1138 /* init of tcp protocol */
1139 unsigned init_net_proto_tcp6 ()
1141 proto_tcp6_conn_list.next = &proto_tcp6_conn_list;
1142 proto_tcp6_conn_list.prev = &proto_tcp6_conn_list;
1144 proto_tcp6_backlog_list.next = &proto_tcp6_backlog_list;
1145 proto_tcp6_backlog_list.prev = &proto_tcp6_backlog_list;
1147 proto_tcp6_dup = 0x0;
1148 proto_tcp6_seq = 0x1;
1150 return 1;