Kernel 0.5.9-r11; Lot of bug fixes, file_cache system was
[ZeXOS.git] / kernel / core / net / tcp.c
blob8279b3de2d80fd011c982cdde58c3ecc6901939a
1 /*
2 * ZeX/OS
3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <system.h>
21 #include <string.h>
22 #include <dev.h>
23 #include <net/eth.h>
24 #include <net/net.h>
25 #include <net/if.h>
26 #include <net/packet.h>
27 #include <net/ip.h>
28 #include <net/tcp.h>
29 #include <net/socket.h>
30 #include <mutex.h>
32 /* Mutex for socket function */
33 MUTEX_CREATE (mutex_tcp_accept);
35 proto_tcp_conn_t proto_tcp_conn_list;
36 proto_tcp_backlog_t proto_tcp_backlog_list;
38 extern netif_t netif_list;
40 static net_port proto_tcp_client_port;
41 static unsigned short proto_tcp_dup;
42 static unsigned proto_tcp_seq;
43 static unsigned proto_tcp_fd;
45 /* prototype */
46 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);
47 int net_proto_tcp_conn_add ();
48 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);
49 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest);
50 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
51 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len);
52 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len);
53 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len);
54 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len);
55 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
56 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old);
57 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn);
58 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn);
59 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd);
60 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
61 int net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq);
63 /** TCP protocol
64 * User-friendly socket functions
66 int net_proto_tcp_socket ()
68 return net_proto_tcp_conn_add ();
71 int net_proto_tcp_connect (int fd, sockaddr_in *addr)
73 int ret = -1;
75 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
77 if (!conn)
78 return -1;
80 netif_t *netif;
81 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
82 ret = net_proto_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_port);
84 /* TODO: connect timeout */
86 /* blocking mode */
87 if (!(conn->flags & O_NONBLOCK)) {
88 if (!ret)
89 return -1;
91 while (1) {
92 schedule ();
94 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHED)
95 break;
97 /* when connection cant be accepted succefully first time, try it again */
98 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISHERROR) {
99 ret = net_proto_tcp_conn_estabilish (conn, netif, addr->sin_addr, addr->sin_port);
100 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
103 } else
104 /* non-blocking mode */
105 return -1;
107 ret = 0;
110 return ret;
113 int net_proto_tcp_send (int fd, char *msg, unsigned size)
115 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
117 if (!conn)
118 return -1;
120 int ret = net_proto_tcp_write_data (conn, msg, size);
122 if (ret) {
123 /* blocking mode */
124 if (!(conn->flags & O_NONBLOCK)) {
125 while (conn->state != PROTO_TCP_CONN_STATE_READY)
126 schedule ();
127 } else {
128 /* non-blocking mode */
129 /* TODO: ? */
130 while (conn->state != PROTO_TCP_CONN_STATE_READY)
131 schedule ();
135 return size;
138 int net_proto_tcp_recv (int fd, char *msg, unsigned size)
140 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
142 if (!conn)
143 return -3;
145 int ret = 0;
147 /* blocking mode */
148 if (!(conn->flags & O_NONBLOCK)) {
149 while (!conn->len/* || conn->state != PROTO_TCP_CONN_STATE_READY*/) {
150 if (!conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
151 if (net_proto_tcp_conn_del (conn));
152 return -1;
155 schedule ();
157 } else {
158 if (conn->state == PROTO_TCP_CONN_STATE_CLOSE) {
159 if (net_proto_tcp_conn_del (conn));
160 return -1;
163 if (!conn->len)
164 return 0;
167 if ((conn->len-conn->offset) > size) {
168 memcpy (msg, conn->data+conn->offset, size);
169 //printf ("msg: %d %d\n", conn->offset, size);
170 conn->offset += size;
172 ret = size;
173 } else {
174 ret = conn->len;
176 memcpy (msg, conn->data+conn->offset, conn->len-conn->offset);
177 //printf ("msg2: %d %d\n", conn->offset, size);
178 conn->len = 0;
179 conn->offset = 0;
181 kfree (conn->data);
184 return ret;
187 int net_proto_tcp_close (int fd)
189 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
191 if (!conn)
192 return -1;
194 if (conn->state == PROTO_TCP_CONN_STATE_DISCONNECTED)
195 return 0;
197 int ret = net_proto_tcp_conn_close (conn);
199 return ret;
202 int net_proto_tcp_fcntl (int fd, int cmd, long arg)
204 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
206 if (!conn)
207 return -1;
209 switch (cmd) {
210 case F_GETFL:
211 return conn->flags;
212 case F_SETFL:
213 conn->flags = arg;
214 return 0;
217 return -1;
220 int net_proto_tcp_bind (int fd, sockaddr_in *addr, socklen_t len)
222 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
224 if (!conn)
225 return -1;
227 netif_t *netif;
228 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
229 net_proto_tcp_conn_set (conn, netif, addr->sin_port, 0, 0);
230 conn->bind = 1;
231 return 0;
234 return -1;
237 int net_proto_tcp_listen (int fd, int backlog)
239 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
241 if (!conn)
242 return -1;
244 return 0;
247 int net_proto_tcp_accept (int fd, sockaddr_in *addr, socklen_t *addrlen)
249 proto_tcp_conn_t *conn = net_proto_tcp_conn_find (fd);
251 if (!conn)
252 return -1;
254 unsigned i = 0;
256 proto_tcp_backlog_t *backlog = 0;
258 /* blocking mode */
259 if (!(conn->flags & O_NONBLOCK)) {
260 while (!i) {
261 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
262 if (backlog->conn == conn) {
263 i = 1;
264 break;
268 schedule ();
270 } else {
271 /* non-blocking mode */
272 for (backlog = proto_tcp_backlog_list.next; backlog != &proto_tcp_backlog_list; backlog = backlog->next) {
273 if (backlog->conn == conn) {
274 i = 1;
275 break;
280 //printf ("accept ()\n");
282 if (!i)
283 return -1;
285 net_ipv4 ip = backlog->ip;
286 net_port port = backlog->port;
287 unsigned seq = backlog->seq;
289 int ret = net_proto_tcp_conn_invite (conn, ip, port, seq);
291 /* remove from queue accepted connection */
292 backlog->next->prev = backlog->prev;
293 backlog->prev->next = backlog->next;
295 kfree (backlog);
297 if (ret < 1)
298 return ret;
300 int fd_new = net_proto_tcp_conn_add ();
302 if (!fd_new)
303 return 0;
305 proto_tcp_conn_t *conn_new = net_proto_tcp_conn_find (fd_new);
307 if (!conn_new)
308 return -1;
310 net_proto_tcp_conn_set (conn_new, conn->netif, conn->port_source, conn->netif->ip, port);
312 conn_new->ip_dest = ip;
314 return fd_new;
317 /** TCP protocol
318 * Hardcore code - syn, ack, psh, fin, etc :P
320 unsigned net_proto_tcp_handler (packet_t *packet, proto_ip_t *ip, char *buf, unsigned len)
322 proto_tcp_t *tcp = (proto_tcp_t *) buf;
324 unsigned char ret = 0;
326 /* First check ip address and ports, that we want this data */
327 proto_tcp_conn_t *conn = net_proto_tcp_conn_check (ip->ip_dest, tcp->port_dest, ip->ip_source, tcp->port_source, &ret);
331 if (!conn && ret == 0)
332 return 1;
334 //printf ("tcp->flags: 0x%x, ret: %d, conn: 0x%x\n", tcp->flags, ret, conn);
336 /* connection from client before accept () */
337 if (ret == 1) {
339 /* client want connect to our server */
340 if (tcp->flags == 0x02) {
341 mutex_lock (&mutex_tcp_accept);
343 unsigned ret = net_proto_tcp_backlog_add (conn, ip->ip_source, tcp->port_source, tcp->seq);
345 mutex_unlock (&mutex_tcp_accept);
347 return ret;
350 return 1;
353 /* data received */
354 if (tcp->flags & 0x08) {
355 /* needed for calculate real offset from 4bit number */
356 unsigned offset = tcp->data_offset * 4;
358 /* now calculate accurate length of tcp _data_ */
359 unsigned size = swap16 (ip->total_len) - (offset + (ip->head_len*4));
361 net_proto_tcp_read_cache (conn, buf+offset, size);
363 /* send ack */
364 net_proto_tcp_read_ok (conn, ip, tcp, size);
367 /* sended data was delivered succefully */
368 if (tcp->flags & 0x10) {
369 if (conn->state == PROTO_TCP_CONN_STATE_ESTABILISH) {
370 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHERROR;
371 net_proto_tcp_write_data_ok (conn, ip, tcp);
372 } else
373 net_proto_tcp_write_data_ok (conn, ip, tcp);
376 /* connection estabilish respond */
377 if (tcp->flags == 0x12) {
378 return net_proto_tcp_conn_estabilish_reply (conn, ip, tcp);
381 /* another side close connection */
382 if (tcp->flags & 0x01) {
383 DPRINT ("TCP -> fd %d connection closed by remote host\n", conn->fd);
384 net_proto_tcp_conn_disconnected (conn, ip, tcp);
387 /* another side close connection */
388 if (tcp->flags & 0x04) {
389 DPRINT ("TCP -> fd %d connection reseted by peer\n", conn->fd);
390 net_proto_tcp_conn_disconnected (conn, ip, tcp);
393 return 1;
396 int net_proto_tcp_read_cache (proto_tcp_conn_t *conn, char *data, unsigned len)
398 if (!data || !conn || !len)
399 return 0;
401 if (!conn->len)
402 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
403 else
404 conn->data = (char *) krealloc (conn->data, (sizeof (char) * (conn->len+len)));
406 if (!conn->data)
407 return -1;
409 //kprintf ("DATA: %d - #'%s'#\n", len, data);
411 memcpy (conn->data+conn->len, data, len);
413 conn->len += len;
415 conn->data[conn->len] = '\0';
417 return conn->len;
420 int net_proto_tcp_read_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old, unsigned len)
422 if (!ip_old || !tcp_old || !conn)
423 return 0;
426 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
428 if (!tcp)
429 return 0;
431 tcp->port_source = conn->port_source; // increase client port too
432 tcp->port_dest = conn->port_dest;
434 tcp->seq = tcp_old->ack;
436 /* this small thing did bad thing when e.g. 10 10 10 fe get to calculation,
437 it returns 10 10 10 08, no 10 10 11 08 */
438 unsigned seq = swap32 (tcp_old->seq);
439 seq += len;
441 tcp->ack = swap32 (seq);
443 tcp->res = 0;
444 tcp->data_offset = 5;
445 tcp->flags = 0x10;
446 tcp->window = tcp_old->window + swap16 (64);
447 tcp->checksum = 0;
449 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
451 /*if (proto_tcp_dup == tcp_old->checksum) {
452 printf ("Duplicated packet :)");
453 timer_wait (150);
456 if (ret) {
457 conn->seq = tcp->ack;
458 conn->ack = tcp->seq;
460 proto_tcp_dup = tcp_old->checksum;
463 kfree (tcp);
465 return ret;
468 int net_proto_tcp_write (netif_t *eth, net_ipv4 dest, proto_tcp_t *tcp, char *data, unsigned len)
470 if (!eth || !tcp)
471 return 0;
473 if (len)
474 if (!data)
475 return 0;
477 mac_addr_t mac_dest;
478 unsigned get = arp_cache_get (dest, &mac_dest);
480 if (!get) {
481 arp_send_request (eth, dest);
483 unsigned i = 0;
484 /* 100ms for waiting on ARP reply */
485 while (i < 100) {
486 get = arp_cache_get (dest, &mac_dest);
488 if (get)
489 break;
491 /* TODO: make better waiting for ARP reply */
492 timer_wait (1);
494 schedule ();
496 i ++;
499 if (!get)
500 return 0;
503 /* packet header */
504 packet_t *packet = (packet_t *) kmalloc (sizeof (packet_t));
506 if (!packet)
507 return 0;
509 memcpy (&packet->mac_source, eth->dev->dev_addr, 6);
510 memcpy (&packet->mac_dest, mac_dest, 6);
511 packet->type = NET_PACKET_TYPE_IPV4;
513 /* ip layer */
514 proto_ip_t *ip = (proto_ip_t *) kmalloc (sizeof (proto_ip_t));
516 if (!ip)
517 return 0;
519 /* there are some fixed values - yeah it is horrible */
520 ip->ver = 4;
521 ip->head_len = 5;
523 ip->flags = 0;
524 ip->frag = 0;
525 ip->ttl = 64;
526 ip->checksum = 0;
527 ip->proto = NET_PROTO_IP_TYPE_TCP;
528 ip->ip_source = eth->ip;
529 ip->ip_dest = dest;
531 unsigned l = (tcp->data_offset*4);
533 /* calculate total length of packet (tcp/ip) */
534 ip->total_len = swap16 (l+sizeof (proto_tcp_t)+len);
536 char *buf_tcp = (char *) kmalloc ((len+l+1) * sizeof (char));
538 if (!buf_tcp)
539 return 0;
541 memcpy (buf_tcp, (char *) tcp, l);
543 if (len)
544 memcpy (buf_tcp+l, data, len);
546 buf_tcp[l+len] = '\0';
548 /* calculate checksum and put it to tcp header */
549 proto_tcp_t *tcp_ = (proto_tcp_t *) buf_tcp;
551 tcp_->checksum = checksum16_tcp (eth->ip, dest, buf_tcp, l+len);
553 /* send tcp header+data to ip layer */
554 unsigned ret = net_proto_ip_send (eth, packet, ip, (char *) buf_tcp, l+len);
556 kfree (buf_tcp);
557 kfree (ip);
558 kfree (packet);
560 return ret;
563 int net_proto_tcp_write_data (proto_tcp_conn_t *conn, char *data, unsigned len)
565 if (!conn || !len || !data)
566 return 0;
568 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
570 if (!tcp)
571 return 0;
573 tcp->port_source = conn->port_source;
574 tcp->port_dest = conn->port_dest;
576 proto_tcp_seq += swap32 (1);
578 tcp->seq = conn->seq;
579 tcp->ack = conn->ack;
581 tcp->res = 0;
582 tcp->data_offset = 5;
583 tcp->flags = 0x18;
584 tcp->window = swap16 (32768);
585 tcp->checksum = 0;
587 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, data, len);
589 kfree (tcp);
591 if (ret)
592 conn->state = PROTO_TCP_CONN_STATE_WAIT;
594 return ret;
597 int net_proto_tcp_write_data_ok (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
599 if (!ip_old || !tcp_old || !conn)
600 return 0;
602 /* cross - because we change now sides :) */
603 conn->seq = tcp_old->ack;
604 conn->ack = tcp_old->seq;
606 conn->state = PROTO_TCP_CONN_STATE_READY;
608 return 1;
611 /* try connect to server */
612 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t *conn, netif_t *eth, net_ipv4 ip_dest, net_port port_dest)
614 if (!conn)
615 return 0;
617 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
619 if (!tcp)
620 return 0;
622 tcp->port_source = swap16 (proto_tcp_client_port); // increase client port too
623 tcp->port_dest = port_dest;
625 /* setup new connection */
626 net_proto_tcp_conn_set (conn, eth, tcp->port_source, ip_dest, tcp->port_dest);
628 tcp->seq = conn->seq;
629 tcp->ack = conn->ack;
631 tcp->res = 0;
632 tcp->data_offset = 5;
633 tcp->flags = 0x02;
634 tcp->window = swap16 (32792);
635 tcp->checksum = 0;
637 int ret = net_proto_tcp_write (eth, ip_dest, tcp, 0, 0);
639 kfree (tcp);
641 if (!ret) {
642 net_proto_tcp_conn_del (conn);
643 return 0;
646 return 1;
649 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
651 if (!ip_old || !tcp_old || !conn)
652 return 0;
654 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
656 if (!tcp)
657 return 0;
659 tcp->port_source = conn->port_source; // increase client port too
660 tcp->port_dest = conn->port_dest;
662 tcp->seq = tcp_old->ack;
663 tcp->ack = tcp_old->seq + swap32 (1);
665 tcp->res = 0;
666 tcp->data_offset = 5;
667 tcp->flags = 0x10;
668 tcp->window = tcp_old->window + swap16 (64);
669 tcp->checksum = 0;
671 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
673 if (ret) {
674 conn->seq = tcp->seq;
675 conn->ack = tcp->ack;
676 conn->state = PROTO_TCP_CONN_STATE_ESTABILISHED;
679 DPRINT ("TCP -> fd %ï connected to server succefully\n", conn->fd);
681 kfree (tcp);
683 return ret;
686 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t *conn, proto_ip_t *ip_old, proto_tcp_t *tcp_old)
688 if (!ip_old || !tcp_old || !conn)
689 return 0;
691 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
693 if (!tcp)
694 return 0;
696 tcp->port_source = conn->port_source; // increase client port too
697 tcp->port_dest = conn->port_dest;
699 tcp->seq = tcp_old->ack;
700 tcp->ack = tcp_old->seq + swap32 (1);
702 tcp->res = 0;
703 tcp->data_offset = 5;
704 tcp->flags = 0x10;
705 tcp->window = tcp_old->window + swap16 (64);
706 tcp->checksum = 0;
708 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
710 kfree (tcp);
712 if (ret)
713 conn->state = PROTO_TCP_CONN_STATE_CLOSE; //ret = net_proto_tcp_conn_del (conn);
714 else
715 return -1;
717 return ret;
720 int net_proto_tcp_conn_close (proto_tcp_conn_t *conn)
722 if (!conn)
723 return 0;
725 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
727 if (!tcp)
728 return 0;
730 tcp->port_source = conn->port_source; // increase client port too
731 tcp->port_dest = conn->port_dest;
733 tcp->seq = conn->seq;
734 tcp->ack = conn->ack;
736 tcp->res = 0;
737 tcp->data_offset = 5;
738 tcp->flags = 0x11;
739 tcp->window = swap16 (32832);
740 tcp->checksum = 0;
742 int ret = net_proto_tcp_write (conn->netif, conn->ip_dest, tcp, 0, 0);
744 kfree (tcp);
746 if (ret) {
747 conn->state = PROTO_TCP_CONN_STATE_CLOSE;
750 return ret;
753 /* client wants to connect */
754 net_proto_tcp_conn_invite (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
756 if (!conn)
757 return 0;
759 proto_tcp_t *tcp = (proto_tcp_t *) kmalloc (sizeof (proto_tcp_t));
761 if (!tcp)
762 return 0;
763 printf ("hehe\n");
764 tcp->port_source = conn->port_source;
765 tcp->port_dest = port;
767 tcp->seq = proto_tcp_seq ++;
768 tcp->ack = seq + swap32 (1);
770 tcp->res = 0;
771 tcp->data_offset = 5;
772 tcp->flags = 0x12;
773 tcp->window = swap16 (5816);
774 tcp->checksum = 0;
776 int ret = net_proto_tcp_write (conn->netif, ip, tcp, 0, 0);
778 kfree (tcp);
780 if (ret)
781 conn->state = PROTO_TCP_CONN_STATE_READY;
782 else {
783 printf ("wtf ?\n");
784 return -1;
786 return 1;
789 /* Create new TCP connection */
790 int net_proto_tcp_conn_add ()
792 proto_tcp_conn_t *conn;
794 /* alloc and init context */
795 conn = (proto_tcp_conn_t *) kmalloc (sizeof (proto_tcp_conn_t));
797 if (!conn)
798 return 0;
800 memset (conn, 0, sizeof (proto_tcp_conn_t));
802 conn->flags = 0;
803 conn->bind = 0;
805 conn->fd = proto_tcp_fd ++;
807 /* add into list */
808 conn->next = &proto_tcp_conn_list;
809 conn->prev = proto_tcp_conn_list.prev;
810 conn->prev->next = conn;
811 conn->next->prev = conn;
813 return conn->fd;
816 /* Setup new connection */
817 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)
819 if (!conn || !eth)
820 return 0;
822 conn->ip_source = eth->ip;
823 conn->ip_dest = ip_dest;
825 conn->port_source = port_source;
826 conn->port_dest = port_dest;
828 proto_tcp_seq += swap32 (1);
830 conn->seq = proto_tcp_seq ++;
831 conn->ack = 0;
833 conn->state = PROTO_TCP_CONN_STATE_ESTABILISH;
835 conn->netif = eth;
837 conn->offset = 0;
838 conn->len = 0;
839 conn->data = 0;
841 return 1;
844 /* Delete existing connection from list */
845 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t *conn)
847 if (!conn)
848 return 0;
850 conn->state = PROTO_TCP_CONN_STATE_DISCONNECTED;
852 if (conn->len)
853 kfree (conn->data);
855 conn->len = 0;
857 conn->next->prev = conn->prev;
858 conn->prev->next = conn->next;
860 kfree (conn);
862 return 1;
865 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)
867 *ret = 0;
868 proto_tcp_conn_t *conn = NULL;
869 proto_tcp_conn_t *conn_ret = NULL;
870 //printf ("-------------------------\n");
871 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
872 /*printf ("-> ");
873 net_proto_ip_print (conn->ip_source);
874 printf (" / ");
875 net_proto_ip_print (ip_source);
876 printf ("\n2> ");
877 net_proto_ip_print (conn->ip_dest);
878 printf (" / ");
879 net_proto_ip_print (ip_dest);
880 printf ("\nporty: %d / %d\n", swap16 (conn->port_source), swap16 (port_source));
881 printf ("porty2: %d / %d\n", swap16 (conn->port_dest), swap16 (port_dest));*/
883 if (conn->ip_source == ip_source && conn->port_source == port_source) {
884 if (conn->ip_dest == ip_dest && conn->port_dest == port_dest) {
885 *ret = 2;
886 return conn;
889 *ret = 1;
891 conn_ret = conn;
895 if (*ret == 1)
896 if (!conn_ret->bind) {
897 conn_ret = 0;
899 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
900 if (conn->bind) {
901 if (conn->ip_source == ip_source && conn->port_source == port_source)
902 conn_ret = conn;
907 return conn_ret;
910 proto_tcp_conn_t *net_proto_tcp_conn_find (int fd)
912 proto_tcp_conn_t *conn = NULL;
913 for (conn = proto_tcp_conn_list.next; conn != &proto_tcp_conn_list; conn = conn->next) {
914 if (conn->fd == fd)
915 return conn;
918 return 0;
921 /* Create new TCP backlog stamp */
922 int net_proto_tcp_backlog_add (proto_tcp_conn_t *conn, net_ipv4 ip, net_port port, unsigned seq)
924 if (!conn)
925 return 0;
927 proto_tcp_backlog_t *backlog;
929 /* alloc and init context */
930 backlog = (proto_tcp_backlog_t *) kmalloc (sizeof (proto_tcp_backlog_t));
932 if (!backlog)
933 return 0;
935 backlog->conn = conn;
936 backlog->ip = ip;
937 backlog->port = port;
938 backlog->seq = seq;
940 /* add into list */
941 backlog->next = &proto_tcp_backlog_list;
942 backlog->prev = proto_tcp_backlog_list.prev;
943 backlog->prev->next = backlog;
944 backlog->next->prev = backlog;
946 return conn->fd;
949 /* init of tcp protocol */
950 unsigned init_net_proto_tcp ()
952 proto_tcp_conn_list.next = &proto_tcp_conn_list;
953 proto_tcp_conn_list.prev = &proto_tcp_conn_list;
955 proto_tcp_backlog_list.next = &proto_tcp_backlog_list;
956 proto_tcp_backlog_list.prev = &proto_tcp_backlog_list;
958 /* base tcp client port, which is used for client's use */
959 proto_tcp_client_port = 1024;
960 proto_tcp_dup = 0x0;
961 proto_tcp_seq = 0x1;
962 proto_tcp_fd = 1024;
964 return 1;