Fixed ZDE build - missing header file
[ZeXOS.git] / kernel / core / net / udp6.c
blobf935e4783113ab0c4b18a76a9f5fee9aa8fb3746
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_udp6_conn_t proto_udp6_conn_list;
39 static proto_ipv6_t proto_ipv6_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_udp6_conn_t *net_proto_udp6_conn_check (net_ipv6 ip_source, net_port port_source, net_ipv6 ip_dest, net_port port_dest, unsigned char *ret);
46 int net_proto_udp6_read_cache (proto_udp6_conn_t *conn, char *data, unsigned len);
47 int net_proto_udp6_write (proto_udp6_conn_t *conn, char *data, unsigned len);
48 proto_udp6_conn_t *net_proto_udp6_conn_find (int fd);
49 int net_proto_udp6_conn_set (proto_udp6_conn_t *conn, netif_t *eth, net_port port_source, net_ipv6 ip_dest, net_port port_dest);
50 unsigned net_proto_udp6_conn_del (proto_udp6_conn_t *conn);
51 int net_proto_udp6_conn_add ();
53 /** UDPv6 protocol
54 * User-friendly socket functions
56 int net_proto_udp6_socket (fd_t *fd)
58 return net_proto_udp6_conn_add (fd);
61 int net_proto_udp6_connect (int fd, sockaddr_in6 *addr)
63 int ret = -1;
65 proto_udp6_conn_t *conn = net_proto_udp6_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_udp6_conn_set (conn, netif, swap16 (netif_port_get ()), addr->sin6_addr, addr->sin6_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_udp6_send (int fd, char *msg, unsigned size)
92 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
94 if (!conn)
95 return -1;
97 int ret = net_proto_udp6_write (conn, msg, size);
99 if (ret) {
100 /* blocking mode */
101 if (!(conn->flags & O_NONBLOCK)) {
103 } else {
104 /* non-blocking mode */
105 /* TODO: ? */
110 return size;
113 int net_proto_udp6_sendto (int fd, char *msg, unsigned size, sockaddr_in6 *to)
115 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
117 if (!conn)
118 return -1;
120 unsigned len = size;
122 unsigned mtu_udp = NET_PACKET_MTU - sizeof (proto_udp_t) - sizeof (net_ipv6) - 16;
124 check:
125 if (size > mtu_udp) {
126 int r = net_proto_udp6_sendto (fd, msg, mtu_udp, to);
128 if (r <= 0)
129 return r;
131 msg += mtu_udp;
132 size -= mtu_udp;
134 goto check;
137 int ret = net_proto_udp6_write (conn, msg, size);
139 if (ret) {
140 /* blocking mode */
141 if (!(conn->flags & O_NONBLOCK)) {
143 } else {
144 /* non-blocking mode */
145 /* TODO: ? */
150 return size;
153 extern unsigned long timer_ticks;
154 int net_proto_udp6_recv (int fd, char *msg, unsigned size)
156 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
158 if (!conn)
159 return -3;
161 if (!msg)
162 return -4;
164 int ret = 0;
166 /* blocking mode */
167 if (!(conn->flags & O_NONBLOCK)) {
168 unsigned long stime = timer_ticks;
170 while (!conn->len) {
171 if ((stime+10000) < timer_ticks)
172 return 0;
174 schedule ();
176 } else {
177 if (!conn->len)
178 return 0;
181 if (!conn->data)
182 return -5;
184 if (conn->len >= size)
185 return -2;
187 ret = conn->len;
189 if (conn->len > 0)
190 memcpy (msg, conn->data, conn->len);
192 conn->len = 0;
194 kfree (conn->data);
196 return ret;
199 int net_proto_udp6_recvfrom (int fd, char *msg, unsigned size, sockaddr_in6 *from)
201 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
203 if (!conn)
204 return -3;
206 if (!msg)
207 return -4;
209 int ret = 0;
211 //int ip = conn->ip_dest;
213 memcpy (from->sin6_addr, (void *) conn->ip_dest, sizeof (net_ipv6));
214 //kprintf ("recvfrom -> ip: 0x%x\n", from->sin6_addr);
216 /* blocking mode */
217 if (!(conn->flags & O_NONBLOCK)) {
218 /* TODO: timeout */
219 while (!conn->len)
220 schedule ();
221 } else {
222 if (!conn->len) {
223 //conn->ip_dest = ip;
224 return 0;
228 //conn->ip_dest = ip; // return old ip address back to structure
230 if (!conn->data)
231 return -5;
233 if (conn->len >= size)
234 return -2;
236 ret = conn->len;
238 if (conn->len > 0)
239 memcpy (msg, conn->data, conn->len);
241 conn->len = 0;
243 kfree (conn->data);
245 return ret;
248 int net_proto_udp6_close (int fd)
250 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
252 if (!conn)
253 return -1;
255 int ret = net_proto_udp6_conn_del (conn);
257 return ret;
260 int net_proto_udp6_fcntl (int fd, int cmd, long arg)
262 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
264 if (!conn)
265 return -1;
267 switch (cmd) {
268 case F_GETFL:
269 return conn->flags;
270 case F_SETFL:
271 conn->flags = arg;
272 return 0;
275 return -1;
278 int net_proto_udp6_bind (int fd, sockaddr_in6 *addr, socklen_t len)
280 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
282 if (!conn)
283 return -1;
285 netif_t *netif;
286 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
287 net_proto_udp6_conn_set (conn, netif, addr->sin6_port, 0, 0);
288 conn->bind = 1;
289 return 0;
292 return -1;
295 int net_proto_udp6_select (int readfd, int writefd, int exceptfd)
297 int fd = -1;
299 if (readfd)
300 fd = readfd;
301 else if (writefd)
302 fd = writefd;
303 else if (exceptfd)
304 fd = exceptfd;
306 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
308 if (!conn)
309 return -1;
311 /* Are some data available ? */
312 if (conn->len)
313 return 1;
315 return 0;
319 /** UDP protocol
320 * hardcore code :P
323 /* handler for received udp datagrams */
324 unsigned net_proto_udp6_handler (packet_t *packet, proto_ipv6_t *ip, char *buf, unsigned len)
326 unsigned char ret;
327 proto_udp_t *udp = (proto_udp_t *) buf;
329 /* First check ip address and ports, that we want this data */
330 proto_udp6_conn_t *conn = net_proto_udp6_conn_check (ip->ip_dest, udp->port_dest, ip->ip_source, udp->port_source, &ret);
332 if (!conn && ret == 0)
333 return 1;
335 if (ret == 1)
336 memcpy (conn->ip_dest, (void *) ip->ip_source, sizeof (net_ipv6));
338 /* HACK: very ugly */
339 conn->port_dest = udp->port_source;
341 /* save data to buffer; +8 because udp packet is 8byte header and then data */
342 int ret2 = net_proto_udp6_read_cache (conn, buf+8, len-8);
344 if (ret2 < 1)
345 return 0;
347 return 1;
350 /* save received data to buffer */
351 int net_proto_udp6_read_cache (proto_udp6_conn_t *conn, char *data, unsigned len)
353 if (!data || !conn || !len)
354 return 0;
356 if (!conn->len)
357 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
358 else
359 conn->data = (char *) krealloc (conn->data, (sizeof (char) * (conn->len+len)));
361 if (!conn->data)
362 return -1;
364 memcpy (conn->data+conn->len, data, len);
366 conn->len += len;
368 //conn->data[conn->len] = '\0';
370 return conn->len;
373 int net_proto_udp6_write (proto_udp6_conn_t *conn, char *data, unsigned len)
375 if (!conn || !len || !data)
376 return 0;
378 mac_addr_t mac_dest;
379 if (!tun6_addr_get ()) {
380 unsigned get = ndp_cache_get (conn->ip_dest, &mac_dest);
382 if (!get) {
383 ndp_send_nbrequest (conn->netif, conn->ip_dest);
385 unsigned i = 0;
386 /* 100ms for waiting on ARP reply */
387 while (i < 100) {
388 get = ndp_cache_get (conn->ip_dest, &mac_dest);
390 if (get)
391 break;
393 /* TODO: make better waiting for ARP reply */
394 timer_wait (1);
396 schedule ();
398 i ++;
401 if (!get)
402 return 0;
404 } else {
405 /* IPv6 tunnel stuff */
406 net_ipv4 tunnel = tun6_addr_get ();
407 unsigned get = arp_cache_get (tunnel, &mac_dest);
409 if (!get) {
410 arp_send_request (conn->netif, tunnel);
412 unsigned i = 0;
413 /* 100ms for waiting on ARP reply */
414 while (i < 100) {
415 get = arp_cache_get (tunnel, &mac_dest);
417 if (get)
418 break;
420 /* TODO: make better waiting for ARP reply */
421 timer_wait (1);
423 schedule ();
425 i ++;
428 if (!get)
429 return 0;
433 /* packet header */
434 packet_t *packet = (packet_t *) &packet_prealloc;
436 if (!packet)
437 return 0;
439 memcpy (&packet->mac_source, conn->netif->dev->dev_addr, 6);
440 memcpy (&packet->mac_dest, mac_dest, 6);
441 packet->type = NET_PACKET_TYPE_IPV6;
443 /* ip layer */
444 proto_ipv6_t *ip = (proto_ipv6_t *) &proto_ipv6_prealloc;
446 if (!ip)
447 return 0;
449 /* there are some fixed values - yeah it is horrible */
450 ip->ver = 0x60;
451 ip->tclass = 0x0;
452 ip->flabel = 0x0;
453 ip->pl_len = swap16 (len);
454 ip->nhead = NET_PROTO_IP_TYPE_UDP6;
455 ip->hop = 0xff;
456 memcpy (ip->ip_source, (void *) conn->ip_source, sizeof (net_ipv6));
457 memcpy (ip->ip_dest, (void *) conn->ip_dest, sizeof (net_ipv6));
460 proto_udp_t *udp = (proto_udp_t *) &proto_udp_prealloc;
462 if (!udp)
463 return 0;
465 udp->port_source = conn->port_source;
466 udp->port_dest = conn->port_dest;
467 udp->len = ip->pl_len;
468 udp->checksum = 0;
470 if ((len + 8) > (NET_PACKET_MTU + sizeof (proto_udp_t) + 1)) {
471 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);
472 return 0;
475 char *buf_udp = (char *) &buf_udp_prealloc;
477 if (!buf_udp)
478 return 0;
480 memcpy (buf_udp, (char *) udp, 8);
481 memcpy (buf_udp+8, data, len);
483 buf_udp[8 + len] = '\0';
485 /* calculate checksum and put it to udp header */
486 proto_udp_t *udp_ = (proto_udp_t *) buf_udp;
487 udp_->checksum = checksum16_ipv6 (conn->ip_source, conn->ip_dest, buf_udp, 8 + len, NET_PROTO_IP_TYPE_UDP6);
489 unsigned ret = 0;
491 /* send udp header+data to ip layer */
492 if (!tun6_addr_get ())
493 ret = net_proto_ipv6_send (conn->netif, packet, ip, (char *) buf_udp, 8 + len);
494 else
495 ret = net_proto_tun6_send (conn->netif, packet, ip, (char *) buf_udp, 8 + len);
497 return ret;
501 /* Create new UDP connection */
502 int net_proto_udp6_conn_add (fd_t *fd)
504 proto_udp6_conn_t *conn;
506 /* alloc and init context */
507 conn = (proto_udp6_conn_t *) kmalloc (sizeof (proto_udp6_conn_t));
509 if (!conn) {
510 errno_set (ENOMEM);
511 return -1;
514 memset (conn, 0, sizeof (proto_udp6_conn_t));
516 conn->flags = 0;
518 conn->fd = fd->id;
520 /* add into list */
521 conn->next = &proto_udp6_conn_list;
522 conn->prev = proto_udp6_conn_list.prev;
523 conn->prev->next = conn;
524 conn->next->prev = conn;
526 return 0;
529 /* Setup new connection */
530 int net_proto_udp6_conn_set (proto_udp6_conn_t *conn, netif_t *eth, net_port port_source, net_ipv6 ip_dest, net_port port_dest)
532 if (!conn || !eth)
533 return 0;
535 memcpy (conn->ip_source, (void *) eth->ipv6, sizeof (net_ipv6));
536 memcpy (conn->ip_dest, (void *) ip_dest, sizeof (net_ipv6));
538 conn->port_source = port_source;
539 conn->port_dest = port_dest;
541 conn->netif = eth;
543 conn->bind = 0;
545 conn->len = 0;
546 conn->data = 0;
548 return 1;
551 /* Delete existing connection from list */
552 unsigned net_proto_udp6_conn_del (proto_udp6_conn_t *conn)
554 if (!conn)
555 return 0;
557 if (conn->len)
558 kfree (conn->data);
560 conn->len = 0;
562 conn->next->prev = conn->prev;
563 conn->prev->next = conn->next;
565 kfree (conn);
567 return 1;
570 proto_udp6_conn_t *net_proto_udp6_conn_check (net_ipv6 ip_source, net_port port_source, net_ipv6 ip_dest, net_port port_dest, unsigned char *ret)
572 *ret = 0;
573 proto_udp6_conn_t *conn = NULL;
574 proto_udp6_conn_t *conn_ret = NULL;
576 for (conn = proto_udp6_conn_list.next; conn != &proto_udp6_conn_list; conn = conn->next) {
577 if (conn->ip_source == ip_source && conn->port_source == port_source) {
578 if (conn->ip_dest == ip_dest /*&& conn->port_dest == port_dest*/) {
579 *ret = 2;
580 return conn;
583 *ret = 1;
585 conn_ret = conn;
589 if (*ret == 1)
590 if (!conn_ret->bind) {
591 conn_ret = 0;
593 for (conn = proto_udp6_conn_list.next; conn != &proto_udp6_conn_list; conn = conn->next) {
594 if (conn->bind) {
595 if (conn->ip_source == ip_source && conn->port_source == port_source)
596 conn_ret = conn;
601 return conn_ret;
604 proto_udp6_conn_t *net_proto_udp6_conn_find (int fd)
606 proto_udp6_conn_t *conn = NULL;
607 for (conn = proto_udp6_conn_list.next; conn != &proto_udp6_conn_list; conn = conn->next) {
608 if (conn->fd == fd)
609 return conn;
612 return 0;
615 /* init of udpv6 protocol */
616 unsigned init_net_proto_udp6 ()
618 proto_udp6_conn_list.next = &proto_udp6_conn_list;
619 proto_udp6_conn_list.prev = &proto_udp6_conn_list;
621 return 1;