Cleanup in elf.c with .bss section clean; adm command mounts cdrom instead of floppy...
[ZeXOS.git] / kernel / core / net / tcp.c
blob8327468b4cfcffe49714b220212666d63ae7e165
1 /*
2 * ZeX/OS
3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
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/tcp.h>
30 #include <net/socket.h>
31 #include <mutex.h>
32 #include <errno.h>
33 #include <fd.h>
35 /* Mutex for socket function */
36 MUTEX_CREATE (mutex_tcp_accept);
37 MUTEX_CREATE (mutex_tcp_read_cache);
39 proto_tcp_conn_t proto_tcp_conn_list;
40 proto_tcp_backlog_t proto_tcp_backlog_list;
42 extern netif_t netif_list;
44 static unsigned short proto_tcp_dup;
45 static unsigned proto_tcp_seq;
46 static proto_ip_t proto_ip_prealloc;
47 static proto_tcp_t proto_tcp_prealloc;
48 static packet_t packet_prealloc;
50 /* prototype */
51 proto_tcp_conn_t *net_proto_tcp_conn_check (net_ipv4 ip_source, net_port port_source, net_ipv4 ip_dest, net_port port_dest, unsigned char *ret);
52 int net_proto_tcp_conn_add (fd_t *fd);
53 int net_proto_tcp_conn_set (proto_tcp_conn_t *conn, netif_t *eth, net_port port_source, net_ipv4 ip_dest, net_port port_dest);
54 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest);
55 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
56 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len);
57 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len);
58 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len);
59 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len);
60 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
61 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
62 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn);
63 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn);
64 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd);
65 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
66 int net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
68 /** TCP protocol
69 * User-friendly socket functions
71 int net_proto_tcp_socket (fd_t *fd)
73 return net_proto_tcp_conn_add (fd);
76 extern unsigned long timer_ticks;
77 int net_proto_tcp_connect (int fd, sockaddr_in *addr)
79 int ret = -1;
81 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
83 if (!conn)
84 return -1;
86 netif_t *netif;
87 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
88 ret = net_proto_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_port);
90 unsigned long stime = timer_ticks;
92 /* blocking mode */
93 if (!(conn->flags & O_NONBLOCK)) {
94 if (!ret)
95 return -1;
97 for (;;) {
98 schedule ();
100 /* timeout for 8s */
101 if ((stime+8000) < timer_ticks)
102 return -1;
104 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHED)
105 break;
107 /* when connection cant be accepted succefully first time, try it again */
108 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHERROR) {
109 ret = net_proto_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_port);
110 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
113 } else
114 /* non-blocking mode */
115 return -1;
117 ret = 0;
120 return ret;
123 int net_proto_tcp_send (int fd, char *msg, unsigned size)
125 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
127 if (!conn)
128 return -1;
130 int ret = net_proto_tcp_write_data (conn, msg, size);
132 if (ret) {
133 unsigned long stime = timer_ticks;
135 /* blocking mode */
136 if (!(conn->flags & O_NONBLOCK)) {
137 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
138 /* timeout 350ms */
139 if ((stime+350) < timer_ticks)
140 return -1;
142 schedule ();
144 } else {
146 /* non-blocking mode */
147 /* TODO: ? */
148 #ifdef TEST
149 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
150 /* timeout 100ms */
151 if ((stime+100) < timer_ticks)
152 return size;
154 printf ("");
156 #endif
160 return size;
163 int net_proto_tcp_recv (int fd, char *msg, unsigned size)
165 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
167 if (!conn)
168 return -3;
170 int ret = 0;
172 //kprintf ("recv () - %d\n", fd);
174 /* blocking mode */
175 if (!(conn->flags & O_NONBLOCK)) {
176 unsigned long stime = timer_ticks;
178 while (!conn->len/* || conn->state != PROTO_TCP_CONN_STATE_READY*/) {
179 if ((stime+10000) < timer_ticks)
180 return -1;
182 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
183 if (net_proto_tcp_conn_del (conn));
184 return -1;
187 schedule ();
189 } else {
190 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
191 if (net_proto_tcp_conn_del (conn));
192 return -1;
195 if (!conn->len)
196 return 0;
199 if ((conn->len-conn->offset) > size) {
200 memcpy (msg, conn->data+conn->offset, size);
201 //printf ("msg11: %d %d\n", conn->offset, size);
202 conn->offset += size;
204 ret = size;
205 } else {
206 ret = conn->len-conn->offset;
208 memcpy (msg, conn->data+conn->offset, conn->len-conn->offset);
209 //printf ("msg22: %d %d %d\n", conn->offset, size, conn->len);
210 conn->len = 0;
211 conn->offset = 0;
213 kfree (conn->data);
216 //kprintf ("recv () - %d -- DATA: %d : %d\n", fd, ret, size);
218 return ret;
221 int net_proto_tcp_close (int fd)
223 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
225 if (!conn)
226 return -1;
228 if (conn->state == PROTO_TCP_CONN_STATE_DISCONNECTED)
229 return 0;
231 return net_proto_tcp_conn_close (conn);
234 int net_proto_tcp_fcntl (int fd, int cmd, long arg)
236 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
238 if (!conn)
239 return -1;
241 switch (cmd) {
242 case F_GETFL:
243 return conn->flags;
244 case F_SETFL:
245 conn->flags = arg;
246 return 0;
249 return -1;
252 int net_proto_tcp_bind (int fd, sockaddr_in *addr, socklen_t len)
254 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
256 if (!conn)
257 return -1;
259 netif_t *netif;
260 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
261 net_proto_tcp_conn_set (conn, netif, addr->sin_port, 0, 0);
262 conn->bind = 1;
263 return 0;
266 return -1;
269 int net_proto_tcp_listen (int fd, int backlog)
271 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
273 if (!conn)
274 return -1;
276 return 0;
279 int net_proto_tcp_accept (int fd, sockaddr_in *addr, socklen_t *addrlen)
281 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
283 if (!conn)
284 return -1;
286 unsigned i = 0;
288 proto_tcp_backlog_t *backlog = 0;
290 /* blocking mode */
291 if (!(conn->flags & O_NONBLOCK)) {
292 while (!i) {
293 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
294 if (backlog->conn == conn) {
295 i = 1;
296 break;
300 schedule ();
302 } else {
303 /* non-blocking mode */
304 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
305 if (backlog->conn == conn) {
306 i = 1;
307 break;
312 //printf ("accept ()\n");
314 if (!i)
315 return -1;
317 net_ipv4 ip = backlog->ip;
318 net_port port = backlog->port;
319 unsigned seq = backlog->seq;
321 int ret = net_proto_tcp_conn_invite (conn, ip, port, seq);
323 /* remove from queue accepted connection */
324 backlog->next->prev = backlog->prev;
325 backlog->prev->next = backlog->next;
327 kfree (backlog);
329 if (ret < 1)
330 return ret;
332 fd_t *fd_new = fd_create (FD_SOCK);
334 if (!fd_new)
335 return 0;
337 net_proto_tcp_conn_add (fd_new);
339 proto_tcp_conn_t *conn_new = net_proto_tcp_conn_find (fd_new->id);
341 if (!conn_new)
342 return -1;
344 net_proto_tcp_conn_set (conn_new, conn->netif, conn->port_source, conn->netif->ip, port);
346 conn_new->ip_dest = ip;
348 addr->sin_addr = ip;
349 addr->sin_port = port;
350 addr->sin_family = AF_INET;
352 return fd_new->id;
355 /** TCP protocol
356 * Hardcore code - syn, ack, psh, fin, etc :P
358 unsigned net_proto_tcp_handler (packet_t *packet, proto_ip_t *ip, char *buf, unsigned len)
360 proto_tcp_t *tcp = (proto_tcp_t *) buf;
362 unsigned char ret = 0;
364 /* First check ip address and ports, that we want this data */
365 proto_tcp_conn_t *conn = net_proto_tcp_conn_check (ip->ip_dest, tcp->port_dest, ip->ip_source, tcp->port_source, &ret);
367 if (!conn && ret == 0)
368 return 1;
370 //printf ("tcp->flags: 0x%x, ret: %d, conn: 0x%x, fd: %d\n", tcp->flags, ret, conn, conn->fd);
372 /* connection from client before accept () */
373 if (ret == 1) {
374 /* client want connect to our server */
375 if (tcp->flags == 0x02) {
376 mutex_lock (&mutex_tcp_accept);
378 unsigned ret = net_proto_tcp_backlog_add (conn, ip->ip_source, tcp->port_source, tcp->seq);
380 mutex_unlock (&mutex_tcp_accept);
382 return ret;
385 return 1;
388 unsigned data_cache = 0;
390 /* data received */
391 if (tcp->flags & 0x08) {
392 /* needed for calculate real offset from 4bit number */
393 unsigned offset = tcp->data_offset * 4;
395 /* now calculate accurate length of tcp _data_ */
396 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
397 //kprintf (">>>> %d : %d : %d\n", offset, size, len);
398 //mutex_lock (&mutex_tcp_read_cache);
399 net_proto_tcp_read_cache (conn, buf+offset, size);
400 //mutex_unlock (&mutex_tcp_read_cache);
401 /* send ack */
402 net_proto_tcp_read_ok (conn, ip, tcp, size);
404 data_cache = 1;
407 /* sended data was delivered succefully */
408 if (tcp->flags & 0x10) {
409 /* HACK: It is interesting, that no push flag, and there could be some data to read */
411 /* needed for calculate real offset from 4bit number */
412 unsigned offset = tcp->data_offset * 4;
414 /* now calculate accurate length of tcp _data_ */
415 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
417 /* there are data for read */
418 if (size) {
419 /* data was cached, so no need cache it again */
420 if (!data_cache) {
421 //kprintf (">>>>2 %d : %d : %d\n", offset, size, len);
422 mutex_lock (&mutex_tcp_read_cache);
423 net_proto_tcp_read_cache (conn, buf+offset, size);
424 mutex_unlock (&mutex_tcp_read_cache);
425 /* send ack */
426 net_proto_tcp_read_ok (conn, ip, tcp, size);
428 } else {
429 /* when data are'nt available, lets normal work - acknowledgement */
430 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISH) {
431 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHERROR;
432 net_proto_tcp_write_data_ok (conn, ip, tcp);
433 } else
434 net_proto_tcp_write_data_ok (conn, ip, tcp);
438 /* connection estabilish respond */
439 if (tcp->flags == 0x12) {
440 return net_proto_tcp_conn_estabilish_reply (conn, ip, tcp);
443 /* another side close connection */
444 if (tcp->flags & 0x01) {
445 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection closed by remote host", conn->fd);
446 net_proto_tcp_conn_disconnected (conn, ip, tcp); // FIXME: problem in server with hangind the whole program
449 /* another side close connection */
450 if (tcp->flags & 0x04) {
451 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection reseted by peer", conn->fd);
452 net_proto_tcp_conn_disconnected (conn, ip, tcp);
455 return 1;
458 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len)
460 if (!data || !conn || !len)
461 return 0;
463 if (!conn->len) {
464 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
466 memcpy (conn->data, data, len);
467 } else {
468 char *newdata = (char *) kmalloc (sizeof (char) * (conn->len + len + 1));
470 if (!newdata)
471 return 0;
473 memcpy (newdata, conn->data, conn->len);
474 memcpy (newdata+conn->len, data, len);
476 kfree (conn->data);
478 conn->data = newdata;
481 if (!conn->data)
482 return -1;
484 //kprintf ("DATA: %d - #'%s'#\n", len, data);
486 conn->len += len;
488 conn->data[conn->len] = '\0';
490 return conn->len;
493 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len)
495 if (!ip_old || !tcp_old || !conn)
496 return 0;
498 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
500 if (!tcp)
501 return 0;
503 tcp->port_source = conn->port_source; // increase client port too
504 tcp->port_dest = conn->port_dest;
506 tcp->seq = tcp_old->ack;
508 /* this small thing did bad work when e.g. 10 10 10 fe get to calculation,
509 it returns 10 10 10 08, no 10 10 11 08 */
510 unsigned seq = swap32 (tcp_old->seq);
511 seq += len;
513 tcp->ack = swap32 (seq);
515 tcp->res = 0;
516 tcp->data_offset = 5;
517 tcp->flags = 0x10;
518 tcp->window = tcp_old->window + swap16 (64);
519 tcp->checksum = 0;
521 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
523 /*if (proto_tcp_dup == tcp_old->checksum) {
524 printf ("Duplicated packet :)");
525 timer_wait (150);
528 if (ret) {
529 //printf ("read_ok: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
531 conn->seq = tcp->ack;
532 conn->ack = tcp->seq;
534 //printf ("read_ok2: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
536 proto_tcp_dup = tcp_old->checksum;
538 conn->cross = 1;
541 kfree (tcp);
543 return ret;
546 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len)
548 if (!eth || !tcp)
549 return 0;
551 if (len)
552 if (!data)
553 return 0;
555 mac_addr_t mac_dest;
556 unsigned get = arp_cache_get (dest, &mac_dest);
558 if (!get) {
559 arp_send_request (eth, dest);
561 unsigned i = 0;
562 /* 100ms for waiting on ARP reply */
563 while (i < 100) {
564 get = arp_cache_get (dest, &mac_dest);
566 if (get)
567 break;
569 /* TODO: make better waiting for ARP reply */
570 timer_wait (1);
572 schedule ();
574 i ++;
577 if (!get)
578 return 0;
581 /* packet header */
582 packet_t *packet = &packet_prealloc;
584 if (!packet)
585 return 0;
587 memcpy (&packet->mac_source, eth->dev->dev_addr, 6);
588 memcpy (&packet->mac_dest, mac_dest, 6);
589 packet->type = NET_PACKET_TYPE_IPV4;
591 /* ip layer */
592 proto_ip_t *ip = &proto_ip_prealloc;
594 if (!ip)
595 return 0;
597 /* there are some fixed values - yeah it is horrible */
598 ip->ver = 4;
599 ip->head_len = 5;
601 ip->flags = 0;
602 ip->frag = 0;
603 ip->ttl = 64;
604 ip->checksum = 0;
605 ip->proto = NET_PROTO_IP_TYPE_TCP;
606 ip->ip_source = eth->ip;
607 ip->ip_dest = dest;
609 unsigned l = (tcp->data_offset*4);
611 /* calculate total length of packet (tcp/ip) */
612 ip->total_len = swap16 (l+sizeof (proto_tcp_t)+len);
614 char *buf_tcp = (char *) kmalloc ((len+l+1) * sizeof (char));
616 if (!buf_tcp)
617 return 0;
619 memcpy (buf_tcp, (char *) tcp, l);
621 if (len)
622 memcpy (buf_tcp+l, data, len);
624 buf_tcp[l+len] = '\0';
626 /* calculate checksum and put it to tcp header */
627 proto_tcp_t *tcp_ = (proto_tcp_t *) buf_tcp;
629 tcp_->checksum = checksum16_tcp (eth->ip, dest, buf_tcp, l+len);
631 /* send tcp header+data to ip layer */
632 unsigned ret = net_proto_ip_send (eth, packet, ip, (char *) buf_tcp, l+len);
634 kfree (buf_tcp);
636 return ret;
639 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len)
641 if (!conn || !len || !data)
642 return 0;
644 proto_tcp_t *tcp = &proto_tcp_prealloc;
646 if (!tcp)
647 return 0;
649 tcp->port_source = conn->port_source;
650 tcp->port_dest = conn->port_dest;
652 unsigned seq = swap32 (proto_tcp_seq);
653 seq ++;
655 //tcp->ack = swap32 (seq);
657 proto_tcp_seq = swap32 (seq);
659 if (!conn->cross) {
660 tcp->seq = conn->seq;
661 tcp->ack = conn->ack;
662 } else {
663 tcp->seq = conn->ack;
664 tcp->ack = conn->seq;
666 conn->cross = 0;
669 // printf ("TCP -> seq: 0x%x | ack: 0x%x | proto_seq: 0x%x\n", tcp->seq, conn->ack, proto_tcp_seq);
671 tcp->res = 0;
672 tcp->data_offset = 5;
673 tcp->flags = 0x18;
674 tcp->window = swap16 (32768);
675 tcp->checksum = 0;
677 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, data, len);
679 if (ret)
680 conn->state = PROTO_TCP_CONN_STATE_WAIT;
682 return ret;
685 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
687 if (!ip_old || !tcp_old || !conn)
688 return 0;
690 /* cross - because we change now sides :) */
691 conn->seq = tcp_old->ack;
692 conn->ack = tcp_old->seq;
694 //printf ("data_ok: seq: 0x%x | ack: 0x%x\n", tcp_old->ack, tcp_old->seq);
696 conn->state = PROTO_TCP_CONN_STATE_READY;
698 return 1;
701 /* try connect to server */
702 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest)
704 if (!conn)
705 return 0;
707 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
709 if (!tcp)
710 return 0;
712 tcp->port_source = swap16 (netif_port_get ()); // increase client port too
713 tcp->port_dest = port_dest;
715 /* setup new connection */
716 net_proto_tcp_conn_set (conn, eth, tcp->port_source, ip_dest, tcp->port_dest);
718 tcp->seq = conn->seq;
719 tcp->ack = conn->ack;
721 tcp->res = 0;
722 tcp->data_offset = 5;
723 tcp->flags = 0x02;
724 tcp->window = swap16 (32792);
725 tcp->checksum = 0;
727 int ret = net_proto_tcp_write (eth, ip_dest, tcp, 0, 0);
729 kfree (tcp);
731 if (!ret) {
732 net_proto_tcp_conn_del (conn);
733 return 0;
736 return 1;
739 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
741 if (!ip_old || !tcp_old || !conn)
742 return 0;
744 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
746 if (!tcp)
747 return 0;
749 tcp->port_source = conn->port_source; // increase client port too
750 tcp->port_dest = conn->port_dest;
752 tcp->seq = tcp_old->ack;
753 tcp->ack = tcp_old->seq + swap32 (1);
755 tcp->res = 0;
756 tcp->data_offset = 5;
757 tcp->flags = 0x10;
758 tcp->window = tcp_old->window + swap16 (64);
759 tcp->checksum = 0;
761 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
763 if (ret) {
764 conn->seq = tcp->seq;
765 conn->ack = tcp->ack;
766 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHED;
769 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connected to server succefully\n", conn->fd);
771 kfree (tcp);
773 return ret;
776 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
778 if (!ip_old || !tcp_old || !conn)
779 return 0;
781 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
782 return net_proto_tcp_conn_del (conn);
784 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
786 if (!tcp)
787 return 0;
789 tcp->port_source = conn->port_source; // increase client port too
790 tcp->port_dest = conn->port_dest;
792 tcp->seq = tcp_old->ack;
793 tcp->ack = tcp_old->seq + swap32 (1);
795 tcp->res = 0;
796 tcp->data_offset = 5;
797 tcp->flags = 0x10;
798 tcp->window = tcp_old->window + swap16 (64);
799 tcp->checksum = 0;
801 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
803 kfree (tcp);
805 if (ret)
806 conn->state = PROTO_TCP_CONN_STATE_CLOSE; //ret = net_proto_tcp_conn_del (conn);
807 else
808 return -1;
810 return ret;
813 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn)
815 return 0; /* FIXME: close () is faster then send () sometime :-B */
817 if (!conn)
818 return 0;
820 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
821 return 0;
823 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
825 if (!tcp)
826 return 0;
828 tcp->port_source = conn->port_source; // increase client port too
829 tcp->port_dest = conn->port_dest;
831 tcp->seq = conn->seq;
832 tcp->ack = conn->ack;
834 tcp->res = 0;
835 tcp->data_offset = 5;
836 tcp->flags = 0x11;
837 tcp->window = swap16 (32832);
838 tcp->checksum = 0;
840 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
842 kfree (tcp);
844 if (ret)
845 conn->state = PROTO_TCP_CONN_STATE_CLOSE;
847 return ret;
850 /* client wants to connect */
851 net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
853 if (!conn)
854 return 0;
856 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
858 if (!tcp)
859 return 0;
861 tcp->port_source = conn->port_source;
862 tcp->port_dest = port;
864 tcp->seq = proto_tcp_seq ++;
865 tcp->ack = seq + swap32 (1);
867 tcp->res = 0;
868 tcp->data_offset = 5;
869 tcp->flags = 0x12;
870 tcp->window = swap16 (5816);
871 tcp->checksum = 0;
873 int ret = net_proto_tcp_write (conn->netif, ip, tcp, 0, 0);
875 kfree (tcp);
877 if (ret > 0)
878 conn->state = PROTO_TCP_CONN_STATE_READY;
879 else {
880 printf ("wtf ?\n");
881 return -1;
883 return 1;
886 /* Create new TCP connection */
887 int net_proto_tcp_conn_add (fd_t *fd)
889 proto_tcp_conn_t *conn;
891 /* alloc and init context */
892 conn = (proto_tcp_conn_t *) kmalloc (sizeof (proto_tcp_conn_t));
894 if (!conn) {
895 errno_set (ENOMEM);
896 return -1;
899 memset (conn, 0, sizeof (proto_tcp_conn_t));
901 conn->flags = 0;
902 conn->bind = 0;
904 conn->fd = fd->id;
906 conn->cross = 0;
908 /* add into list */
909 conn->next = &proto_tcp_conn_list;
910 conn->prev = proto_tcp_conn_list.prev;
911 conn->prev->next = conn;
912 conn->next->prev = conn;
914 return 0;
917 /* Setup new connection */
918 int net_proto_tcp_conn_set (proto_tcp_conn_t *conn, netif_t *eth, net_port port_source, net_ipv4 ip_dest, net_port port_dest)
920 if (!conn || !eth)
921 return 0;
923 conn->ip_source = eth->ip;
924 conn->ip_dest = ip_dest;
926 conn->port_source = port_source;
927 conn->port_dest = port_dest;
929 proto_tcp_seq += swap32 (1);
931 conn->seq = proto_tcp_seq ++;
932 conn->ack = 0;
934 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
936 conn->netif = eth;
938 conn->offset = 0;
939 conn->len = 0;
940 conn->data = 0;
942 return 1;
945 /* Delete existing connection from list */
946 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn)
948 if (!conn)
949 return 0;
951 conn->state = PROTO_TCP_CONN_STATE_DISCONNECTED;
953 if (conn->len)
954 kfree (conn->data);
956 conn->len = 0;
958 conn->next->prev = conn->prev;
959 conn->prev->next = conn->next;
961 kfree (conn);
963 return 1;
966 proto_tcp_conn_t *net_proto_tcp_conn_check (net_ipv4 ip_source, net_port port_source, net_ipv4 ip_dest, net_port port_dest, unsigned char *ret)
968 *ret = 0;
969 proto_tcp_conn_t *conn = NULL;
970 proto_tcp_conn_t *conn_ret = NULL;
971 //printf ("-------------------------\n");
972 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
973 /*printf ("-> ");
974 net_proto_ip_print (conn->ip_source);
975 printf (" / ");
976 net_proto_ip_print (ip_source);
977 printf ("\n2> ");
978 net_proto_ip_print (conn->ip_dest);
979 printf (" / ");
980 net_proto_ip_print (ip_dest);
981 printf ("\nporty: %d / %d\n", swap16 (conn->port_source), swap16 (port_source));
982 printf ("porty2: %d / %d\n", swap16 (conn->port_dest), swap16 (port_dest));*/
984 if (conn->ip_source == ip_source && conn->port_source == port_source) {
985 if (conn->ip_dest == ip_dest && conn->port_dest == port_dest) {
986 *ret = 2;
987 return conn;
990 *ret = 1;
992 conn_ret = conn;
996 if (*ret == 1)
997 if (!conn_ret->bind) {
998 conn_ret = 0;
1000 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1001 if (conn->bind) {
1002 if (conn->ip_source == ip_source && conn->port_source == port_source)
1003 conn_ret = conn;
1008 return conn_ret;
1011 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd)
1013 proto_tcp_conn_t *conn = NULL;
1014 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1015 if (conn->fd == fd)
1016 return conn;
1019 return 0;
1022 /* Create new TCP backlog stamp */
1023 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
1025 if (!conn)
1026 return 0;
1028 proto_tcp_backlog_t *backlog;
1030 /* alloc and init context */
1031 backlog = (proto_tcp_backlog_t *) kmalloc (sizeof (proto_tcp_backlog_t));
1033 if (!backlog)
1034 return 0;
1036 backlog->conn = conn;
1037 backlog->ip = ip;
1038 backlog->port = port;
1039 backlog->seq = seq;
1041 /* add into list */
1042 backlog->next = &proto_tcp_backlog_list;
1043 backlog->prev = proto_tcp_backlog_list.prev;
1044 backlog->prev->next = backlog;
1045 backlog->next->prev = backlog;
1047 return conn->fd;
1050 /* init of tcp protocol */
1051 unsigned init_net_proto_tcp ()
1053 proto_tcp_conn_list.next = &proto_tcp_conn_list;
1054 proto_tcp_conn_list.prev = &proto_tcp_conn_list;
1056 proto_tcp_backlog_list.next = &proto_tcp_backlog_list;
1057 proto_tcp_backlog_list.prev = &proto_tcp_backlog_list;
1059 proto_tcp_dup = 0x0;
1060 proto_tcp_seq = 0x1;
1062 return 1;