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/>.
26 #include <net/packet.h>
29 #include <net/socket.h>
31 proto_tcp_conn_t proto_tcp_conn_list
;
33 extern netif_t netif_list
;
35 static net_port proto_tcp_client_port
;
36 static unsigned short proto_tcp_dup
;
37 static unsigned proto_tcp_seq
;
39 static unsigned proto_tcp_fd
;
42 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
);
43 int net_proto_tcp_conn_add ();
44 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
);
45 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t
*conn
, netif_t
*eth
, net_ipv4 ip_dest
, net_port port_dest
);
46 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t
*conn
, proto_ip_t
*ip_old
, proto_tcp_t
*tcp_old
);
47 int net_proto_tcp_read_cache (proto_tcp_conn_t
*conn
, char *data
, unsigned len
);
48 int net_proto_tcp_read_ok (proto_tcp_conn_t
*conn
, proto_ip_t
*ip_old
, proto_tcp_t
*tcp_old
, unsigned len
);
49 int net_proto_tcp_write (netif_t
*eth
, net_ipv4 dest
, proto_tcp_t
*tcp
, char *data
, unsigned len
);
50 int net_proto_tcp_write_data (proto_tcp_conn_t
*conn
, char *data
, unsigned len
);
51 int net_proto_tcp_write_data_ok (proto_tcp_conn_t
*conn
, proto_ip_t
*ip_old
, proto_tcp_t
*tcp_old
);
52 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t
*conn
, proto_ip_t
*ip_old
, proto_tcp_t
*tcp_old
);
53 int net_proto_tcp_conn_close (proto_tcp_conn_t
*conn
);
54 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t
*conn
);
55 proto_tcp_conn_t
*net_proto_tcp_conn_find (int fd
);
58 * User-friendly socket functions
60 int net_proto_tcp_socket ()
62 return net_proto_tcp_conn_add ();
65 int net_proto_tcp_connect (int fd
, sockaddr_in
*addr
)
69 proto_tcp_conn_t
*conn
= net_proto_tcp_conn_find (fd
);
75 for (netif
= netif_list
.next
; netif
!= &netif_list
; netif
= netif
->next
) {
76 ret
= net_proto_tcp_conn_estabilish (conn
, netif
, net_proto_ip_convert (addr
->sin_addr
), addr
->sin_port
);
78 /* TODO: connect timeout */
81 if (!(conn
->flags
& O_NONBLOCK
)) {
85 while (conn
->state
!= PROTO_TCP_CONN_STATE_ESTABILISHED
)
88 /* non-blocking mode */
97 int net_proto_tcp_send (int fd
, char *msg
, unsigned size
)
99 proto_tcp_conn_t
*conn
= net_proto_tcp_conn_find (fd
);
104 int ret
= net_proto_tcp_write_data (conn
, msg
, size
);
108 if (!(conn
->flags
& O_NONBLOCK
)) {
109 while (conn
->state
!= PROTO_TCP_CONN_STATE_READY
)
112 /* non-blocking mode */
114 while (conn
->state
!= PROTO_TCP_CONN_STATE_READY
)
122 int net_proto_tcp_recv (int fd
, char *msg
, unsigned size
)
124 proto_tcp_conn_t
*conn
= net_proto_tcp_conn_find (fd
);
132 if (!(conn
->flags
& O_NONBLOCK
)) {
133 while (!conn
->len
/* || conn->state != PROTO_TCP_CONN_STATE_READY*/) {
134 if (!conn
->state
== PROTO_TCP_CONN_STATE_CLOSE
) {
135 if (net_proto_tcp_conn_del (conn
));
142 if (conn
->state
== PROTO_TCP_CONN_STATE_CLOSE
) {
143 if (net_proto_tcp_conn_del (conn
));
151 if (conn
->len
> size
)
156 memcpy (msg
, conn
->data
, conn
->len
);
165 int net_proto_tcp_close (int fd
)
167 proto_tcp_conn_t
*conn
= net_proto_tcp_conn_find (fd
);
172 if (conn
->state
== PROTO_TCP_CONN_STATE_DISCONNECTED
)
175 int ret
= net_proto_tcp_conn_close (conn
);
180 int net_proto_tcp_fcntl (int fd
, int cmd
, long arg
)
182 proto_tcp_conn_t
*conn
= net_proto_tcp_conn_find (fd
);
199 * Hardend code - syn, ack, psh, fin, etc :P
201 unsigned net_proto_tcp_handler (packet_t
*packet
, proto_ip_t
*ip
, char *buf
, unsigned len
)
203 proto_tcp_t
*tcp
= (proto_tcp_t
*) buf
;
205 /* First check ip address and ports, that we want this data */
206 proto_tcp_conn_t
*conn
= net_proto_tcp_conn_check (ip
->ip_dest
, tcp
->port_dest
, ip
->ip_source
, tcp
->port_source
);
212 if (tcp
->flags
& 0x08) {
213 /* needed for calculate real offset from 4bit number */
214 unsigned offset
= tcp
->data_offset
* 4;
216 /* now calculate accurate length of tcp _data_ */
217 unsigned size
= swap16 (ip
->total_len
) - (offset
+ (ip
->head_len
*4));
219 net_proto_tcp_read_cache (conn
, buf
+offset
, size
);
222 net_proto_tcp_read_ok (conn
, ip
, tcp
, size
);
225 /* sended data was delivered succefully */
226 if (tcp
->flags
& 0x10) {
227 net_proto_tcp_write_data_ok (conn
, ip
, tcp
);
230 /* connection estabilish respond */
231 if (tcp
->flags
== 0x12) {
232 return net_proto_tcp_conn_estabilish_reply (conn
, ip
, tcp
);
235 /* another side close connection */
236 if (tcp
->flags
& 0x01) {
237 DPRINT ("TCP -> fd %d connection closed by remote host\n", conn
->fd
);
238 net_proto_tcp_conn_disconnected (conn
, ip
, tcp
);
244 int net_proto_tcp_read_cache (proto_tcp_conn_t
*conn
, char *data
, unsigned len
)
246 if (!data
|| !conn
|| !len
)
250 conn
->data
= (char *) kmalloc (sizeof (char) * len
);
252 conn
->data
= (char *) krealloc (conn
->data
, (sizeof (char) * (conn
->len
+len
)));
257 memcpy (conn
->data
+conn
->len
, data
, len
);
261 conn
->data
[conn
->len
] = '\0';
266 int net_proto_tcp_read_ok (proto_tcp_conn_t
*conn
, proto_ip_t
*ip_old
, proto_tcp_t
*tcp_old
, unsigned len
)
268 if (!ip_old
|| !tcp_old
|| !conn
)
272 proto_tcp_t
*tcp
= (proto_tcp_t
*) kmalloc (sizeof (proto_tcp_t
));
277 tcp
->port_source
= conn
->port_source
; // increase client port too
278 tcp
->port_dest
= conn
->port_dest
;
280 tcp
->seq
= tcp_old
->ack
;
282 /* this small thing did bad thing when e.g. 10 10 10 fe get to calculation,
283 it returns 10 10 10 08, no 10 10 11 08 */
284 unsigned seq
= swap32 (tcp_old
->seq
);
287 tcp
->ack
= swap32 (seq
);
290 tcp
->data_offset
= 5;
292 tcp
->window
= tcp_old
->window
+ swap16 (64);
295 int ret
= net_proto_tcp_write (conn
->netif
, conn
->ip_dest
, tcp
, 0, 0);
297 /*if (proto_tcp_dup == tcp_old->checksum) {
298 printf ("Duplicated packet :)");
303 conn
->seq
= tcp
->ack
;
304 conn
->ack
= tcp
->seq
;
306 proto_tcp_dup
= tcp_old
->checksum
;
314 int net_proto_tcp_write (netif_t
*eth
, net_ipv4 dest
, proto_tcp_t
*tcp
, char *data
, unsigned len
)
324 unsigned get
= arp_cache_get (dest
, &mac_dest
);
327 arp_send_request (eth
, dest
);
330 /* 100ms for waiting on ARP reply */
332 get
= arp_cache_get (dest
, &mac_dest
);
337 /* TODO: make better waiting for ARP reply */
350 packet_t
*packet
= (packet_t
*) kmalloc (sizeof (packet_t
));
355 memcpy (&packet
->mac_source
, eth
->dev
->dev_addr
, 6);
356 memcpy (&packet
->mac_dest
, mac_dest
, 6);
357 packet
->type
= NET_PACKET_TYPE_IPV4
;
360 proto_ip_t
*ip
= (proto_ip_t
*) kmalloc (sizeof (proto_ip_t
));
365 /* there are some fixed values - yeah it is horrible */
373 ip
->proto
= NET_PROTO_IP_TYPE_TCP
;
374 ip
->ip_source
= eth
->ip
;
377 unsigned l
= (tcp
->data_offset
*4);
379 /* calculate total length of packet (tcp/ip) */
380 ip
->total_len
= swap16 (l
+sizeof (proto_tcp_t
)+len
);
382 char *buf_tcp
= (char *) kmalloc ((len
+l
) * sizeof (char));
387 memcpy (buf_tcp
, (char *) tcp
, l
);
390 memcpy (buf_tcp
+l
, data
, len
);
392 buf_tcp
[l
+len
] = '\0';
394 /* calculate checksum and put it to tcp header */
395 proto_tcp_t
*tcp_
= (proto_tcp_t
*) buf_tcp
;
397 tcp_
->checksum
= checksum16_tcp (eth
->ip
, dest
, buf_tcp
, l
+len
);
399 /* send tcp header+data to ip layer */
400 unsigned ret
= net_proto_ip_send (eth
, packet
, ip
, (char *) buf_tcp
, l
+len
);
409 int net_proto_tcp_write_data (proto_tcp_conn_t
*conn
, char *data
, unsigned len
)
411 if (!conn
|| !len
|| !data
)
414 proto_tcp_t
*tcp
= (proto_tcp_t
*) kmalloc (sizeof (proto_tcp_t
));
419 tcp
->port_source
= conn
->port_source
;
420 tcp
->port_dest
= conn
->port_dest
;
422 proto_tcp_seq
+= swap32 (1);
424 tcp
->seq
= conn
->seq
;
425 tcp
->ack
= conn
->ack
;
428 tcp
->data_offset
= 5;
430 tcp
->window
= swap16 (32768);
433 int ret
= net_proto_tcp_write (conn
->netif
, conn
->ip_dest
, tcp
, data
, len
);
438 conn
->state
= PROTO_TCP_CONN_STATE_WAIT
;
443 int net_proto_tcp_write_data_ok (proto_tcp_conn_t
*conn
, proto_ip_t
*ip_old
, proto_tcp_t
*tcp_old
)
445 if (!ip_old
|| !tcp_old
|| !conn
)
448 /* cross - because we change now sides :) */
449 conn
->seq
= tcp_old
->ack
;
450 conn
->ack
= tcp_old
->seq
;
452 conn
->state
= PROTO_TCP_CONN_STATE_READY
;
457 /* try connect to server */
458 int net_proto_tcp_conn_estabilish (proto_tcp_conn_t
*conn
, netif_t
*eth
, net_ipv4 ip_dest
, net_port port_dest
)
463 proto_tcp_t
*tcp
= (proto_tcp_t
*) kmalloc (sizeof (proto_tcp_t
));
468 tcp
->port_source
= swap16 (proto_tcp_client_port
); // increase client port too
469 tcp
->port_dest
= port_dest
;
471 /* setup new connection */
472 net_proto_tcp_conn_set (conn
, eth
, tcp
->port_source
, ip_dest
, tcp
->port_dest
);
474 tcp
->seq
= conn
->seq
;
475 tcp
->ack
= conn
->ack
;
478 tcp
->data_offset
= 5;
480 tcp
->window
= swap16 (32792);
483 int ret
= net_proto_tcp_write (eth
, ip_dest
, tcp
, 0, 0);
488 net_proto_tcp_conn_del (conn
);
495 int net_proto_tcp_conn_estabilish_reply (proto_tcp_conn_t
*conn
, proto_ip_t
*ip_old
, proto_tcp_t
*tcp_old
)
497 if (!ip_old
|| !tcp_old
|| !conn
)
500 proto_tcp_t
*tcp
= (proto_tcp_t
*) kmalloc (sizeof (proto_tcp_t
));
505 tcp
->port_source
= conn
->port_source
; // increase client port too
506 tcp
->port_dest
= conn
->port_dest
;
508 tcp
->seq
= tcp_old
->ack
;
509 tcp
->ack
= tcp_old
->seq
+ swap32 (1);
512 tcp
->data_offset
= 5;
514 tcp
->window
= tcp_old
->window
+ swap16 (64);
517 int ret
= net_proto_tcp_write (conn
->netif
, conn
->ip_dest
, tcp
, 0, 0);
520 conn
->seq
= tcp
->seq
;
521 conn
->ack
= tcp
->ack
;
522 conn
->state
= PROTO_TCP_CONN_STATE_ESTABILISHED
;
525 DPRINT ("TCP -> fd %ï connected to server succefully\n", conn
->fd
);
532 int net_proto_tcp_conn_disconnected (proto_tcp_conn_t
*conn
, proto_ip_t
*ip_old
, proto_tcp_t
*tcp_old
)
534 if (!ip_old
|| !tcp_old
|| !conn
)
537 proto_tcp_t
*tcp
= (proto_tcp_t
*) kmalloc (sizeof (proto_tcp_t
));
542 tcp
->port_source
= conn
->port_source
; // increase client port too
543 tcp
->port_dest
= conn
->port_dest
;
545 tcp
->seq
= tcp_old
->ack
;
546 tcp
->ack
= tcp_old
->seq
+ swap32 (1);
549 tcp
->data_offset
= 5;
551 tcp
->window
= tcp_old
->window
+ swap16 (64);
554 int ret
= net_proto_tcp_write (conn
->netif
, conn
->ip_dest
, tcp
, 0, 0);
559 conn
->state
= PROTO_TCP_CONN_STATE_CLOSE
; //ret = net_proto_tcp_conn_del (conn);
566 int net_proto_tcp_conn_close (proto_tcp_conn_t
*conn
)
571 proto_tcp_t
*tcp
= (proto_tcp_t
*) kmalloc (sizeof (proto_tcp_t
));
576 tcp
->port_source
= conn
->port_source
; // increase client port too
577 tcp
->port_dest
= conn
->port_dest
;
579 tcp
->seq
= conn
->seq
;
580 tcp
->ack
= conn
->ack
;
583 tcp
->data_offset
= 5;
585 tcp
->window
= swap16 (32832);
588 int ret
= net_proto_tcp_write (conn
->netif
, conn
->ip_dest
, tcp
, 0, 0);
593 conn
->state
= PROTO_TCP_CONN_STATE_CLOSE
;
599 /* Create new TCP connection */
600 int net_proto_tcp_conn_add ()
602 proto_tcp_conn_t
*conn
;
604 /* alloc and init context */
605 conn
= (proto_tcp_conn_t
*) kmalloc (sizeof (proto_tcp_conn_t
));
610 memset (conn
, 0, sizeof (proto_tcp_conn_t
));
614 conn
->fd
= proto_tcp_fd
++;
617 conn
->next
= &proto_tcp_conn_list
;
618 conn
->prev
= proto_tcp_conn_list
.prev
;
619 conn
->prev
->next
= conn
;
620 conn
->next
->prev
= conn
;
625 /* Setup new connection */
626 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
)
631 conn
->ip_source
= eth
->ip
;
632 conn
->ip_dest
= ip_dest
;
634 conn
->port_source
= port_source
;
635 conn
->port_dest
= port_dest
;
637 proto_tcp_seq
+= swap32 (1);
639 conn
->seq
= proto_tcp_seq
;
642 conn
->state
= PROTO_TCP_CONN_STATE_ESTABILISH
;
652 /* Delete existing connection from list */
653 unsigned net_proto_tcp_conn_del (proto_tcp_conn_t
*conn
)
658 conn
->state
= PROTO_TCP_CONN_STATE_DISCONNECTED
;
665 conn
->next
->prev
= conn
->prev
;
666 conn
->prev
->next
= conn
->next
;
673 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
)
675 proto_tcp_conn_t
*conn
= NULL
;
676 for (conn
= proto_tcp_conn_list
.next
; conn
!= &proto_tcp_conn_list
; conn
= conn
->next
) {
677 if (conn
->ip_source
== ip_source
)
678 if (conn
->ip_dest
== ip_dest
&& conn
->port_source
== port_source
679 && conn
->port_dest
== port_dest
)
686 proto_tcp_conn_t
*net_proto_tcp_conn_find (int fd
)
688 proto_tcp_conn_t
*conn
= NULL
;
689 for (conn
= proto_tcp_conn_list
.next
; conn
!= &proto_tcp_conn_list
; conn
= conn
->next
) {
697 /* init of tcp protocol */
698 unsigned init_net_proto_tcp ()
700 proto_tcp_conn_list
.next
= &proto_tcp_conn_list
;
701 proto_tcp_conn_list
.prev
= &proto_tcp_conn_list
;
703 /* base tcp client port, which is used for client's use */
704 proto_tcp_client_port
= 1024;