Fixed buffer overflow in mserver; fixed type of checkinfo () 2nd parameter; memory
[ZeXOS.git] / kernel / core / net / tcp.c
blob5b135b08562a5f6659097dd9d89d31e2a2988ae9
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/tcp.h>
31 #include <net/socket.h>
32 #include <mutex.h>
33 #include <errno.h>
34 #include <fd.h>
36 /* Mutex for socket function */
37 MUTEX_CREATE (mutex_tcp_accept);
38 MUTEX_CREATE (mutex_tcp_read_cache);
40 extern netif_t netif_list;
42 proto_tcp_conn_t proto_tcp_conn_list;
43 proto_tcp_backlog_t proto_tcp_backlog_list;
45 static unsigned short proto_tcp_dup;
46 static unsigned proto_tcp_seq;
47 static proto_ip_t proto_ip_prealloc;
48 static proto_tcp_t proto_tcp_prealloc;
49 static packet_t packet_prealloc;
50 static char buf_tcp_prealloc[NET_PACKET_MTU + sizeof (proto_tcp_t) + 1];
52 /* prototype */
53 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);
54 int net_proto_tcp_conn_add (fd_t *fd);
55 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);
56 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest);
57 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
58 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len);
59 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len);
60 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len);
61 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len);
62 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
63 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
64 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn);
65 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn);
66 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd);
67 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
68 int net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
70 /** TCP protocol
71 * User-friendly socket functions
73 int net_proto_tcp_socket (fd_t *fd)
75 return net_proto_tcp_conn_add (fd);
78 extern unsigned long timer_ticks;
79 int net_proto_tcp_connect (int fd, sockaddr_in *addr)
81 int ret = -1;
83 proto_tcp_conn_t *conn = net_proto_tcp_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_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_port);
92 unsigned long stime = timer_ticks;
94 /* blocking mode */
95 if (!(conn->flags & O_NONBLOCK)) {
96 if (!ret)
97 return -1;
99 for (;;) {
100 schedule ();
102 /* timeout for 8s */
103 if ((stime+8000) < 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_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_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_tcp_send (int fd, char *msg, unsigned size)
127 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
129 if (!conn)
130 return -1;
132 unsigned len = size;
134 unsigned mtu_tcp = NET_PACKET_MTU - sizeof (proto_tcp_t) - sizeof (net_ipv4) - 16;
136 check:
137 if (size > mtu_tcp) {
138 int r = net_proto_tcp_send (fd, msg, mtu_tcp);
140 if (r <= 0)
141 return r;
143 msg += mtu_tcp;
144 size -= mtu_tcp;
146 goto check;
149 int ret = net_proto_tcp_write_data (conn, msg, size);
151 if (ret) {
152 unsigned long stime = timer_ticks;
154 /* blocking mode */
155 if (!(conn->flags & O_NONBLOCK)) {
156 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
157 /* timeout 350ms */
158 if ((stime+350) < timer_ticks)
159 return -1;
161 schedule ();
163 } else {
165 /* non-blocking mode */
166 /* TODO: ? */
167 //#ifdef TEST
168 while (conn->state != PROTO_TCP_CONN_STATE_READY) {
169 /* timeout 100ms */
170 if ((stime+100) < timer_ticks)
171 return 0;
173 schedule ();
175 //#endif
179 return len;
182 int net_proto_tcp_recv (int fd, char *msg, unsigned size)
184 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
186 if (!conn)
187 return -3;
189 int ret = 0;
191 //kprintf ("recv () - %d\n", fd);
193 /* blocking mode */
194 if (!(conn->flags & O_NONBLOCK)) {
195 unsigned long stime = timer_ticks;
197 while (!conn->len/* || conn->state != PROTO_TCP_CONN_STATE_READY*/) {
198 if ((stime+10000) < timer_ticks)
199 return -1;
201 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
202 if (net_proto_tcp_conn_del (conn));
203 return -1;
206 schedule ();
208 } else {
209 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
210 if (net_proto_tcp_conn_del (conn));
211 return -1;
214 if (!conn->len)
215 return 0;
218 if ((conn->len-conn->offset) > size) {
219 memcpy (msg, conn->data+conn->offset, size);
220 //printf ("msg11: %d %d\n", conn->offset, size);
221 conn->offset += size;
223 ret = size;
224 } else {
225 ret = conn->len-conn->offset;
227 memcpy (msg, conn->data+conn->offset, conn->len-conn->offset);
228 //printf ("msg22: %d %d %d\n", conn->offset, size, conn->len);
229 conn->len = 0;
230 conn->offset = 0;
232 kfree (conn->data);
235 //kprintf ("recv () - %d -- DATA: %d : %d\n", fd, ret, size);
237 return ret;
240 int net_proto_tcp_close (int fd)
242 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
244 if (!conn)
245 return -1;
247 if (conn->state == PROTO_TCP_CONN_STATE_DISCONNECTED)
248 return 0;
250 return net_proto_tcp_conn_close (conn);
253 int net_proto_tcp_fcntl (int fd, int cmd, long arg)
255 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
257 if (!conn)
258 return -1;
260 switch (cmd) {
261 case F_GETFL:
262 return conn->flags;
263 case F_SETFL:
264 conn->flags = arg;
265 return 0;
268 return -1;
271 int net_proto_tcp_bind (int fd, sockaddr_in *addr, socklen_t len)
273 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
275 if (!conn)
276 return -1;
278 netif_t *netif;
279 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
280 net_proto_tcp_conn_set (conn, netif, addr->sin_port, 0, 0);
281 conn->bind = 1;
282 return 0;
285 return -1;
288 int net_proto_tcp_listen (int fd, int backlog)
290 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
292 if (!conn)
293 return -1;
295 return 0;
298 int net_proto_tcp_accept (int fd, sockaddr_in *addr, socklen_t *addrlen)
300 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
302 if (!conn)
303 return -1;
305 unsigned i = 0;
307 proto_tcp_backlog_t *backlog = 0;
309 /* blocking mode */
310 if (!(conn->flags & O_NONBLOCK)) {
311 while (!i) {
312 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
313 if (backlog->conn == conn) {
314 i = 1;
315 break;
319 schedule ();
321 } else {
322 /* non-blocking mode */
323 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
324 if (backlog->conn == conn) {
325 i = 1;
326 break;
331 //printf ("accept ()\n");
333 if (!i)
334 return -1;
336 net_ipv4 ip = backlog->ip;
337 net_port port = backlog->port;
338 unsigned seq = backlog->seq;
340 int ret = net_proto_tcp_conn_invite (conn, ip, port, seq);
342 /* remove from queue accepted connection */
343 backlog->next->prev = backlog->prev;
344 backlog->prev->next = backlog->next;
346 kfree (backlog);
348 if (ret < 1)
349 return ret;
351 fd_t *fd_new = fd_create (FD_SOCK);
353 if (!fd_new)
354 return 0;
356 net_proto_tcp_conn_add (fd_new);
358 proto_tcp_conn_t *conn_new = net_proto_tcp_conn_find (fd_new->id);
360 if (!conn_new)
361 return -1;
363 net_proto_tcp_conn_set (conn_new, conn->netif, conn->port_source, conn->netif->ip, port);
365 conn_new->ip_dest = ip;
367 addr->sin_addr = ip;
368 addr->sin_port = port;
369 addr->sin_family = AF_INET;
371 /* wait for ACK */
372 unsigned long stime = timer_ticks;
373 while (conn_new->state != PROTO_TCP_CONN_STATE_READY) {
374 if ((stime+10) < timer_ticks)
375 return -1;
377 schedule ();
380 return fd_new->id;
383 int net_proto_tcp_select (int readfd, int writefd, int exceptfd)
385 int fd = -1;
387 if (readfd)
388 fd = readfd;
389 else if (writefd)
390 fd = writefd;
391 else if (exceptfd)
392 fd = exceptfd;
394 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
396 if (!conn)
397 return -1;
399 /* check for incoming connections */
400 if (conn->bind) {
401 proto_tcp_backlog_t *backlog = 0;
403 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
404 if (backlog->conn == conn)
405 return 1;
408 return 0;
411 /* Is socket closed ? */
412 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
413 return 1;
415 /* Are some data available ? */
416 if (conn->len)
417 return 1;
419 return 0;
422 /** TCP protocol
423 * Hardcore code - syn, ack, psh, fin, etc :P
425 unsigned net_proto_tcp_handler (packet_t *packet, proto_ip_t *ip, char *buf, unsigned len)
427 proto_tcp_t *tcp = (proto_tcp_t *) buf;
429 unsigned char ret = 0;
431 /* First check ip address and ports, that we want this data */
432 proto_tcp_conn_t *conn = net_proto_tcp_conn_check (ip->ip_dest, tcp->port_dest, ip->ip_source, tcp->port_source, &ret);
434 if (!conn && ret == 0)
435 return 1;
437 //printf ("tcp->flags: 0x%x, ret: %d, conn: 0x%x, fd: %d\n", tcp->flags, ret, conn, conn->fd);
439 /* connection from client before accept () */
440 if (ret == 1) {
441 /* client want connect to our server */
442 if (tcp->flags == 0x02) {
443 mutex_lock (&mutex_tcp_accept);
445 unsigned ret = net_proto_tcp_backlog_add (conn, ip->ip_source, tcp->port_source, tcp->seq);
447 mutex_unlock (&mutex_tcp_accept);
449 return ret;
452 return 1;
455 unsigned data_cache = 0;
457 /* data received */
458 if (tcp->flags & 0x08) {
459 /* needed for calculate real offset from 4bit number */
460 unsigned offset = tcp->data_offset * 4;
462 /* now calculate accurate length of tcp _data_ */
463 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
464 //kprintf (">>>> %d : %d : %d\n", offset, size, len);
465 //mutex_lock (&mutex_tcp_read_cache);
466 net_proto_tcp_read_cache (conn, buf+offset, size);
467 //mutex_unlock (&mutex_tcp_read_cache);
468 /* send ack */
469 net_proto_tcp_read_ok (conn, ip, tcp, size);
471 data_cache = 1;
474 /* sended data was delivered succefully / ACK */
475 if (tcp->flags & 0x10) {
476 /* HACK: It is interesting, that no push flag, and there could be some data to read */
478 /* needed for calculate real offset from 4bit number */
479 unsigned offset = tcp->data_offset * 4;
481 /* now calculate accurate length of tcp _data_ */
482 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
484 /* there are data for read */
485 if (size) {
486 /* data was cached, so no need cache it again */
487 if (!data_cache) {
488 //kprintf (">>>>2 %d : %d : %d\n", offset, size, len);
489 mutex_lock (&mutex_tcp_read_cache);
490 net_proto_tcp_read_cache (conn, buf+offset, size);
491 mutex_unlock (&mutex_tcp_read_cache);
492 /* send ack */
493 net_proto_tcp_read_ok (conn, ip, tcp, size);
495 } else {
496 /* when data are'nt available, lets normal work - acknowledgement */
497 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISH) {
498 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHERROR;
499 net_proto_tcp_write_data_ok (conn, ip, tcp);
500 } else
501 net_proto_tcp_write_data_ok (conn, ip, tcp);
505 /* connection estabilish respond */
506 if (tcp->flags == 0x12) {
507 return net_proto_tcp_conn_estabilish_reply (conn, ip, tcp);
510 /* another side close connection */
511 if (tcp->flags & 0x01) {
512 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection closed by remote host", conn->fd);
513 net_proto_tcp_conn_disconnected (conn, ip, tcp); // FIXME: problem in server with hangind the whole program
516 /* another side close connection */
517 if (tcp->flags & 0x04) {
518 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connection reseted by peer", conn->fd);
519 net_proto_tcp_conn_disconnected (conn, ip, tcp);
522 return 1;
525 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len)
527 if (!data || !conn || !len)
528 return 0;
530 if (!conn->len) {
531 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
533 memcpy (conn->data, data, len);
534 } else {
535 char *newdata = (char *) kmalloc (sizeof (char) * (conn->len + len + 1));
537 if (!newdata)
538 return 0;
540 memcpy (newdata, conn->data, conn->len);
541 memcpy (newdata+conn->len, data, len);
543 kfree (conn->data);
545 conn->data = newdata;
548 if (!conn->data)
549 return -1;
551 //kprintf ("DATA: %d - #'%s'#\n", len, data);
553 conn->len += len;
555 conn->data[conn->len] = '\0';
557 return conn->len;
560 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len)
562 if (!ip_old || !tcp_old || !conn)
563 return 0;
565 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
567 if (!tcp)
568 return 0;
570 tcp->port_source = conn->port_source; // increase client port too
571 tcp->port_dest = conn->port_dest;
573 tcp->seq = tcp_old->ack;
575 /* this small thing did bad work when e.g. 10 10 10 fe get to calculation,
576 it returns 10 10 10 08, no 10 10 11 08 */
577 unsigned seq = swap32 (tcp_old->seq);
578 seq += len;
580 tcp->ack = swap32 (seq);
582 tcp->res = 0;
583 tcp->data_offset = 5;
584 tcp->flags = 0x10;
585 tcp->window = tcp_old->window + swap16 (64);
586 tcp->checksum = 0;
588 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
590 /*if (proto_tcp_dup == tcp_old->checksum) {
591 printf ("Duplicated packet :)");
592 timer_wait (150);
595 if (ret) {
596 //printf ("read_ok: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
598 conn->seq = tcp->ack;
599 conn->ack = tcp->seq;
601 //printf ("read_ok2: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
603 proto_tcp_dup = tcp_old->checksum;
605 conn->cross = 1;
608 kfree (tcp);
610 return ret;
613 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len)
615 if (!eth || !tcp)
616 return 0;
618 if (len)
619 if (!data)
620 return 0;
622 mac_addr_t mac_dest;
623 unsigned get = arp_cache_get (dest, &mac_dest);
625 if (!get) {
626 arp_send_request (eth, dest);
628 unsigned i = 0;
629 /* 100ms for waiting on ARP reply */
630 while (i < 100) {
631 get = arp_cache_get (dest, &mac_dest);
633 if (get)
634 break;
636 /* TODO: make better waiting for ARP reply */
637 timer_wait (1);
639 schedule ();
641 i ++;
644 if (!get)
645 return 0;
648 /* packet header */
649 packet_t *packet = &packet_prealloc;
651 if (!packet)
652 return 0;
654 memcpy (&packet->mac_source, eth->dev->dev_addr, 6);
655 memcpy (&packet->mac_dest, mac_dest, 6);
656 packet->type = NET_PACKET_TYPE_IPV4;
658 /* ip layer */
659 proto_ip_t *ip = &proto_ip_prealloc;
661 if (!ip)
662 return 0;
664 /* there are some fixed values - yeah it is horrible */
665 ip->ver = 4;
666 ip->head_len = 5;
668 ip->flags = 0;
669 ip->frag = 0;
670 ip->ttl = 64;
671 ip->checksum = 0;
672 ip->proto = NET_PROTO_IP_TYPE_TCP;
673 ip->ip_source = eth->ip;
674 ip->ip_dest = dest;
676 unsigned l = (tcp->data_offset*4);
678 /* calculate total length of packet (tcp/ip) */
679 ip->total_len = swap16 (l+sizeof (proto_tcp_t)+len);
681 if (len+l > NET_PACKET_MTU + sizeof (proto_tcp_t)) {
682 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);
683 return 0;
686 char *buf_tcp = (char *) &buf_tcp_prealloc; //(char *) kmalloc ((len+l+1) * sizeof (char));
688 if (!buf_tcp)
689 return 0;
691 memcpy (buf_tcp, (char *) tcp, l);
693 if (len)
694 memcpy (buf_tcp+l, data, len);
696 // buf_tcp[l+len] = '\0';
698 /* calculate checksum and put it to tcp header */
699 proto_tcp_t *tcp_ = (proto_tcp_t *) buf_tcp;
701 tcp_->checksum = checksum16_tcp (eth->ip, dest, buf_tcp, l+len);
703 /* send tcp header+data to ip layer */
704 unsigned ret = net_proto_ip_send (eth, packet, ip, (char *) buf_tcp, l+len);
706 //kfree (buf_tcp);
708 return ret;
711 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len)
713 if (!conn || !len || !data)
714 return 0;
716 proto_tcp_t *tcp = &proto_tcp_prealloc;
718 if (!tcp)
719 return 0;
721 tcp->port_source = conn->port_source;
722 tcp->port_dest = conn->port_dest;
724 unsigned seq = swap32 (proto_tcp_seq);
725 seq ++;
727 //tcp->ack = swap32 (seq);
729 proto_tcp_seq = swap32 (seq);
731 if (!conn->cross) {
732 tcp->seq = conn->seq;
733 tcp->ack = conn->ack;
734 } else {
735 tcp->seq = conn->ack;
736 tcp->ack = conn->seq;
738 conn->cross = 0;
741 // printf ("TCP -> seq: 0x%x | ack: 0x%x | proto_seq: 0x%x\n", tcp->seq, tcp->ack, proto_tcp_seq);
743 tcp->res = 0;
744 tcp->data_offset = 5;
745 tcp->flags = 0x18;
746 tcp->window = swap16 (32768);
747 tcp->checksum = 0;
749 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, data, len);
751 if (ret)
752 conn->state = PROTO_TCP_CONN_STATE_WAIT;
754 return ret;
757 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
759 if (!ip_old || !tcp_old || !conn)
760 return 0;
762 /* cross - because we change now sides :) */
763 conn->seq = tcp_old->ack;
764 conn->ack = tcp_old->seq;
766 // printf ("data_ok: seq: 0x%x | ack: 0x%x\n", tcp_old->ack, tcp_old->seq);
768 conn->state = PROTO_TCP_CONN_STATE_READY;
770 return 1;
773 /* try connect to server */
774 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest)
776 if (!conn)
777 return 0;
779 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
781 if (!tcp)
782 return 0;
784 tcp->port_source = swap16 (netif_port_get ()); // increase client port too
785 tcp->port_dest = port_dest;
787 /* setup new connection */
788 net_proto_tcp_conn_set (conn, eth, tcp->port_source, ip_dest, tcp->port_dest);
790 tcp->seq = conn->seq;
791 tcp->ack = conn->ack;
793 tcp->res = 0;
794 tcp->data_offset = 5;
795 tcp->flags = 0x02;
796 tcp->window = swap16 (32792);
797 tcp->checksum = 0;
799 int ret = net_proto_tcp_write (eth, ip_dest, tcp, 0, 0);
801 kfree (tcp);
803 if (!ret) {
804 net_proto_tcp_conn_del (conn);
805 return 0;
808 return 1;
811 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
813 if (!ip_old || !tcp_old || !conn)
814 return 0;
816 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
818 if (!tcp)
819 return 0;
821 tcp->port_source = conn->port_source; // increase client port too
822 tcp->port_dest = conn->port_dest;
824 tcp->seq = tcp_old->ack;
825 tcp->ack = tcp_old->seq + swap32 (1);
827 tcp->res = 0;
828 tcp->data_offset = 5;
829 tcp->flags = 0x10;
830 tcp->window = tcp_old->window + swap16 (64);
831 tcp->checksum = 0;
833 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
835 if (ret) {
836 conn->seq = tcp->seq;
837 conn->ack = tcp->ack;
838 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHED;
840 DPRINT (DBG_NET | DBG_SOCKET | DBG_TCP, "TCP -> fd %d connected to server succefully\n", conn->fd);
843 kfree (tcp);
845 return ret;
848 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
850 if (!ip_old || !tcp_old || !conn)
851 return 0;
853 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
854 return net_proto_tcp_conn_del (conn);
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; // increase client port too
862 tcp->port_dest = conn->port_dest;
864 tcp->seq = tcp_old->ack;
865 tcp->ack = tcp_old->seq + swap32 (1);
867 tcp->res = 0;
868 tcp->data_offset = 5;
869 tcp->flags = 0x10;
870 tcp->window = tcp_old->window + swap16 (64);
871 tcp->checksum = 0;
873 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
875 kfree (tcp);
877 if (ret)
878 conn->state = PROTO_TCP_CONN_STATE_CLOSE; //ret = net_proto_tcp_conn_del (conn);
879 else
880 return -1;
882 return ret;
885 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn)
887 return 0; /* FIXME: close () is faster then send () sometime :-B */
889 if (!conn)
890 return 0;
892 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
893 return 0;
895 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
897 if (!tcp)
898 return 0;
900 tcp->port_source = conn->port_source; // increase client port too
901 tcp->port_dest = conn->port_dest;
903 tcp->seq = conn->seq;
904 tcp->ack = conn->ack;
906 tcp->res = 0;
907 tcp->data_offset = 5;
908 tcp->flags = 0x11;
909 tcp->window = swap16 (32832);
910 tcp->checksum = 0;
912 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
914 kfree (tcp);
916 if (ret)
917 conn->state = PROTO_TCP_CONN_STATE_CLOSE;
919 return ret;
922 /* client wants to connect */
923 net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
925 if (!conn)
926 return 0;
928 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
930 if (!tcp)
931 return 0;
933 tcp->port_source = conn->port_source;
934 tcp->port_dest = port;
936 tcp->seq = proto_tcp_seq ++;
937 tcp->ack = seq + swap32 (1);
939 tcp->res = 0;
940 tcp->data_offset = 5;
941 tcp->flags = 0x12;
942 tcp->window = swap16 (5816);
943 tcp->checksum = 0;
945 int ret = net_proto_tcp_write (conn->netif, ip, tcp, 0, 0);
947 kfree (tcp);
949 if (ret > 0)
950 conn->state = PROTO_TCP_CONN_STATE_READY;
951 else {
952 printf ("wtf ?\n");
953 return -1;
955 return 1;
958 /* Create new TCP connection */
959 int net_proto_tcp_conn_add (fd_t *fd)
961 proto_tcp_conn_t *conn;
963 /* alloc and init context */
964 conn = (proto_tcp_conn_t *) kmalloc (sizeof (proto_tcp_conn_t));
966 if (!conn) {
967 errno_set (ENOMEM);
968 return -1;
971 memset (conn, 0, sizeof (proto_tcp_conn_t));
973 conn->flags = 0;
974 conn->bind = 0;
976 conn->fd = fd->id;
978 conn->cross = 0;
980 /* add into list */
981 conn->next = &proto_tcp_conn_list;
982 conn->prev = proto_tcp_conn_list.prev;
983 conn->prev->next = conn;
984 conn->next->prev = conn;
986 return 0;
989 /* Setup new connection */
990 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)
992 if (!conn || !eth)
993 return 0;
995 conn->ip_source = eth->ip;
996 conn->ip_dest = ip_dest;
998 conn->port_source = port_source;
999 conn->port_dest = port_dest;
1001 proto_tcp_seq += swap32 (1);
1003 conn->seq = proto_tcp_seq ++;
1004 conn->ack = 0;
1006 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
1008 conn->netif = eth;
1010 conn->offset = 0;
1011 conn->len = 0;
1012 conn->data = 0;
1014 return 1;
1017 /* Delete existing connection from list */
1018 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn)
1020 if (!conn)
1021 return 0;
1023 conn->state = PROTO_TCP_CONN_STATE_DISCONNECTED;
1025 if (conn->len)
1026 kfree (conn->data);
1028 conn->len = 0;
1030 conn->next->prev = conn->prev;
1031 conn->prev->next = conn->next;
1033 kfree (conn);
1035 return 1;
1038 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)
1040 *ret = 0;
1041 proto_tcp_conn_t *conn = NULL;
1042 proto_tcp_conn_t *conn_ret = NULL;
1043 //printf ("-------------------------\n");
1044 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1045 /*printf ("-> ");
1046 net_proto_ip_print (conn->ip_source);
1047 printf (" / ");
1048 net_proto_ip_print (ip_source);
1049 printf ("\n2> ");
1050 net_proto_ip_print (conn->ip_dest);
1051 printf (" / ");
1052 net_proto_ip_print (ip_dest);
1053 printf ("\nporty: %d / %d\n", swap16 (conn->port_source), swap16 (port_source));
1054 printf ("porty2: %d / %d\n", swap16 (conn->port_dest), swap16 (port_dest));*/
1056 if (conn->ip_source == ip_source && conn->port_source == port_source) {
1057 if (conn->ip_dest == ip_dest && conn->port_dest == port_dest) {
1058 *ret = 2;
1059 return conn;
1062 *ret = 1;
1064 conn_ret = conn;
1068 if (*ret == 1)
1069 if (!conn_ret->bind) {
1070 conn_ret = 0;
1072 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1073 if (conn->bind) {
1074 if (conn->ip_source == ip_source && conn->port_source == port_source)
1075 conn_ret = conn;
1080 return conn_ret;
1083 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd)
1085 proto_tcp_conn_t *conn = NULL;
1086 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1087 if (conn->fd == fd)
1088 return conn;
1091 return 0;
1094 /* Create new TCP backlog stamp */
1095 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
1097 if (!conn)
1098 return 0;
1100 proto_tcp_backlog_t *backlog;
1102 /* alloc and init context */
1103 backlog = (proto_tcp_backlog_t *) kmalloc (sizeof (proto_tcp_backlog_t));
1105 if (!backlog)
1106 return 0;
1108 backlog->conn = conn;
1109 backlog->ip = ip;
1110 backlog->port = port;
1111 backlog->seq = seq;
1113 /* add into list */
1114 backlog->next = &proto_tcp_backlog_list;
1115 backlog->prev = proto_tcp_backlog_list.prev;
1116 backlog->prev->next = backlog;
1117 backlog->next->prev = backlog;
1119 return conn->fd;
1122 /* init of tcp protocol */
1123 unsigned init_net_proto_tcp ()
1125 proto_tcp_conn_list.next = &proto_tcp_conn_list;
1126 proto_tcp_conn_list.prev = &proto_tcp_conn_list;
1128 proto_tcp_backlog_list.next = &proto_tcp_backlog_list;
1129 proto_tcp_backlog_list.prev = &proto_tcp_backlog_list;
1131 proto_tcp_dup = 0x0;
1132 proto_tcp_seq = 0x1;
1134 return 1;