Fixed ZDE build - missing header file
[ZeXOS.git] / kernel / core / net / udp.c
bloba86404117ccb015e3ce694c28796036f122ebc12
1 /*
2 * ZeX/OS
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/>.
22 #include <system.h>
23 #include <string.h>
24 #include <dev.h>
25 #include <net/eth.h>
26 #include <net/net.h>
27 #include <net/if.h>
28 #include <net/ip.h>
29 #include <net/packet.h>
30 #include <net/udp.h>
31 #include <net/socket.h>
32 #include <fd.h>
33 #include <errno.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];
44 /* prototypes */
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 ();
53 /** UDP protocol
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)
63 int ret = -1;
65 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
67 if (!conn)
68 return -1;
70 netif_t *netif;
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 */
76 /* blocking mode */
77 if (!(conn->flags & O_NONBLOCK)) {
78 if (!ret)
79 return -1;
80 } else
81 /* non-blocking mode */
82 return -1;
84 ret = 0;
87 return ret;
90 int net_proto_udp_send (int fd, char *msg, unsigned size)
92 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
94 if (!conn)
95 return -1;
97 unsigned len = size;
99 unsigned mtu_udp = NET_PACKET_MTU - sizeof (proto_udp_t) - sizeof (net_ipv4) - 16;
101 check:
102 if (size > mtu_udp) {
103 int r = net_proto_udp_send (fd, msg, mtu_udp);
105 if (r <= 0)
106 return r;
108 msg += mtu_udp;
109 size -= mtu_udp;
111 goto check;
114 int ret = net_proto_udp_write (conn, msg, size);
116 if (ret) {
117 /* blocking mode */
118 if (!(conn->flags & O_NONBLOCK)) {
120 } else {
121 /* non-blocking mode */
122 /* TODO: ? */
127 return len;
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);
134 if (!conn)
135 return -1;
137 unsigned len = size;
139 unsigned mtu_udp = NET_PACKET_MTU - sizeof (proto_udp_t) - sizeof (net_ipv4) - 16;
141 check:
142 if (size > mtu_udp) {
143 int r = net_proto_udp_sendto (fd, msg, mtu_udp, to);
145 if (r <= 0)
146 return r;
148 msg += mtu_udp;
149 size -= mtu_udp;
151 goto check;
154 int ret = net_proto_udp_write (conn, msg, size);
156 if (ret) {
157 /* blocking mode */
158 if (!(conn->flags & O_NONBLOCK)) {
160 } else {
161 /* non-blocking mode */
162 /* TODO: ? */
167 return len;
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);
175 if (!conn)
176 return -3;
178 if (!msg)
179 return -4;
181 int ret = 0;
183 /* blocking mode */
184 if (!(conn->flags & O_NONBLOCK)) {
185 unsigned long stime = timer_ticks;
187 while (!conn->len) {
188 if ((stime+10000) < timer_ticks)
189 return 0;
191 schedule ();
193 } else {
194 if (!conn->len)
195 return 0;
198 if (!conn->data)
199 return -5;
201 if (conn->len >= size)
202 return -2;
204 ret = conn->len;
206 if (conn->len > 0)
207 memcpy (msg, conn->data, conn->len);
209 conn->len = 0;
211 kfree (conn->data);
213 return ret;
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);
220 if (!conn)
221 return -3;
223 if (!msg)
224 return -4;
226 int ret = 0;
228 //int ip = conn->ip_dest;
230 from->sin_addr = conn->ip_dest;
231 //kprintf ("recvfrom -> ip: 0x%x\n", from->sin_addr);
233 /* blocking mode */
234 if (!(conn->flags & O_NONBLOCK)) {
235 /* TODO: timeout */
236 while (!conn->len)
237 schedule ();
238 } else {
239 if (!conn->len) {
240 //conn->ip_dest = ip;
241 return 0;
245 //conn->ip_dest = ip; // return old ip address back to structure
247 if (!conn->data)
248 return -5;
250 if (conn->len >= size)
251 return -2;
253 ret = conn->len;
255 if (conn->len > 0)
256 memcpy (msg, conn->data, conn->len);
258 conn->len = 0;
260 kfree (conn->data);
262 return ret;
265 int net_proto_udp_close (int fd)
267 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
269 if (!conn)
270 return -1;
272 int ret = net_proto_udp_conn_del (conn);
274 return ret;
277 int net_proto_udp_fcntl (int fd, int cmd, long arg)
279 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
281 if (!conn)
282 return -1;
284 switch (cmd) {
285 case F_GETFL:
286 return conn->flags;
287 case F_SETFL:
288 conn->flags = arg;
289 return 0;
292 return -1;
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);
299 if (!conn)
300 return -1;
302 netif_t *netif;
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);
305 conn->bind = 1;
306 return 0;
309 return -1;
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);
318 if (!conn)
319 return -1;
321 conn->ip_source = INADDR_ANY;
323 return 0;
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);
331 if (!conn)
332 return -1;
334 conn->port_source = port;
336 return 0;
339 int net_proto_udp_select (int readfd, int writefd, int exceptfd)
341 int fd = -1;
343 if (readfd)
344 fd = readfd;
345 else if (writefd)
346 fd = writefd;
347 else if (exceptfd)
348 fd = exceptfd;
350 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
352 if (!conn)
353 return -1;
355 /* New incoming connection */
356 if (conn->state == PROTO_UDP_CONN_STATE_NEW) {
357 conn->state = 0;
358 return 1;
361 /* Are some data available ? */
362 if (conn->len > 0)
363 return 1;
365 return 0;
368 /** UDP protocol
369 * hardcore code :P
372 /* handler for received udp datagrams */
373 unsigned net_proto_udp_handler (packet_t *packet, proto_ip_t *ip, char *buf, unsigned len)
375 unsigned char ret;
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)
382 return 1;
384 if (ret == 1)
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);
392 if (l < 1)
393 return 0;
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);
398 if (ret2 < 1)
399 return 0;
401 return 1;
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)
408 return 0;
410 if (!conn->len)
411 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
412 else
413 conn->data = (char *) krealloc (conn->data, (sizeof (char) * (conn->len+len)));
415 if (!conn->data)
416 return -1;
418 memcpy (conn->data+conn->len, data, len);
420 conn->len += len;
422 //conn->data[conn->len] = '\0';
424 return conn->len;
427 int net_proto_udp_write (proto_udp_conn_t *conn, char *data, unsigned len)
429 if (!conn || !len || !data)
430 return 0;
432 mac_addr_t mac_dest;
433 unsigned get = arp_cache_get (conn->ip_dest, &mac_dest);
435 if (!get) {
436 arp_send_request (conn->netif, conn->ip_dest);
438 unsigned i = 0;
439 /* 100ms for waiting on ARP reply */
440 while (i < 100) {
441 get = arp_cache_get (conn->ip_dest, &mac_dest);
443 if (get)
444 break;
446 /* TODO: make better waiting for ARP reply */
447 timer_wait (1);
449 schedule ();
451 i ++;
454 if (!get)
455 return 0;
458 /* packet header */
459 packet_t *packet = (packet_t *) &packet_prealloc;
461 if (!packet)
462 return 0;
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;
468 /* ip layer */
469 proto_ip_t *ip = (proto_ip_t *) &proto_ip_prealloc;
471 if (!ip)
472 return 0;
474 /* there are some fixed values - yeah it is horrible */
475 ip->ver = 4;
476 ip->head_len = 5;
478 ip->flags = 0;
479 ip->frag = 0;
480 ip->ttl = 64;
481 ip->checksum = 0;
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;
489 if (!udp)
490 return 0;
492 udp->port_source = conn->port_source;
493 udp->port_dest = conn->port_dest;
494 udp->len = swap16 (8 + len);
495 udp->checksum = 0;
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);
504 return 0;
507 char *buf_udp = (char *) &buf_udp_prealloc;
509 if (!buf_udp)
510 return 0;
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);
525 return ret;
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));
537 if (!conn) {
538 errno_set (ENOMEM);
539 return -1;
542 memset (conn, 0, sizeof (proto_udp_conn_t));
544 conn->flags = 0;
546 conn->fd = fd->id;
548 /* add into list */
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;
554 return 0;
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)
560 if (!conn || !eth)
561 return 0;
563 conn->ip_source = eth->ip;
564 conn->ip_dest = ip_dest;
566 conn->port_source = port_source;
567 conn->port_dest = port_dest;
569 conn->netif = eth;
571 conn->bind = 0;
572 conn->state = 0;
574 conn->len = 0;
575 conn->data = 0;
577 return 1;
580 /* Delete existing connection from list */
581 unsigned net_proto_udp_conn_del (proto_udp_conn_t *conn)
583 if (!conn)
584 return 0;
586 if (conn->len)
587 kfree (conn->data);
589 conn->len = 0;
591 conn->next->prev = conn->prev;
592 conn->prev->next = conn->next;
594 kfree (conn);
596 return 1;
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)
601 *ret = 0;
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) {
609 *ret = 2;
611 /*if (conn->bind) {
612 *ret = 1;printf ("OO11122\n");
613 conn->state = PROTO_UDP_CONN_STATE_NEW;
616 return conn;
619 *ret = 1;
621 conn_ret = conn;
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;
630 *ret = 2;
631 return conn;
636 if (*ret == 1) {
637 //if (!conn_ret->bind) {
638 conn_ret = 0;
640 for (conn = proto_udp_conn_list.next; conn != &proto_udp_conn_list; conn = conn->next) {
641 if (conn->bind) {
642 if (conn->ip_source == ip_source && conn->port_source == port_source) {
643 conn_ret = conn;
644 conn->state = PROTO_UDP_CONN_STATE_NEW;
650 return conn_ret;
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) {
657 if (conn->fd == fd)
658 return conn;
661 return 0;
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;
670 return 1;