websrv makefile updated; added support for more web pages to websrv; ZDE improvement...
[ZeXOS.git] / kernel / core / net / tcp6.c
blob7a81bff3a5e8541df840ff10d89bbb4a6c469c9c
1 /*
2 * ZeX/OS
3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
4 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <system.h>
22 #include <string.h>
23 #include <dev.h>
24 #include <net/eth.h>
25 #include <net/net.h>
26 #include <net/if.h>
27 #include <net/packet.h>
28 #include <net/ip.h>
29 #include <net/ndp.h>
30 #include <net/tcp.h>
31 #include <net/tun.h>
32 #include <net/socket.h>
33 #include <mutex.h>
34 #include <errno.h>
35 #include <fd.h>
37 /* Mutex for socket function */
38 MUTEX_CREATE (mutex_tcp6_accept);
39 MUTEX_CREATE (mutex_tcp6_read_cache);
41 proto_tcp6_conn_t proto_tcp6_conn_list;
42 proto_tcp6_backlog_t proto_tcp6_backlog_list;
44 extern netif_t netif_list;
46 static unsigned short proto_tcp6_dup;
47 static unsigned proto_tcp6_seq;
48 static proto_ipv6_t proto_ipv6_prealloc;
49 static proto_tcp_t proto_tcp6_prealloc;
50 static packet_t packet6_prealloc;
52 /* prototype */
53 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);
54 int net_proto_tcp6_conn_add ();
55 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);
56 int net_proto_tcp6_conn_estabilish (proto_tcp6_conn_t *conn, netif_t *eth, net_ipv6 ip_dest, net_port port_dest);
57 int net_proto_tcp6_conn_estabilish_reply (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old);
58 int net_proto_tcp6_read_cache (proto_tcp6_conn_t *conn, char *data, unsigned len);
59 int net_proto_tcp6_read_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old, unsigned len);
60 int net_proto_tcp6_write (netif_t *eth, net_ipv6 dest, proto_tcp_t *tcp, char *data, unsigned len);
61 int net_proto_tcp6_write_data (proto_tcp6_conn_t *conn, char *data, unsigned len);
62 int net_proto_tcp6_write_data_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old);
63 int net_proto_tcp6_conn_disconnected (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old);
64 int net_proto_tcp6_conn_close (proto_tcp6_conn_t *conn);
65 unsigned net_proto_tcp6_conn_del (proto_tcp6_conn_t *conn);
66 proto_tcp6_conn_t *net_proto_tcp6_conn_find (int fd);
67 int net_proto_tcp6_backlog_add (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq);
68 int net_proto_tcp6_conn_invite (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq);
70 /** TCPv6 protocol
71 * User-friendly socket functions
73 int net_proto_tcp6_socket (fd_t *fd)
75 return net_proto_tcp6_conn_add (fd);
78 extern unsigned long timer_ticks;
79 int net_proto_tcp6_connect (int fd, sockaddr_in6 *addr)
81 int ret = -1;
83 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
85 if (!conn)
86 return -1;
88 netif_t *netif;
89 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
90 ret = net_proto_tcp6_conn_estabilish (conn, netif, addr->sin6_addr, addr->sin6_port);
92 unsigned long stime = timer_ticks;
94 /* blocking mode */
95 if (!(conn->flags & O_NONBLOCK)) {
96 if (!ret)
97 return -1;
99 while (1) {
100 schedule ();
102 /* timeout for 3s */
103 if ((stime+3000) < timer_ticks)
104 return -1;
106 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHED)
107 break;
109 /* when connection cant be accepted succefully first time, try it again */
110 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHERROR) {
111 ret = net_proto_tcp6_conn_estabilish (conn, netif, addr->sin6_addr, addr->sin6_port);
112 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
115 } else
116 /* non-blocking mode */
117 return -1;
119 ret = 0;
122 return ret;
125 int net_proto_tcp6_send (int fd, char *msg, unsigned size)
127 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
129 if (!conn)
130 return -1;
132 int ret = net_proto_tcp6_write_data (conn, msg, size);
134 if (ret) {
135 unsigned long stime = timer_ticks;
137 /* blocking mode */
138 if (!(conn->flags & O_NONBLOCK)) {
139 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
140 schedule ();
142 /* timeout for 8s */
143 if ((stime+8000) < timer_ticks)
144 return -1;
146 } else {
147 /* non-blocking mode */
148 /* TODO: ? */
149 #ifdef TEST
150 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
151 schedule ();
153 /* timeout for 1s */
154 if ((stime+1000) < timer_ticks)
155 return -1;
157 #endif
161 return size;
164 int net_proto_tcp6_recv (int fd, char *msg, unsigned size)
166 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
168 if (!conn)
169 return -3;
171 int ret = 0;
173 //kprintf ("recv () - %d\n", fd);
175 /* blocking mode */
176 if (!(conn->flags & O_NONBLOCK)) {
177 unsigned long stime = timer_ticks;
179 while (!conn->len/* || conn->state != PROTO_TCP_CONN_STATE_READY*/) {
180 if ((stime+10000) < timer_ticks)
181 return -1;
183 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
184 if (net_proto_tcp6_conn_del (conn));
185 return -1;
188 schedule ();
190 } else {
191 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
192 if (net_proto_tcp6_conn_del (conn));
193 return -1;
196 if (!conn->len)
197 return 0;
200 if ((conn->len-conn->offset) > size) {
201 memcpy (msg, conn->data+conn->offset, size);
202 //printf ("msg: %d %d\n", conn->offset, size);
203 conn->offset += size;
205 ret = size;
206 } else {
207 ret = conn->len-conn->offset;
209 memcpy (msg, conn->data+conn->offset, conn->len-conn->offset);
210 //printf ("msg2: %d %d\n", conn->offset, size);
211 conn->len = 0;
212 conn->offset = 0;
214 kfree (conn->data);
217 //kprintf ("recv () - %d -- DATA: %d\n", fd, ret);
219 return ret;
222 int net_proto_tcp6_close (int fd)
224 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
226 if (!conn)
227 return -1;
229 if (conn->state == PROTO_TCP_CONN_STATE_DISCONNECTED)
230 return 0;
232 int ret = net_proto_tcp6_conn_close (conn);
234 return ret;
237 int net_proto_tcp6_fcntl (int fd, int cmd, long arg)
239 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
241 if (!conn)
242 return -1;
244 switch (cmd) {
245 case F_GETFL:
246 return conn->flags;
247 case F_SETFL:
248 conn->flags = arg;
249 return 0;
252 return -1;
255 int net_proto_tcp6_bind (int fd, sockaddr_in6 *addr, socklen_t len)
257 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
259 if (!conn)
260 return -1;
262 netif_t *netif;
263 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
264 net_proto_tcp6_conn_set (conn, netif, addr->sin6_port, 0, 0);
265 conn->bind = 1;
266 return 0;
269 return -1;
272 int net_proto_tcp6_listen (int fd, int backlog)
274 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
276 if (!conn)
277 return -1;
279 return 0;
282 int net_proto_tcp6_accept (int fd, sockaddr_in6 *addr, socklen_t *addrlen)
284 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_find (fd);
286 if (!conn)
287 return -1;
289 unsigned i = 0;
291 proto_tcp6_backlog_t *backlog = 0;
293 /* blocking mode */
294 if (!(conn->flags & O_NONBLOCK)) {
295 while (!i) {
296 for (backlog = proto_tcp6_backlog_list.next; backlog != &proto_tcp6_backlog_list; backlog = backlog->next) {
297 if (backlog->conn == conn) {
298 i = 1;
299 break;
303 schedule ();
305 } else {
306 /* non-blocking mode */
307 for (backlog = proto_tcp6_backlog_list.next; backlog != &proto_tcp6_backlog_list; backlog = backlog->next) {
308 if (backlog->conn == conn) {
309 i = 1;
310 break;
315 //printf ("accept ()\n");
317 if (!i)
318 return -1;
320 net_ipv6 ip;
321 memcpy (ip, backlog->ip, sizeof (net_ipv6));
323 net_port port = backlog->port;
324 unsigned seq = backlog->seq;
326 int ret = net_proto_tcp6_conn_invite (conn, ip, port, seq);
328 /* remove from queue accepted connection */
329 backlog->next->prev = backlog->prev;
330 backlog->prev->next = backlog->next;
332 kfree (backlog);
334 if (ret < 1)
335 return ret;
337 fd_t *fd_new = fd_create (FD_SOCK);
339 if (!fd_new)
340 return 0;
342 net_proto_tcp6_conn_add (fd_new);
344 proto_tcp6_conn_t *conn_new = net_proto_tcp6_conn_find (fd_new->id);
346 if (!conn_new)
347 return -1;
349 net_proto_tcp6_conn_set (conn_new, conn->netif, conn->port_source, conn->netif->ipv6, port);
351 memcpy (conn_new->ip_dest, ip, sizeof (net_ipv6));
353 memcpy (addr->sin6_addr, ip, sizeof (net_ipv6));
354 addr->sin6_port = port;
355 addr->sin6_family = AF_INET6;
357 return fd_new->id;
360 /** TCP protocol
361 * Hardcore code - syn, ack, psh, fin, etc :P
363 unsigned net_proto_tcp6_handler (packet_t *packet, proto_ipv6_t *ip, char *buf, unsigned len, unsigned flags)
365 proto_tcp_t *tcp = (proto_tcp_t *) buf;
367 unsigned char ret = 0;
369 /* First check ip address and ports, that we want this data */
370 proto_tcp6_conn_t *conn = net_proto_tcp6_conn_check (ip->ip_dest, tcp->port_dest, ip->ip_source, tcp->port_source, &ret);
372 //printf ("hmm: %d - %d - %d\n", len, swap16 (tcp->port_dest), ret);
374 if (!conn && ret == 0)
375 return 1;
377 //printf ("tcp6->flags: 0x%x, ret: %d, conn: 0x%x, fd: %d\n", tcp->flags, ret, conn, conn->fd);
379 /* connection from client before accept () */
380 if (ret == 1) {
381 /* client want connect to our server */
382 if (tcp->flags == 0x02) {
383 mutex_lock (&mutex_tcp6_accept);
385 unsigned ret = net_proto_tcp6_backlog_add (conn, ip->ip_source, tcp->port_source, tcp->seq);
387 mutex_unlock (&mutex_tcp6_accept);
389 return ret;
392 return 1;
395 unsigned data_cache = 0;
397 /* data received */
398 if (tcp->flags & 0x08) {
399 /* needed for calculate real offset from 4bit number */
400 unsigned offset = tcp->data_offset * 4;
401 unsigned size = len - offset;
403 //kprintf (">>>> %d : %d : %d\n", offset, size, len);
404 //mutex_lock (&mutex_tcp6_read_cache);
405 net_proto_tcp6_read_cache (conn, buf+offset, size);
406 //mutex_unlock (&mutex_tcp6_read_cache);
407 /* send ack */
408 net_proto_tcp6_read_ok (conn, ip, tcp, size);
410 data_cache = 1;
413 /* sended data was delivered succefully */
414 if (tcp->flags & 0x10) {
415 /* HACK: It is interesting, that no push flag, and there could be some data to read */
417 /* needed for calculate real offset from 4bit number */
418 unsigned offset = tcp->data_offset * 4;
419 unsigned size = len - offset;
421 /* there are data for read */
422 if (size) {
423 /* data was cached, so no need cache it again */
424 if (!data_cache) {
425 //kprintf (">>>>2 %d : %d : %d\n", offset, size, len);
426 mutex_lock (&mutex_tcp6_read_cache);
427 net_proto_tcp6_read_cache (conn, buf+offset, size);
428 mutex_unlock (&mutex_tcp6_read_cache);
429 /* send ack */
430 net_proto_tcp6_read_ok (conn, ip, tcp, size);
432 } else {
433 /* when data are'nt available, lets normal work - acknowledgement */
434 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISH) {
435 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHERROR;
436 net_proto_tcp6_write_data_ok (conn, ip, tcp);
437 } else
438 net_proto_tcp6_write_data_ok (conn, ip, tcp);
442 /* connection estabilish respond */
443 if (tcp->flags == 0x12) {
444 return net_proto_tcp6_conn_estabilish_reply (conn, ip, tcp);
447 /* another side close connection */
448 if (tcp->flags & 0x01) {
449 DPRINT ("TCP -> fd %d connection closed by remote host\n", conn->fd);
450 net_proto_tcp6_conn_disconnected (conn, ip, tcp); // FIXME: problem in server with hangind the whole program
453 /* another side close connection */
454 if (tcp->flags & 0x04) {
455 DPRINT ("TCP -> fd %d connection reseted by peer\n", conn->fd);
456 net_proto_tcp6_conn_disconnected (conn, ip, tcp);
459 return 1;
462 int net_proto_tcp6_read_cache (proto_tcp6_conn_t *conn, char *data, unsigned len)
464 if (!data || !conn || !len)
465 return 0;
467 if (!conn->len) {
468 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
470 memcpy (conn->data, data, len);
471 } else {
472 char *newdata = (char *) kmalloc (sizeof (char) * (conn->len + len + 1));
474 if (!newdata)
475 return 0;
477 memcpy (newdata, conn->data, conn->len);
478 memcpy (newdata+conn->len, data, len);
480 kfree (conn->data);
482 conn->data = newdata;
485 if (!conn->data)
486 return -1;
488 //kprintf ("DATA: %d - #'%s'#\n", len, data);
490 conn->len += len;
492 conn->data[conn->len] = '\0';
494 return conn->len;
497 int net_proto_tcp6_read_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old, unsigned len)
499 if (!ip_old || !tcp_old || !conn)
500 return 0;
502 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
504 if (!tcp)
505 return 0;
507 tcp->port_source = conn->port_source; // increase client port too
508 tcp->port_dest = conn->port_dest;
510 tcp->seq = tcp_old->ack;
512 /* this small thing did bad work when e.g. 10 10 10 fe get to calculation,
513 it returns 10 10 10 08, no 10 10 11 08 */
514 unsigned seq = swap32 (tcp_old->seq);
515 seq += len;
517 tcp->ack = swap32 (seq);
519 tcp->res = 0;
520 tcp->data_offset = 5;
521 tcp->flags = 0x10;
522 tcp->window = tcp_old->window + swap16 (64);
523 tcp->checksum = 0;
525 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
527 /*if (proto_tcp6_dup == tcp_old->checksum) {
528 printf ("Duplicated packet :)");
529 timer_wait (150);
532 if (ret) {
533 //printf ("read_ok: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
535 conn->seq = tcp->ack;
536 conn->ack = tcp->seq;
538 //printf ("read_ok2: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
540 proto_tcp6_dup = tcp_old->checksum;
542 conn->cross = 1;
545 kfree (tcp);
547 return ret;
550 int net_proto_tcp6_write (netif_t *eth, net_ipv6 dest, proto_tcp_t *tcp, char *data, unsigned len)
552 if (!eth || !tcp) {
553 printf ("!eth || !tcp\n");
554 return 0;
556 if (len)
557 if (!data) {
558 printf ("!data\n");
559 return 0;
561 mac_addr_t mac_dest;
563 if (!tun6_addr_get ()) {
564 unsigned get = ndp_cache_get (dest, &mac_dest);
566 if (!get) {
567 ndp_send_nbrequest (eth, dest);
569 unsigned i = 0;
570 /* 200ms for waiting on NDP reply */
571 while (i < 200) {
572 get = ndp_cache_get (dest, &mac_dest);
574 if (get)
575 break;
577 /* TODO: make better waiting for NDP reply */
578 timer_wait (1);
580 schedule ();
582 i ++;
585 if (!get) {
586 printf ("!get\n");
587 return 0;
590 } else {
591 /* IPv6 tunnel stuff */
592 net_ipv4 tunnel = tun6_addr_get ();
593 unsigned get = arp_cache_get (tunnel, &mac_dest);
595 if (!get) {
596 arp_send_request (eth, tunnel);
598 unsigned i = 0;
599 /* 100ms for waiting on ARP reply */
600 while (i < 100) {
601 get = arp_cache_get (tunnel, &mac_dest);
603 if (get)
604 break;
606 /* TODO: make better waiting for ARP reply */
607 timer_wait (1);
609 schedule ();
611 i ++;
614 if (!get) {
615 printf ("!get2\n");
616 return 0;
621 /* packet header */
622 packet_t *packet = &packet6_prealloc;
624 if (!packet) {
625 printf ("!packet\n");
626 return 0;
629 memcpy (&packet->mac_source, eth->dev->dev_addr, 6);
630 memcpy (&packet->mac_dest, mac_dest, 6);
631 packet->type = NET_PACKET_TYPE_IPV6;
633 unsigned l = (tcp->data_offset*4);
635 /* ip layer */
636 proto_ipv6_t *ip = &proto_ipv6_prealloc;
638 if (!ip) {
639 printf ("!ip\n");
640 return 0;
643 /* there are some fixed values - yeah it is horrible */
644 ip->ver = 0x60;
645 ip->tclass = 0x0;
646 ip->flabel = 0x0;
647 ip->pl_len = swap16 (l+len);
648 ip->nhead = NET_PROTO_IP_TYPE_TCP6;
649 ip->hop = 0xff;
650 memcpy (ip->ip_source, (void *) eth->ipv6, sizeof (net_ipv6));
651 memcpy (ip->ip_dest, (void *) dest, sizeof (net_ipv6));
653 char *buf_tcp = (char *) kmalloc ((len+l+1) * sizeof (char));
655 if (!buf_tcp) {
656 printf ("!buf_tcp\n");
657 return 0;
660 memcpy (buf_tcp, (char *) tcp, l);
662 if (len)
663 memcpy (buf_tcp+l, data, len);
665 buf_tcp[l+len] = '\0';
667 /* calculate checksum and put it to tcp header */
668 proto_tcp_t *tcp_ = (proto_tcp_t *) buf_tcp;
670 unsigned ret = 0;
672 tcp_->checksum = checksum16_ipv6 (eth->ipv6, dest, buf_tcp, l+len, NET_PROTO_IP_TYPE_TCP6);
674 /* send tcp header+data to ip layer */
675 if (!tun6_addr_get ())
676 ret = net_proto_ipv6_send (eth, packet, ip, (char *) buf_tcp, l+len);
677 else
678 ret = net_proto_tun6_send (eth, packet, ip, (char *) buf_tcp, l+len);
680 kfree (buf_tcp);
682 return ret;
685 int net_proto_tcp6_write_data (proto_tcp6_conn_t *conn, char *data, unsigned len)
687 if (!conn || !len || !data)
688 return 0;
690 proto_tcp_t *tcp = &proto_tcp6_prealloc;
692 if (!tcp)
693 return 0;
695 tcp->port_source = conn->port_source;
696 tcp->port_dest = conn->port_dest;
698 unsigned seq = swap32 (proto_tcp6_seq);
699 seq ++;
701 //tcp->ack = swap32 (seq);
703 proto_tcp6_seq = swap32 (seq);
705 if (!conn->cross) {
706 tcp->seq = conn->seq;
707 tcp->ack = conn->ack;
708 } else {
709 tcp->seq = conn->ack;
710 tcp->ack = conn->seq;
712 conn->cross = 0;
715 //printf ("TCP -> seq: 0x%x | ack: 0x%x | proto_seq: 0x%x\n", tcp->seq, conn->ack, proto_tcp6_seq);
717 tcp->res = 0;
718 tcp->data_offset = 5;
719 tcp->flags = 0x18;
720 tcp->window = swap16 (32768);
721 tcp->checksum = 0;
723 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, data, len);
725 if (ret)
726 conn->state = PROTO_TCP_CONN_STATE_WAIT;
728 return ret;
731 int net_proto_tcp6_write_data_ok (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old)
733 if (!ip_old || !tcp_old || !conn)
734 return 0;
736 /* cross - because we change now sides :) */
737 conn->seq = tcp_old->ack;
738 conn->ack = tcp_old->seq;
740 //printf ("data_ok: seq: 0x%x | ack: 0x%x\n", tcp_old->ack, tcp_old->seq);
742 conn->state = PROTO_TCP_CONN_STATE_READY;
744 return 1;
747 /* try connect to server */
748 int net_proto_tcp6_conn_estabilish (proto_tcp6_conn_t *conn, netif_t *eth, net_ipv6 ip_dest, net_port port_dest)
750 if (!conn)
751 return 0;
753 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
755 if (!tcp)
756 return 0;
758 tcp->port_source = swap16 (netif_port_get ()); // increase client port too
759 tcp->port_dest = port_dest;
761 /* setup new connection */
762 net_proto_tcp6_conn_set (conn, eth, tcp->port_source, ip_dest, tcp->port_dest);
764 tcp->seq = conn->seq;
765 tcp->ack = conn->ack;
767 tcp->res = 0;
768 tcp->data_offset = 5;
769 tcp->flags = 0x02;
770 tcp->window = swap16 (32792);
771 tcp->checksum = 0;
773 int ret = net_proto_tcp6_write (eth, ip_dest, tcp, 0, 0);
775 kfree (tcp);
777 if (!ret) {
778 net_proto_tcp6_conn_del (conn);
779 return 0;
782 return 1;
785 int net_proto_tcp6_conn_estabilish_reply (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old)
787 if (!ip_old || !tcp_old || !conn)
788 return 0;
790 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
792 if (!tcp)
793 return 0;
795 tcp->port_source = conn->port_source; // increase client port too
796 tcp->port_dest = conn->port_dest;
798 tcp->seq = tcp_old->ack;
799 tcp->ack = tcp_old->seq + swap32 (1);
801 tcp->res = 0;
802 tcp->data_offset = 5;
803 tcp->flags = 0x10;
804 tcp->window = tcp_old->window + swap16 (64);
805 tcp->checksum = 0;
807 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
809 if (ret) {
810 conn->seq = tcp->seq;
811 conn->ack = tcp->ack;
812 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHED;
815 DPRINT ("TCP -> fd %� connected to server succefully\n", conn->fd);
817 kfree (tcp);
819 return ret;
822 int net_proto_tcp6_conn_disconnected (proto_tcp6_conn_t *conn, proto_ipv6_t *ip_old, proto_tcp_t *tcp_old)
824 if (!ip_old || !tcp_old || !conn)
825 return 0;
827 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
828 return net_proto_tcp6_conn_del (conn);
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 kfree (tcp);
851 if (ret)
852 conn->state = PROTO_TCP_CONN_STATE_CLOSE; //ret = net_proto_tcp6_conn_del (conn);
853 else
854 return -1;
856 return ret;
859 int net_proto_tcp6_conn_close (proto_tcp6_conn_t *conn)
861 return 0; /* FIXME: close () is faster then send () sometime :-B */
863 if (!conn)
864 return 0;
866 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
867 return 0;
869 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
871 if (!tcp)
872 return 0;
874 tcp->port_source = conn->port_source; // increase client port too
875 tcp->port_dest = conn->port_dest;
877 tcp->seq = conn->seq;
878 tcp->ack = conn->ack;
880 tcp->res = 0;
881 tcp->data_offset = 5;
882 tcp->flags = 0x11;
883 tcp->window = swap16 (32832);
884 tcp->checksum = 0;
886 int ret = net_proto_tcp6_write (conn->netif, conn->ip_dest, tcp, 0, 0);
888 kfree (tcp);
890 if (ret) {
891 conn->state = PROTO_TCP_CONN_STATE_CLOSE;
894 return ret;
897 /* client wants to connect */
898 net_proto_tcp6_conn_invite (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq)
900 if (!conn)
901 return 0;
903 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
905 if (!tcp)
906 return 0;
908 tcp->port_source = conn->port_source;
909 tcp->port_dest = port;
911 tcp->seq = proto_tcp6_seq ++;
912 tcp->ack = seq + swap32 (1);
914 tcp->res = 0;
915 tcp->data_offset = 5;
916 tcp->flags = 0x12;
917 tcp->window = swap16 (5816);
918 tcp->checksum = 0;
920 int ret = net_proto_tcp6_write (conn->netif, ip, tcp, 0, 0);
922 kfree (tcp);
924 if (ret > 0)
925 conn->state = PROTO_TCP_CONN_STATE_READY;
926 else {
927 printf ("wtf ?\n");
928 return -1;
931 return 1;
934 /* Create new TCP connection */
935 int net_proto_tcp6_conn_add (fd_t *fd)
937 proto_tcp6_conn_t *conn;
939 /* alloc and init context */
940 conn = (proto_tcp6_conn_t *) kmalloc (sizeof (proto_tcp6_conn_t));
942 if (!conn) {
943 errno_set (ENOMEM);
944 return -1;
947 memset (conn, 0, sizeof (proto_tcp6_conn_t));
949 conn->flags = 0;
950 conn->bind = 0;
952 conn->fd = fd->id;
954 conn->cross = 0;
956 /* add into list */
957 conn->next = &proto_tcp6_conn_list;
958 conn->prev = proto_tcp6_conn_list.prev;
959 conn->prev->next = conn;
960 conn->next->prev = conn;
962 return conn->fd;
965 /* Setup new connection */
966 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)
968 if (!conn || !eth)
969 return 0;
971 memcpy (conn->ip_source, eth->ipv6, sizeof (net_ipv6));
972 memcpy (conn->ip_dest, ip_dest, sizeof (net_ipv6));
974 conn->port_source = port_source;
975 conn->port_dest = port_dest;
977 proto_tcp6_seq += swap32 (1);
979 conn->seq = proto_tcp6_seq ++;
980 conn->ack = 0;
982 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
984 conn->netif = eth;
986 conn->offset = 0;
987 conn->len = 0;
988 conn->data = 0;
990 return 1;
993 /* Delete existing connection from list */
994 unsigned net_proto_tcp6_conn_del (proto_tcp6_conn_t *conn)
996 if (!conn)
997 return 0;
999 conn->state = PROTO_TCP_CONN_STATE_DISCONNECTED;
1001 if (conn->len)
1002 kfree (conn->data);
1004 conn->len = 0;
1006 conn->next->prev = conn->prev;
1007 conn->prev->next = conn->next;
1009 kfree (conn);
1011 return 1;
1014 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)
1016 *ret = 0;
1017 proto_tcp6_conn_t *conn = NULL;
1018 proto_tcp6_conn_t *conn_ret = NULL;
1019 //printf ("-------------------------\n");
1020 for (conn = proto_tcp6_conn_list.next; conn != &proto_tcp6_conn_list; conn = conn->next) {
1021 /*printf ("-> ");
1022 net_proto_ipv6_print (conn->ip_source);
1023 printf (" / ");
1024 net_proto_ipv6_print (ip_source);
1025 printf ("\n2> ");
1026 net_proto_ipv6_print (conn->ip_dest);
1027 printf (" / ");
1028 net_proto_ipv6_print (ip_dest);
1029 printf ("\nporty: %d / %d\n", swap16 (conn->port_source), swap16 (port_source));
1030 printf ("porty2: %d / %d\n", swap16 (conn->port_dest), swap16 (port_dest));*/
1032 if (net_proto_ipv6_cmp (conn->ip_source, ip_source) && conn->port_source == port_source) {
1033 if (net_proto_ipv6_cmp (conn->ip_dest, ip_dest) && conn->port_dest == port_dest) {
1034 *ret = 2;
1035 return conn;
1038 *ret = 1;
1040 conn_ret = conn;
1044 if (*ret == 1)
1045 if (!conn_ret->bind) {
1046 conn_ret = 0;
1048 for (conn = proto_tcp6_conn_list.next; conn != &proto_tcp6_conn_list; conn = conn->next) {
1049 if (conn->bind) {
1050 if (net_proto_ipv6_cmp (conn->ip_source, ip_source) && conn->port_source == port_source)
1051 conn_ret = conn;
1056 return conn_ret;
1059 proto_tcp6_conn_t *net_proto_tcp6_conn_find (int fd)
1061 proto_tcp6_conn_t *conn = NULL;
1062 for (conn = proto_tcp6_conn_list.next; conn != &proto_tcp6_conn_list; conn = conn->next) {
1063 if (conn->fd == fd)
1064 return conn;
1067 return 0;
1070 /* Create new TCP backlog stamp */
1071 int net_proto_tcp6_backlog_add (proto_tcp6_conn_t *conn, net_ipv6 ip, net_port port, unsigned seq)
1073 if (!conn)
1074 return 0;
1076 proto_tcp6_backlog_t *backlog;
1078 /* alloc and init context */
1079 backlog = (proto_tcp6_backlog_t *) kmalloc (sizeof (proto_tcp6_backlog_t));
1081 if (!backlog)
1082 return 0;
1084 backlog->conn = conn;
1085 memcpy (backlog->ip, ip, sizeof (net_ipv6));
1086 backlog->port = port;
1087 backlog->seq = seq;
1089 /* add into list */
1090 backlog->next = &proto_tcp6_backlog_list;
1091 backlog->prev = proto_tcp6_backlog_list.prev;
1092 backlog->prev->next = backlog;
1093 backlog->next->prev = backlog;
1095 return conn->fd;
1098 /* init of tcp protocol */
1099 unsigned init_net_proto_tcp6 ()
1101 proto_tcp6_conn_list.next = &proto_tcp6_conn_list;
1102 proto_tcp6_conn_list.prev = &proto_tcp6_conn_list;
1104 proto_tcp6_backlog_list.next = &proto_tcp6_backlog_list;
1105 proto_tcp6_backlog_list.prev = &proto_tcp6_backlog_list;
1107 proto_tcp6_dup = 0x0;
1108 proto_tcp6_seq = 0x1;
1110 return 1;