New version 0.6.6: app edit was improved; app nc was improved + code cleanup; app...
[ZeXOS.git] / kernel / core / net / tcp.c
blob8e84fac2665a3331dae9b501a9dc3c0d7ef3ba5f
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/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 while (1) {
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 int ret = net_proto_tcp_conn_close (conn);
233 return ret;
236 int net_proto_tcp_fcntl (int fd, int cmd, long arg)
238 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
240 if (!conn)
241 return -1;
243 switch (cmd) {
244 case F_GETFL:
245 return conn->flags;
246 case F_SETFL:
247 conn->flags = arg;
248 return 0;
251 return -1;
254 int net_proto_tcp_bind (int fd, sockaddr_in *addr, socklen_t len)
256 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
258 if (!conn)
259 return -1;
261 netif_t *netif;
262 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
263 net_proto_tcp_conn_set (conn, netif, addr->sin_port, 0, 0);
264 conn->bind = 1;
265 return 0;
268 return -1;
271 int net_proto_tcp_listen (int fd, int backlog)
273 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
275 if (!conn)
276 return -1;
278 return 0;
281 int net_proto_tcp_accept (int fd, sockaddr_in *addr, socklen_t *addrlen)
283 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
285 if (!conn)
286 return -1;
288 unsigned i = 0;
290 proto_tcp_backlog_t *backlog = 0;
292 /* blocking mode */
293 if (!(conn->flags & O_NONBLOCK)) {
294 while (!i) {
295 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
296 if (backlog->conn == conn) {
297 i = 1;
298 break;
302 schedule ();
304 } else {
305 /* non-blocking mode */
306 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
307 if (backlog->conn == conn) {
308 i = 1;
309 break;
314 //printf ("accept ()\n");
316 if (!i)
317 return -1;
319 net_ipv4 ip = backlog->ip;
320 net_port port = backlog->port;
321 unsigned seq = backlog->seq;
323 int ret = net_proto_tcp_conn_invite (conn, ip, port, seq);
325 /* remove from queue accepted connection */
326 backlog->next->prev = backlog->prev;
327 backlog->prev->next = backlog->next;
329 kfree (backlog);
331 if (ret < 1)
332 return ret;
334 fd_t *fd_new = fd_create (FD_SOCK);
336 if (!fd_new)
337 return 0;
339 net_proto_tcp_conn_add (fd_new);
341 proto_tcp_conn_t *conn_new = net_proto_tcp_conn_find (fd_new->id);
343 if (!conn_new)
344 return -1;
346 net_proto_tcp_conn_set (conn_new, conn->netif, conn->port_source, conn->netif->ip, port);
348 conn_new->ip_dest = ip;
350 addr->sin_addr = ip;
351 addr->sin_port = port;
352 addr->sin_family = AF_INET;
354 return fd_new->id;
357 /** TCP protocol
358 * Hardcore code - syn, ack, psh, fin, etc :P
360 unsigned net_proto_tcp_handler (packet_t *packet, proto_ip_t *ip, char *buf, unsigned len)
362 proto_tcp_t *tcp = (proto_tcp_t *) buf;
364 unsigned char ret = 0;
366 /* First check ip address and ports, that we want this data */
367 proto_tcp_conn_t *conn = net_proto_tcp_conn_check (ip->ip_dest, tcp->port_dest, ip->ip_source, tcp->port_source, &ret);
369 if (!conn && ret == 0)
370 return 1;
372 //printf ("tcp->flags: 0x%x, ret: %d, conn: 0x%x, fd: %d\n", tcp->flags, ret, conn, conn->fd);
374 /* connection from client before accept () */
375 if (ret == 1) {
376 /* client want connect to our server */
377 if (tcp->flags == 0x02) {
378 mutex_lock (&mutex_tcp_accept);
380 unsigned ret = net_proto_tcp_backlog_add (conn, ip->ip_source, tcp->port_source, tcp->seq);
382 mutex_unlock (&mutex_tcp_accept);
384 return ret;
387 return 1;
390 unsigned data_cache = 0;
392 /* data received */
393 if (tcp->flags & 0x08) {
394 /* needed for calculate real offset from 4bit number */
395 unsigned offset = tcp->data_offset * 4;
397 /* now calculate accurate length of tcp _data_ */
398 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
399 //kprintf (">>>> %d : %d : %d\n", offset, size, len);
400 //mutex_lock (&mutex_tcp_read_cache);
401 net_proto_tcp_read_cache (conn, buf+offset, size);
402 //mutex_unlock (&mutex_tcp_read_cache);
403 /* send ack */
404 net_proto_tcp_read_ok (conn, ip, tcp, size);
406 data_cache = 1;
409 /* sended data was delivered succefully */
410 if (tcp->flags & 0x10) {
411 /* HACK: It is interesting, that no push flag, and there could be some data to read */
413 /* needed for calculate real offset from 4bit number */
414 unsigned offset = tcp->data_offset * 4;
416 /* now calculate accurate length of tcp _data_ */
417 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
419 /* there are data for read */
420 if (size) {
421 /* data was cached, so no need cache it again */
422 if (!data_cache) {
423 //kprintf (">>>>2 %d : %d : %d\n", offset, size, len);
424 mutex_lock (&mutex_tcp_read_cache);
425 net_proto_tcp_read_cache (conn, buf+offset, size);
426 mutex_unlock (&mutex_tcp_read_cache);
427 /* send ack */
428 net_proto_tcp_read_ok (conn, ip, tcp, size);
430 } else {
431 /* when data are'nt available, lets normal work - acknowledgement */
432 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISH) {
433 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHERROR;
434 net_proto_tcp_write_data_ok (conn, ip, tcp);
435 } else
436 net_proto_tcp_write_data_ok (conn, ip, tcp);
440 /* connection estabilish respond */
441 if (tcp->flags == 0x12) {
442 return net_proto_tcp_conn_estabilish_reply (conn, ip, tcp);
445 /* another side close connection */
446 if (tcp->flags & 0x01) {
447 DPRINT ("TCP -> fd %d connection closed by remote host\n", conn->fd);
448 net_proto_tcp_conn_disconnected (conn, ip, tcp); // FIXME: problem in server with hangind the whole program
451 /* another side close connection */
452 if (tcp->flags & 0x04) {
453 DPRINT ("TCP -> fd %d connection reseted by peer\n", conn->fd);
454 net_proto_tcp_conn_disconnected (conn, ip, tcp);
457 return 1;
460 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len)
462 if (!data || !conn || !len)
463 return 0;
465 if (!conn->len) {
466 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
468 memcpy (conn->data, data, len);
469 } else {
470 char *newdata = (char *) kmalloc (sizeof (char) * (conn->len + len + 1));
472 if (!newdata)
473 return 0;
475 memcpy (newdata, conn->data, conn->len);
476 memcpy (newdata+conn->len, data, len);
478 kfree (conn->data);
480 conn->data = newdata;
483 if (!conn->data)
484 return -1;
486 //kprintf ("DATA: %d - #'%s'#\n", len, data);
488 conn->len += len;
490 conn->data[conn->len] = '\0';
492 return conn->len;
495 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len)
497 if (!ip_old || !tcp_old || !conn)
498 return 0;
500 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
502 if (!tcp)
503 return 0;
505 tcp->port_source = conn->port_source; // increase client port too
506 tcp->port_dest = conn->port_dest;
508 tcp->seq = tcp_old->ack;
510 /* this small thing did bad work when e.g. 10 10 10 fe get to calculation,
511 it returns 10 10 10 08, no 10 10 11 08 */
512 unsigned seq = swap32 (tcp_old->seq);
513 seq += len;
515 tcp->ack = swap32 (seq);
517 tcp->res = 0;
518 tcp->data_offset = 5;
519 tcp->flags = 0x10;
520 tcp->window = tcp_old->window + swap16 (64);
521 tcp->checksum = 0;
523 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
525 /*if (proto_tcp_dup == tcp_old->checksum) {
526 printf ("Duplicated packet :)");
527 timer_wait (150);
530 if (ret) {
531 //printf ("read_ok: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
533 conn->seq = tcp->ack;
534 conn->ack = tcp->seq;
536 //printf ("read_ok2: seq: 0x%x | ack: 0x%x\n", conn->seq, conn->ack);
538 proto_tcp_dup = tcp_old->checksum;
540 conn->cross = 1;
543 kfree (tcp);
545 return ret;
548 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len)
550 if (!eth || !tcp)
551 return 0;
553 if (len)
554 if (!data)
555 return 0;
557 mac_addr_t mac_dest;
558 unsigned get = arp_cache_get (dest, &mac_dest);
560 if (!get) {
561 arp_send_request (eth, dest);
563 unsigned i = 0;
564 /* 100ms for waiting on ARP reply */
565 while (i < 100) {
566 get = arp_cache_get (dest, &mac_dest);
568 if (get)
569 break;
571 /* TODO: make better waiting for ARP reply */
572 timer_wait (1);
574 schedule ();
576 i ++;
579 if (!get)
580 return 0;
583 /* packet header */
584 packet_t *packet = &packet_prealloc;
586 if (!packet)
587 return 0;
589 memcpy (&packet->mac_source, eth->dev->dev_addr, 6);
590 memcpy (&packet->mac_dest, mac_dest, 6);
591 packet->type = NET_PACKET_TYPE_IPV4;
593 /* ip layer */
594 proto_ip_t *ip = &proto_ip_prealloc;
596 if (!ip)
597 return 0;
599 /* there are some fixed values - yeah it is horrible */
600 ip->ver = 4;
601 ip->head_len = 5;
603 ip->flags = 0;
604 ip->frag = 0;
605 ip->ttl = 64;
606 ip->checksum = 0;
607 ip->proto = NET_PROTO_IP_TYPE_TCP;
608 ip->ip_source = eth->ip;
609 ip->ip_dest = dest;
611 unsigned l = (tcp->data_offset*4);
613 /* calculate total length of packet (tcp/ip) */
614 ip->total_len = swap16 (l+sizeof (proto_tcp_t)+len);
616 char *buf_tcp = (char *) kmalloc ((len+l+1) * sizeof (char));
618 if (!buf_tcp)
619 return 0;
621 memcpy (buf_tcp, (char *) tcp, l);
623 if (len)
624 memcpy (buf_tcp+l, data, len);
626 buf_tcp[l+len] = '\0';
628 /* calculate checksum and put it to tcp header */
629 proto_tcp_t *tcp_ = (proto_tcp_t *) buf_tcp;
631 tcp_->checksum = checksum16_tcp (eth->ip, dest, buf_tcp, l+len);
633 /* send tcp header+data to ip layer */
634 unsigned ret = net_proto_ip_send (eth, packet, ip, (char *) buf_tcp, l+len);
636 kfree (buf_tcp);
638 return ret;
641 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len)
643 if (!conn || !len || !data)
644 return 0;
646 proto_tcp_t *tcp = &proto_tcp_prealloc;
648 if (!tcp)
649 return 0;
651 tcp->port_source = conn->port_source;
652 tcp->port_dest = conn->port_dest;
654 unsigned seq = swap32 (proto_tcp_seq);
655 seq ++;
657 //tcp->ack = swap32 (seq);
659 proto_tcp_seq = swap32 (seq);
661 if (!conn->cross) {
662 tcp->seq = conn->seq;
663 tcp->ack = conn->ack;
664 } else {
665 tcp->seq = conn->ack;
666 tcp->ack = conn->seq;
668 conn->cross = 0;
671 //printf ("TCP -> seq: 0x%x | ack: 0x%x | proto_seq: 0x%x\n", tcp->seq, conn->ack, proto_tcp_seq);
673 tcp->res = 0;
674 tcp->data_offset = 5;
675 tcp->flags = 0x18;
676 tcp->window = swap16 (32768);
677 tcp->checksum = 0;
679 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, data, len);
681 if (ret)
682 conn->state = PROTO_TCP_CONN_STATE_WAIT;
684 return ret;
687 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
689 if (!ip_old || !tcp_old || !conn)
690 return 0;
692 /* cross - because we change now sides :) */
693 conn->seq = tcp_old->ack;
694 conn->ack = tcp_old->seq;
696 //printf ("data_ok: seq: 0x%x | ack: 0x%x\n", tcp_old->ack, tcp_old->seq);
698 conn->state = PROTO_TCP_CONN_STATE_READY;
700 return 1;
703 /* try connect to server */
704 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest)
706 if (!conn)
707 return 0;
709 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
711 if (!tcp)
712 return 0;
714 tcp->port_source = swap16 (netif_port_get ()); // increase client port too
715 tcp->port_dest = port_dest;
717 /* setup new connection */
718 net_proto_tcp_conn_set (conn, eth, tcp->port_source, ip_dest, tcp->port_dest);
720 tcp->seq = conn->seq;
721 tcp->ack = conn->ack;
723 tcp->res = 0;
724 tcp->data_offset = 5;
725 tcp->flags = 0x02;
726 tcp->window = swap16 (32792);
727 tcp->checksum = 0;
729 int ret = net_proto_tcp_write (eth, ip_dest, tcp, 0, 0);
731 kfree (tcp);
733 if (!ret) {
734 net_proto_tcp_conn_del (conn);
735 return 0;
738 return 1;
741 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
743 if (!ip_old || !tcp_old || !conn)
744 return 0;
746 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
748 if (!tcp)
749 return 0;
751 tcp->port_source = conn->port_source; // increase client port too
752 tcp->port_dest = conn->port_dest;
754 tcp->seq = tcp_old->ack;
755 tcp->ack = tcp_old->seq + swap32 (1);
757 tcp->res = 0;
758 tcp->data_offset = 5;
759 tcp->flags = 0x10;
760 tcp->window = tcp_old->window + swap16 (64);
761 tcp->checksum = 0;
763 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
765 if (ret) {
766 conn->seq = tcp->seq;
767 conn->ack = tcp->ack;
768 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHED;
771 DPRINT ("TCP -> fd %d connected to server succefully\n", conn->fd);
773 kfree (tcp);
775 return ret;
778 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
780 if (!ip_old || !tcp_old || !conn)
781 return 0;
783 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE)
784 return net_proto_tcp_conn_del (conn);
786 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
788 if (!tcp)
789 return 0;
791 tcp->port_source = conn->port_source; // increase client port too
792 tcp->port_dest = conn->port_dest;
794 tcp->seq = tcp_old->ack;
795 tcp->ack = tcp_old->seq + swap32 (1);
797 tcp->res = 0;
798 tcp->data_offset = 5;
799 tcp->flags = 0x10;
800 tcp->window = tcp_old->window + swap16 (64);
801 tcp->checksum = 0;
803 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
805 kfree (tcp);
807 if (ret)
808 conn->state = PROTO_TCP_CONN_STATE_CLOSE; //ret = net_proto_tcp_conn_del (conn);
809 else
810 return -1;
812 return ret;
815 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn)
817 if (!conn)
818 return 0;
820 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
822 if (!tcp)
823 return 0;
825 tcp->port_source = conn->port_source; // increase client port too
826 tcp->port_dest = conn->port_dest;
828 tcp->seq = conn->seq;
829 tcp->ack = conn->ack;
831 tcp->res = 0;
832 tcp->data_offset = 5;
833 tcp->flags = 0x11;
834 tcp->window = swap16 (32832);
835 tcp->checksum = 0;
837 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
839 kfree (tcp);
841 if (ret) {
842 conn->state = PROTO_TCP_CONN_STATE_CLOSE;
845 return ret;
848 /* client wants to connect */
849 net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
851 if (!conn)
852 return 0;
854 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
856 if (!tcp)
857 return 0;
859 tcp->port_source = conn->port_source;
860 tcp->port_dest = port;
862 tcp->seq = proto_tcp_seq ++;
863 tcp->ack = seq + swap32 (1);
865 tcp->res = 0;
866 tcp->data_offset = 5;
867 tcp->flags = 0x12;
868 tcp->window = swap16 (5816);
869 tcp->checksum = 0;
871 int ret = net_proto_tcp_write (conn->netif, ip, tcp, 0, 0);
873 kfree (tcp);
875 if (ret > 0)
876 conn->state = PROTO_TCP_CONN_STATE_READY;
877 else {
878 printf ("wtf ?\n");
879 return -1;
881 return 1;
884 /* Create new TCP connection */
885 int net_proto_tcp_conn_add (fd_t *fd)
887 proto_tcp_conn_t *conn;
889 /* alloc and init context */
890 conn = (proto_tcp_conn_t *) kmalloc (sizeof (proto_tcp_conn_t));
892 if (!conn) {
893 errno_set (ENOMEM);
894 return -1;
897 memset (conn, 0, sizeof (proto_tcp_conn_t));
899 conn->flags = 0;
900 conn->bind = 0;
902 conn->fd = fd->id;
904 conn->cross = 0;
906 /* add into list */
907 conn->next = &proto_tcp_conn_list;
908 conn->prev = proto_tcp_conn_list.prev;
909 conn->prev->next = conn;
910 conn->next->prev = conn;
912 return 0;
915 /* Setup new connection */
916 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)
918 if (!conn || !eth)
919 return 0;
921 conn->ip_source = eth->ip;
922 conn->ip_dest = ip_dest;
924 conn->port_source = port_source;
925 conn->port_dest = port_dest;
927 proto_tcp_seq += swap32 (1);
929 conn->seq = proto_tcp_seq ++;
930 conn->ack = 0;
932 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
934 conn->netif = eth;
936 conn->offset = 0;
937 conn->len = 0;
938 conn->data = 0;
940 return 1;
943 /* Delete existing connection from list */
944 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn)
946 if (!conn)
947 return 0;
949 conn->state = PROTO_TCP_CONN_STATE_DISCONNECTED;
951 if (conn->len)
952 kfree (conn->data);
954 conn->len = 0;
956 conn->next->prev = conn->prev;
957 conn->prev->next = conn->next;
959 kfree (conn);
961 return 1;
964 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)
966 *ret = 0;
967 proto_tcp_conn_t *conn = NULL;
968 proto_tcp_conn_t *conn_ret = NULL;
969 //printf ("-------------------------\n");
970 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
971 /*printf ("-> ");
972 net_proto_ip_print (conn->ip_source);
973 printf (" / ");
974 net_proto_ip_print (ip_source);
975 printf ("\n2> ");
976 net_proto_ip_print (conn->ip_dest);
977 printf (" / ");
978 net_proto_ip_print (ip_dest);
979 printf ("\nporty: %d / %d\n", swap16 (conn->port_source), swap16 (port_source));
980 printf ("porty2: %d / %d\n", swap16 (conn->port_dest), swap16 (port_dest));*/
982 if (conn->ip_source == ip_source && conn->port_source == port_source) {
983 if (conn->ip_dest == ip_dest && conn->port_dest == port_dest) {
984 *ret = 2;
985 return conn;
988 *ret = 1;
990 conn_ret = conn;
994 if (*ret == 1)
995 if (!conn_ret->bind) {
996 conn_ret = 0;
998 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
999 if (conn->bind) {
1000 if (conn->ip_source == ip_source && conn->port_source == port_source)
1001 conn_ret = conn;
1006 return conn_ret;
1009 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd)
1011 proto_tcp_conn_t *conn = NULL;
1012 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
1013 if (conn->fd == fd)
1014 return conn;
1017 return 0;
1020 /* Create new TCP backlog stamp */
1021 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
1023 if (!conn)
1024 return 0;
1026 proto_tcp_backlog_t *backlog;
1028 /* alloc and init context */
1029 backlog = (proto_tcp_backlog_t *) kmalloc (sizeof (proto_tcp_backlog_t));
1031 if (!backlog)
1032 return 0;
1034 backlog->conn = conn;
1035 backlog->ip = ip;
1036 backlog->port = port;
1037 backlog->seq = seq;
1039 /* add into list */
1040 backlog->next = &proto_tcp_backlog_list;
1041 backlog->prev = proto_tcp_backlog_list.prev;
1042 backlog->prev->next = backlog;
1043 backlog->next->prev = backlog;
1045 return conn->fd;
1048 /* init of tcp protocol */
1049 unsigned init_net_proto_tcp ()
1051 proto_tcp_conn_list.next = &proto_tcp_conn_list;
1052 proto_tcp_conn_list.prev = &proto_tcp_conn_list;
1054 proto_tcp_backlog_list.next = &proto_tcp_backlog_list;
1055 proto_tcp_backlog_list.prev = &proto_tcp_backlog_list;
1057 proto_tcp_dup = 0x0;
1058 proto_tcp_seq = 0x1;
1060 return 1;