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/>.
29 #include <net/packet.h>
31 #include <net/socket.h>
35 extern netif_t netif_list
;
37 proto_udp_conn_t proto_udp_conn_list
;
39 static proto_ip_t proto_ip_prealloc
;
40 static proto_udp_t proto_udp_prealloc
;
41 static packet_t packet_prealloc
;
42 static char buf_udp_prealloc
[NET_PACKET_MTU
+ sizeof (proto_udp_t
) + 1];
45 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
);
46 int net_proto_udp_read_cache (proto_udp_conn_t
*conn
, char *data
, unsigned len
);
47 int net_proto_udp_write (proto_udp_conn_t
*conn
, char *data
, unsigned len
);
48 proto_udp_conn_t
*net_proto_udp_conn_find (int fd
);
49 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
);
50 unsigned net_proto_udp_conn_del (proto_udp_conn_t
*conn
);
51 int net_proto_udp_conn_add ();
54 * User-friendly socket functions
56 int net_proto_udp_socket (fd_t
*fd
)
58 return net_proto_udp_conn_add (fd
);
61 int net_proto_udp_connect (int fd
, sockaddr_in
*addr
)
65 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
71 for (netif
= netif_list
.next
; netif
!= &netif_list
; netif
= netif
->next
) {
72 ret
= net_proto_udp_conn_set (conn
, netif
, swap16 (netif_port_get ()), addr
->sin_addr
, addr
->sin_port
);
74 /* TODO: connect timeout */
77 if (!(conn
->flags
& O_NONBLOCK
)) {
81 /* non-blocking mode */
90 int net_proto_udp_send (int fd
, char *msg
, unsigned size
)
92 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
99 unsigned mtu_udp
= NET_PACKET_MTU
- sizeof (proto_udp_t
) - sizeof (net_ipv4
) - 16;
102 if (size
> mtu_udp
) {
103 int r
= net_proto_udp_send (fd
, msg
, mtu_udp
);
114 int ret
= net_proto_udp_write (conn
, msg
, size
);
118 if (!(conn
->flags
& O_NONBLOCK
)) {
121 /* non-blocking mode */
130 int net_proto_udp_sendto (int fd
, char *msg
, unsigned size
, sockaddr_in
*to
)
132 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
139 unsigned mtu_udp
= NET_PACKET_MTU
- sizeof (proto_udp_t
) - sizeof (net_ipv4
) - 16;
142 if (size
> mtu_udp
) {
143 int r
= net_proto_udp_sendto (fd
, msg
, mtu_udp
, to
);
154 int ret
= net_proto_udp_write (conn
, msg
, size
);
158 if (!(conn
->flags
& O_NONBLOCK
)) {
161 /* non-blocking mode */
170 extern unsigned long timer_ticks
;
171 int net_proto_udp_recv (int fd
, char *msg
, unsigned size
)
173 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
184 if (!(conn
->flags
& O_NONBLOCK
)) {
185 unsigned long stime
= timer_ticks
;
188 if ((stime
+10000) < timer_ticks
)
201 if (conn
->len
>= size
)
207 memcpy (msg
, conn
->data
, conn
->len
);
216 int net_proto_udp_recvfrom (int fd
, char *msg
, unsigned size
, sockaddr_in
*from
)
218 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
228 //int ip = conn->ip_dest;
230 from
->sin_addr
= conn
->ip_dest
;
231 //kprintf ("recvfrom -> ip: 0x%x\n", from->sin_addr);
234 if (!(conn
->flags
& O_NONBLOCK
)) {
240 //conn->ip_dest = ip;
245 //conn->ip_dest = ip; // return old ip address back to structure
250 if (conn
->len
>= size
)
256 memcpy (msg
, conn
->data
, conn
->len
);
265 int net_proto_udp_close (int fd
)
267 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
272 int ret
= net_proto_udp_conn_del (conn
);
277 int net_proto_udp_fcntl (int fd
, int cmd
, long arg
)
279 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
295 int net_proto_udp_bind (int fd
, sockaddr_in
*addr
, socklen_t len
)
297 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
303 for (netif
= netif_list
.next
; netif
!= &netif_list
; netif
= netif
->next
) {
304 net_proto_udp_conn_set (conn
, netif
, addr
->sin_port
, 0, 0);
312 /** special functions for kernel purposes **/
313 /* set source ip address as anycast */
314 int net_proto_udp_anycast (int fd
)
316 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
321 conn
->ip_source
= INADDR_ANY
;
326 /* set source port to specified one */
327 int net_proto_udp_port (int fd
, net_port port
)
329 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
334 conn
->port_source
= port
;
339 int net_proto_udp_select (int readfd
, int writefd
, int exceptfd
)
350 proto_udp_conn_t
*conn
= net_proto_udp_conn_find (fd
);
355 /* New incoming connection */
356 if (conn
->state
== PROTO_UDP_CONN_STATE_NEW
) {
361 /* Are some data available ? */
372 /* handler for received udp datagrams */
373 unsigned net_proto_udp_handler (packet_t
*packet
, proto_ip_t
*ip
, char *buf
, unsigned len
)
376 proto_udp_t
*udp
= (proto_udp_t
*) buf
;
378 /* check ip address and ports first */
379 proto_udp_conn_t
*conn
= net_proto_udp_conn_check (ip
->ip_dest
, udp
->port_dest
, ip
->ip_source
, udp
->port_source
, &ret
);
381 if (!conn
|| ret
== 0)
385 conn
->ip_dest
= ip
->ip_source
;
387 /* HACK: very ugly */
388 conn
->port_dest
= udp
->port_source
;
390 unsigned short l
= htons (udp
->len
);
395 /* save data to buffer; +8 because udp packet contain 8byte header and than data */
396 int ret2
= net_proto_udp_read_cache (conn
, buf
+8, l
-8);
404 /* save received data to buffer */
405 int net_proto_udp_read_cache (proto_udp_conn_t
*conn
, char *data
, unsigned len
)
407 if (!data
|| !conn
|| !len
)
411 conn
->data
= (char *) kmalloc (sizeof (char) * (len
+ 1));
413 conn
->data
= (char *) krealloc (conn
->data
, (sizeof (char) * (conn
->len
+len
)));
418 memcpy (conn
->data
+conn
->len
, data
, len
);
422 //conn->data[conn->len] = '\0';
427 int net_proto_udp_write (proto_udp_conn_t
*conn
, char *data
, unsigned len
)
429 if (!conn
|| !len
|| !data
)
433 unsigned get
= arp_cache_get (conn
->ip_dest
, &mac_dest
);
436 arp_send_request (conn
->netif
, conn
->ip_dest
);
439 /* 100ms for waiting on ARP reply */
441 get
= arp_cache_get (conn
->ip_dest
, &mac_dest
);
446 /* TODO: make better waiting for ARP reply */
459 packet_t
*packet
= (packet_t
*) &packet_prealloc
;
464 memcpy (&packet
->mac_source
, conn
->netif
->dev
->dev_addr
, 6);
465 memcpy (&packet
->mac_dest
, mac_dest
, 6);
466 packet
->type
= NET_PACKET_TYPE_IPV4
;
469 proto_ip_t
*ip
= (proto_ip_t
*) &proto_ip_prealloc
;
474 /* there are some fixed values - yeah it is horrible */
482 ip
->proto
= NET_PROTO_IP_TYPE_UDP
;
483 ip
->ip_source
= conn
->ip_source
;
484 ip
->ip_dest
= conn
->ip_dest
;
487 proto_udp_t
*udp
= (proto_udp_t
*) &proto_udp_prealloc
;
492 udp
->port_source
= conn
->port_source
;
493 udp
->port_dest
= conn
->port_dest
;
494 udp
->len
= swap16 (8 + len
);
497 unsigned l
= (ip
->head_len
* 4);
499 /* calculate total length of packet (udp/ip) */
500 ip
->total_len
= swap16 (l
+ 8 + len
);
502 if ((len
+ 8) > (NET_PACKET_MTU
+ sizeof (proto_udp_t
) + 1)) {
503 DPRINT (DBG_NET
| DBG_SOCKET
| DBG_UDP
, "UDP -> data lenght is exceed: %d/%d bytes", len
+8, NET_PACKET_MTU
+ sizeof (proto_udp_t
) + 1);
507 char *buf_udp
= (char *) &buf_udp_prealloc
;
512 memcpy (buf_udp
, (char *) udp
, 8);
513 memcpy (buf_udp
+8, data
, len
);
515 buf_udp
[8 + len
] = '\0';
517 /* calculate checksum and put it to udp header */
518 // FIXME: wrong checksum
519 proto_udp_t
*udp_
= (proto_udp_t
*) buf_udp
;
520 udp_
->checksum
= checksum16_udp (conn
->ip_source
, conn
->ip_dest
, buf_udp
, 8 + len
); // checksum16 (buf_udp, 8 + len);
522 /* send udp header+data to ip layer */
523 unsigned ret
= net_proto_ip_send (conn
->netif
, packet
, ip
, (char *) buf_udp
, 8 + len
);
529 /* Create new UDP connection */
530 int net_proto_udp_conn_add (fd_t
*fd
)
532 proto_udp_conn_t
*conn
;
534 /* alloc and init context */
535 conn
= (proto_udp_conn_t
*) kmalloc (sizeof (proto_udp_conn_t
));
542 memset (conn
, 0, sizeof (proto_udp_conn_t
));
549 conn
->next
= &proto_udp_conn_list
;
550 conn
->prev
= proto_udp_conn_list
.prev
;
551 conn
->prev
->next
= conn
;
552 conn
->next
->prev
= conn
;
557 /* Setup new connection */
558 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
)
563 conn
->ip_source
= eth
->ip
;
564 conn
->ip_dest
= ip_dest
;
566 conn
->port_source
= port_source
;
567 conn
->port_dest
= port_dest
;
580 /* Delete existing connection from list */
581 unsigned net_proto_udp_conn_del (proto_udp_conn_t
*conn
)
591 conn
->next
->prev
= conn
->prev
;
592 conn
->prev
->next
= conn
->next
;
599 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
)
602 proto_udp_conn_t
*conn
= NULL
;
603 proto_udp_conn_t
*conn_ret
= NULL
;
605 if (ip_source
!= INADDR_BROADCAST
) {
606 for (conn
= proto_udp_conn_list
.next
; conn
!= &proto_udp_conn_list
; conn
= conn
->next
) {
607 if (conn
->ip_source
== ip_source
&& conn
->port_source
== port_source
) {
608 if (conn
->ip_dest
== ip_dest
) {
612 *ret = 1;printf ("OO11122\n");
613 conn->state = PROTO_UDP_CONN_STATE_NEW;
624 } else { /* broadcast packet */
625 for (conn
= proto_udp_conn_list
.next
; conn
!= &proto_udp_conn_list
; conn
= conn
->next
) {
626 if (conn
->port_source
== port_source
&& conn
->port_dest
== port_dest
) {
627 conn
->ip_source
= ip_dest
;
628 conn
->ip_dest
= ip_source
;
637 //if (!conn_ret->bind) {
640 for (conn
= proto_udp_conn_list
.next
; conn
!= &proto_udp_conn_list
; conn
= conn
->next
) {
642 if (conn
->ip_source
== ip_source
&& conn
->port_source
== port_source
) {
644 conn
->state
= PROTO_UDP_CONN_STATE_NEW
;
653 proto_udp_conn_t
*net_proto_udp_conn_find (int fd
)
655 proto_udp_conn_t
*conn
= NULL
;
656 for (conn
= proto_udp_conn_list
.next
; conn
!= &proto_udp_conn_list
; conn
= conn
->next
) {
664 /* init of udp protocol */
665 unsigned init_net_proto_udp ()
667 proto_udp_conn_list
.next
= &proto_udp_conn_list
;
668 proto_udp_conn_list
.prev
= &proto_udp_conn_list
;