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/>.
28 #include <net/packet.h>
30 #include <net/socket.h>
35 extern netif_t netif_list
;
36 proto_udp_conn_t proto_udp_conn_list
;
38 static net_port proto_udp_client_port
;
39 static unsigned proto_udp_fd
;
42 proto_udp_conn_t
*net_proto_udp_conn_check (net_ipv4 ip_source
, net_port port_source
, net_ipv4 ip_dest
, net_port port_dest
, unsigned char *ret
);
43 int net_proto_udp_read_cache (proto_udp_conn_t
*conn
, char *data
, unsigned len
);
44 int net_proto_udp_write (proto_udp_conn_t
*conn
, char *data
, unsigned len
);
45 proto_udp_conn_t
*net_proto_udp_conn_find (int fd
);
46 int net_proto_udp_conn_set (proto_udp_conn_t
*conn
, netif_t
*eth
, net_port port_source
, net_ipv4 ip_dest
, net_port port_dest
);
47 unsigned net_proto_udp_conn_del (proto_udp_conn_t
*conn
);
48 int net_proto_udp_conn_add ();
51 * User-friendly socket functions
53 int net_proto_udp_socket (fd_t
*fd
)
55 return net_proto_udp_conn_add (fd
);
58 int net_proto_udp_connect (int fd
, sockaddr_in
*addr
)
62 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
68 for (netif
= netif_list
.next
; netif
!= &netif_list
; netif
= netif
->next
) {
69 ret
= net_proto_udp_conn_set (conn
, netif
, swap16 (proto_udp_client_port
++), addr
->sin_addr
, addr
->sin_port
);
71 /* TODO: connect timeout */
74 if (!(conn
->flags
& O_NONBLOCK
)) {
78 /* non-blocking mode */
87 int net_proto_udp_send (int fd
, char *msg
, unsigned size
)
89 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
94 int ret
= net_proto_udp_write (conn
, msg
, size
);
98 if (!(conn
->flags
& O_NONBLOCK
)) {
101 /* non-blocking mode */
110 int net_proto_udp_sendto (int fd
, char *msg
, unsigned size
, sockaddr_in
*to
)
112 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
117 //int ip = conn->ip_dest;
119 /*net_proto_ip_print (conn->ip_dest);
121 net_proto_ip_print (conn->ip_source);*/
123 //conn->ip_source = to->sin_addr;
125 int ret
= net_proto_udp_write (conn
, msg
, size
);
127 //conn->ip_dest = ip;
131 if (!(conn
->flags
& O_NONBLOCK
)) {
134 /* non-blocking mode */
143 extern unsigned long timer_ticks
;
144 int net_proto_udp_recv (int fd
, char *msg
, unsigned size
)
146 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
157 if (!(conn
->flags
& O_NONBLOCK
)) {
158 unsigned long stime
= timer_ticks
;
161 if ((stime
+10000) < timer_ticks
)
174 if (conn
->len
>= size
)
180 memcpy (msg
, conn
->data
, conn
->len
);
189 int net_proto_udp_recvfrom (int fd
, char *msg
, unsigned size
, sockaddr_in
*from
)
191 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
201 //int ip = conn->ip_dest;
203 from
->sin_addr
= conn
->ip_dest
;
204 //kprintf ("recvfrom -> ip: 0x%x\n", from->sin_addr);
207 if (!(conn
->flags
& O_NONBLOCK
)) {
213 //conn->ip_dest = ip;
218 //conn->ip_dest = ip; // return old ip address back to structure
223 if (conn
->len
>= size
)
229 memcpy (msg
, conn
->data
, conn
->len
);
238 int net_proto_udp_close (int fd
)
240 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
245 int ret
= net_proto_udp_conn_del (conn
);
250 int net_proto_udp_fcntl (int fd
, int cmd
, long arg
)
252 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
268 int net_proto_udp_bind (int fd
, sockaddr_in
*addr
, socklen_t len
)
270 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
276 for (netif
= netif_list
.next
; netif
!= &netif_list
; netif
= netif
->next
) {
277 net_proto_udp_conn_set (conn
, netif
, addr
->sin_port
, 0, 0);
285 /** special functions for kernel purposes **/
286 /* set source ip address as anycast */
287 int net_proto_udp_anycast (int fd
)
289 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
294 conn
->ip_source
= INADDR_ANY
;
299 /* set source port to specified one */
300 int net_proto_udp_port (int fd
, net_port port
)
302 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
307 conn
->port_source
= port
;
316 /* handler for received udp datagrams */
317 unsigned net_proto_udp_handler (packet_t
*packet
, proto_ip_t
*ip
, char *buf
, unsigned len
)
320 proto_udp_t
*udp
= (proto_udp_t
*) buf
;
322 /* First check ip address and ports, that we want this data */
323 proto_udp_conn_t
*conn
= net_proto_udp_conn_check (ip
->ip_dest
, udp
->port_dest
, ip
->ip_source
, udp
->port_source
, &ret
);
325 if (!conn
&& ret
== 0)
329 conn
->ip_dest
= ip
->ip_source
;
331 /* HACK: very ugly */
332 conn
->port_dest
= udp
->port_source
;
334 /* save data to buffer; +8 because udp packet is 8byte header and then data */
335 int ret2
= net_proto_udp_read_cache (conn
, buf
+8, len
-8);
343 /* save received data to buffer */
344 int net_proto_udp_read_cache (proto_udp_conn_t
*conn
, char *data
, unsigned len
)
346 if (!data
|| !conn
|| !len
)
350 conn
->data
= (char *) kmalloc (sizeof (char) * (len
+ 1));
352 conn
->data
= (char *) krealloc (conn
->data
, (sizeof (char) * (conn
->len
+len
)));
357 memcpy (conn
->data
+conn
->len
, data
, len
);
361 //conn->data[conn->len] = '\0';
366 int net_proto_udp_write (proto_udp_conn_t
*conn
, char *data
, unsigned len
)
368 if (!conn
|| !len
|| !data
)
372 unsigned get
= arp_cache_get (conn
->ip_dest
, &mac_dest
);
375 arp_send_request (conn
->netif
, conn
->ip_dest
);
378 /* 100ms for waiting on ARP reply */
380 get
= arp_cache_get (conn
->ip_dest
, &mac_dest
);
385 /* TODO: make better waiting for ARP reply */
398 packet_t
*packet
= (packet_t
*) kmalloc (sizeof (packet_t
));
403 memcpy (&packet
->mac_source
, conn
->netif
->dev
->dev_addr
, 6);
404 memcpy (&packet
->mac_dest
, mac_dest
, 6);
405 packet
->type
= NET_PACKET_TYPE_IPV4
;
408 proto_ip_t
*ip
= (proto_ip_t
*) kmalloc (sizeof (proto_ip_t
));
413 /* there are some fixed values - yeah it is horrible */
421 ip
->proto
= NET_PROTO_IP_TYPE_UDP
;
422 ip
->ip_source
= conn
->ip_source
;
423 ip
->ip_dest
= conn
->ip_dest
;
426 proto_udp_t
*udp
= (proto_udp_t
*) kmalloc (sizeof (proto_udp_t
));
431 udp
->port_source
= conn
->port_source
;
432 udp
->port_dest
= conn
->port_dest
;
434 udp
->len
= swap16 (8 + len
);
439 unsigned l
= (ip
->head_len
* 4);
441 /* calculate total length of packet (udp/ip) */
442 ip
->total_len
= swap16 (l
+ 8 + len
);
444 char *buf_udp
= (char *) kmalloc ((9 + len
) * sizeof (char));
449 memcpy (buf_udp
, (char *) udp
, 8);
450 memcpy (buf_udp
+8, data
, len
);
452 buf_udp
[8 + len
] = '\0';
454 /* calculate checksum and put it to udp header */
455 // FIXME: wrong checksum
456 proto_udp_t
*udp_
= (proto_udp_t
*) buf_udp
;
457 udp_
->checksum
= checksum16_udp (conn
->ip_source
, conn
->ip_dest
, buf_udp
, 8 + len
); // checksum16 (buf_udp, 8 + len);
459 /* send udp header+data to ip layer */
460 unsigned ret
= net_proto_ip_send (conn
->netif
, packet
, ip
, (char *) buf_udp
, 8 + len
);
471 /* Create new UDP connection */
472 int net_proto_udp_conn_add (fd_t
*fd
)
474 proto_udp_conn_t
*conn
;
476 /* alloc and init context */
477 conn
= (proto_udp_conn_t
*) kmalloc (sizeof (proto_udp_conn_t
));
484 memset (conn
, 0, sizeof (proto_udp_conn_t
));
491 conn
->next
= &proto_udp_conn_list
;
492 conn
->prev
= proto_udp_conn_list
.prev
;
493 conn
->prev
->next
= conn
;
494 conn
->next
->prev
= conn
;
499 /* Setup new connection */
500 int net_proto_udp_conn_set (proto_udp_conn_t
*conn
, netif_t
*eth
, net_port port_source
, net_ipv4 ip_dest
, net_port port_dest
)
505 conn
->ip_source
= eth
->ip
;
506 conn
->ip_dest
= ip_dest
;
508 conn
->port_source
= port_source
;
509 conn
->port_dest
= port_dest
;
521 /* Delete existing connection from list */
522 unsigned net_proto_udp_conn_del (proto_udp_conn_t
*conn
)
532 conn
->next
->prev
= conn
->prev
;
533 conn
->prev
->next
= conn
->next
;
540 proto_udp_conn_t
*net_proto_udp_conn_check (net_ipv4 ip_source
, net_port port_source
, net_ipv4 ip_dest
, net_port port_dest
, unsigned char *ret
)
543 proto_udp_conn_t
*conn
= NULL
;
544 proto_udp_conn_t
*conn_ret
= NULL
;
546 if (conn
->ip_dest
!= INADDR_BROADCAST
) {
547 for (conn
= proto_udp_conn_list
.next
; conn
!= &proto_udp_conn_list
; conn
= conn
->next
) {
548 if (conn
->ip_source
== ip_source
&& conn
->port_source
== port_source
) {
549 if (conn
->ip_dest
== ip_dest
) {
559 } else { /* broadcast packet */
560 for (conn
= proto_udp_conn_list
.next
; conn
!= &proto_udp_conn_list
; conn
= conn
->next
) {
561 if (conn
->port_source
== port_source
&& conn
->port_dest
== port_dest
) {
562 conn
->ip_source
= ip_dest
;
563 conn
->ip_dest
= ip_source
;
572 if (!conn_ret
->bind
) {
575 for (conn
= proto_udp_conn_list
.next
; conn
!= &proto_udp_conn_list
; conn
= conn
->next
) {
577 if (conn
->ip_source
== ip_source
&& conn
->port_source
== port_source
)
586 proto_udp_conn_t
*net_proto_udp_conn_find (int fd
)
588 proto_udp_conn_t
*conn
= NULL
;
589 for (conn
= proto_udp_conn_list
.next
; conn
!= &proto_udp_conn_list
; conn
= conn
->next
) {
597 /* init of udp protocol */
598 unsigned init_net_proto_udp ()
600 proto_udp_conn_list
.next
= &proto_udp_conn_list
;
601 proto_udp_conn_list
.prev
= &proto_udp_conn_list
;
603 /* base udp client port, which is used for client's use */
604 proto_udp_client_port
= 1024;