Cleanup in elf.c with .bss section clean; adm command mounts cdrom instead of floppy...
[ZeXOS.git] / kernel / core / net / udp6.c
blobad9223a534895437e7639c825aa152e9c3f1486a
1 /*
2 * ZeX/OS
3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
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/>.
21 #include <system.h>
22 #include <string.h>
23 #include <dev.h>
24 #include <net/eth.h>
25 #include <net/net.h>
26 #include <net/if.h>
27 #include <net/ip.h>
28 #include <net/packet.h>
29 #include <net/udp.h>
30 #include <net/socket.h>
31 #include <fd.h>
32 #include <errno.h>
35 extern netif_t netif_list;
36 proto_udp6_conn_t proto_udp6_conn_list;
38 /* prototypes */
39 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);
40 int net_proto_udp6_read_cache (proto_udp6_conn_t *conn, char *data, unsigned len);
41 int net_proto_udp6_write (proto_udp6_conn_t *conn, char *data, unsigned len);
42 proto_udp6_conn_t *net_proto_udp6_conn_find (int fd);
43 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);
44 unsigned net_proto_udp6_conn_del (proto_udp6_conn_t *conn);
45 int net_proto_udp6_conn_add ();
47 /** UDPv6 protocol
48 * User-friendly socket functions
50 int net_proto_udp6_socket (fd_t *fd)
52 return net_proto_udp6_conn_add (fd);
55 int net_proto_udp6_connect (int fd, sockaddr_in6 *addr)
57 int ret = -1;
59 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
61 if (!conn)
62 return -1;
64 netif_t *netif;
65 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
66 ret = net_proto_udp6_conn_set (conn, netif, swap16 (netif_port_get ()), addr->sin6_addr, addr->sin6_port);
68 /* TODO: connect timeout */
70 /* blocking mode */
71 if (!(conn->flags & O_NONBLOCK)) {
72 if (!ret)
73 return -1;
74 } else
75 /* non-blocking mode */
76 return -1;
78 ret = 0;
81 return ret;
84 int net_proto_udp6_send (int fd, char *msg, unsigned size)
86 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
88 if (!conn)
89 return -1;
91 int ret = net_proto_udp6_write (conn, msg, size);
93 if (ret) {
94 /* blocking mode */
95 if (!(conn->flags & O_NONBLOCK)) {
97 } else {
98 /* non-blocking mode */
99 /* TODO: ? */
104 return size;
107 int net_proto_udp6_sendto (int fd, char *msg, unsigned size, sockaddr_in6 *to)
109 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
111 if (!conn)
112 return -1;
114 //int ip = conn->ip_dest;
116 /*net_proto_ip_print (conn->ip_dest);
117 kprintf (" | ");
118 net_proto_ip_print (conn->ip_source);*/
120 //conn->ip_source = to->sin6_addr;
122 int ret = net_proto_udp6_write (conn, msg, size);
124 //conn->ip_dest = ip;
126 if (ret) {
127 /* blocking mode */
128 if (!(conn->flags & O_NONBLOCK)) {
130 } else {
131 /* non-blocking mode */
132 /* TODO: ? */
137 return size;
140 extern unsigned long timer_ticks;
141 int net_proto_udp6_recv (int fd, char *msg, unsigned size)
143 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
145 if (!conn)
146 return -3;
148 if (!msg)
149 return -4;
151 int ret = 0;
153 /* blocking mode */
154 if (!(conn->flags & O_NONBLOCK)) {
155 unsigned long stime = timer_ticks;
157 while (!conn->len) {
158 if ((stime+10000) < timer_ticks)
159 return 0;
161 schedule ();
163 } else {
164 if (!conn->len)
165 return 0;
168 if (!conn->data)
169 return -5;
171 if (conn->len >= size)
172 return -2;
174 ret = conn->len;
176 if (conn->len > 0)
177 memcpy (msg, conn->data, conn->len);
179 conn->len = 0;
181 kfree (conn->data);
183 return ret;
186 int net_proto_udp6_recvfrom (int fd, char *msg, unsigned size, sockaddr_in6 *from)
188 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
190 if (!conn)
191 return -3;
193 if (!msg)
194 return -4;
196 int ret = 0;
198 //int ip = conn->ip_dest;
200 memcpy (from->sin6_addr, (void *) conn->ip_dest, sizeof (net_ipv6));
201 //kprintf ("recvfrom -> ip: 0x%x\n", from->sin6_addr);
203 /* blocking mode */
204 if (!(conn->flags & O_NONBLOCK)) {
205 /* TODO: timeout */
206 while (!conn->len)
207 schedule ();
208 } else {
209 if (!conn->len) {
210 //conn->ip_dest = ip;
211 return 0;
215 //conn->ip_dest = ip; // return old ip address back to structure
217 if (!conn->data)
218 return -5;
220 if (conn->len >= size)
221 return -2;
223 ret = conn->len;
225 if (conn->len > 0)
226 memcpy (msg, conn->data, conn->len);
228 conn->len = 0;
230 kfree (conn->data);
232 return ret;
235 int net_proto_udp6_close (int fd)
237 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
239 if (!conn)
240 return -1;
242 int ret = net_proto_udp6_conn_del (conn);
244 return ret;
247 int net_proto_udp6_fcntl (int fd, int cmd, long arg)
249 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
251 if (!conn)
252 return -1;
254 switch (cmd) {
255 case F_GETFL:
256 return conn->flags;
257 case F_SETFL:
258 conn->flags = arg;
259 return 0;
262 return -1;
265 int net_proto_udp6_bind (int fd, sockaddr_in6 *addr, socklen_t len)
267 proto_udp6_conn_t *conn = net_proto_udp6_conn_find (fd);
269 if (!conn)
270 return -1;
272 netif_t *netif;
273 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
274 net_proto_udp6_conn_set (conn, netif, addr->sin6_port, 0, 0);
275 conn->bind = 1;
276 return 0;
279 return -1;
282 /** UDP protocol
283 * hardcore code :P
286 /* handler for received udp datagrams */
287 unsigned net_proto_udp6_handler (packet_t *packet, proto_ipv6_t *ip, char *buf, unsigned len)
289 unsigned char ret;
290 proto_udp_t *udp = (proto_udp_t *) buf;
292 /* First check ip address and ports, that we want this data */
293 proto_udp6_conn_t *conn = net_proto_udp6_conn_check (ip->ip_dest, udp->port_dest, ip->ip_source, udp->port_source, &ret);
295 if (!conn && ret == 0)
296 return 1;
298 if (ret == 1)
299 memcpy (conn->ip_dest, (void *) ip->ip_source, sizeof (net_ipv6));
301 /* HACK: very ugly */
302 conn->port_dest = udp->port_source;
304 /* save data to buffer; +8 because udp packet is 8byte header and then data */
305 int ret2 = net_proto_udp6_read_cache (conn, buf+8, len-8);
307 if (ret2 < 1)
308 return 0;
310 return 1;
313 /* save received data to buffer */
314 int net_proto_udp6_read_cache (proto_udp6_conn_t *conn, char *data, unsigned len)
316 if (!data || !conn || !len)
317 return 0;
319 if (!conn->len)
320 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
321 else
322 conn->data = (char *) krealloc (conn->data, (sizeof (char) * (conn->len+len)));
324 if (!conn->data)
325 return -1;
327 memcpy (conn->data+conn->len, data, len);
329 conn->len += len;
331 //conn->data[conn->len] = '\0';
333 return conn->len;
336 int net_proto_udp6_write (proto_udp6_conn_t *conn, char *data, unsigned len)
338 if (!conn || !len || !data)
339 return 0;
341 mac_addr_t mac_dest;
342 if (!tun6_addr_get ()) {
343 unsigned get = ndp_cache_get (conn->ip_dest, &mac_dest);
345 if (!get) {
346 ndp_send_nbrequest (conn->netif, conn->ip_dest);
348 unsigned i = 0;
349 /* 100ms for waiting on ARP reply */
350 while (i < 100) {
351 get = ndp_cache_get (conn->ip_dest, &mac_dest);
353 if (get)
354 break;
356 /* TODO: make better waiting for ARP reply */
357 timer_wait (1);
359 schedule ();
361 i ++;
364 if (!get)
365 return 0;
367 } else {
368 /* IPv6 tunnel stuff */
369 net_ipv4 tunnel = tun6_addr_get ();
370 unsigned get = arp_cache_get (tunnel, &mac_dest);
372 if (!get) {
373 arp_send_request (conn->netif, tunnel);
375 unsigned i = 0;
376 /* 100ms for waiting on ARP reply */
377 while (i < 100) {
378 get = arp_cache_get (tunnel, &mac_dest);
380 if (get)
381 break;
383 /* TODO: make better waiting for ARP reply */
384 timer_wait (1);
386 schedule ();
388 i ++;
391 if (!get)
392 return 0;
396 /* packet header */
397 packet_t *packet = (packet_t *) kmalloc (sizeof (packet_t));
399 if (!packet)
400 return 0;
402 memcpy (&packet->mac_source, conn->netif->dev->dev_addr, 6);
403 memcpy (&packet->mac_dest, mac_dest, 6);
404 packet->type = NET_PACKET_TYPE_IPV6;
406 /* ip layer */
407 proto_ipv6_t *ip = (proto_ipv6_t *) kmalloc (sizeof (proto_ipv6_t));
409 if (!ip)
410 return 0;
412 /* there are some fixed values - yeah it is horrible */
413 ip->ver = 0x60;
414 ip->tclass = 0x0;
415 ip->flabel = 0x0;
416 ip->pl_len = swap16 (len);
417 ip->nhead = NET_PROTO_IP_TYPE_UDP6;
418 ip->hop = 0xff;
419 memcpy (ip->ip_source, (void *) conn->ip_source, sizeof (net_ipv6));
420 memcpy (ip->ip_dest, (void *) conn->ip_dest, sizeof (net_ipv6));
423 proto_udp_t *udp = (proto_udp_t *) kmalloc (sizeof (proto_udp_t));
425 if (!udp)
426 return 0;
428 udp->port_source = conn->port_source;
429 udp->port_dest = conn->port_dest;
431 udp->len = ip->pl_len;
433 udp->checksum = 0;
436 /* calculate total length of packet (udp/ip) */
439 char *buf_udp = (char *) kmalloc ((9 + len) * sizeof (char));
441 if (!buf_udp)
442 return 0;
444 memcpy (buf_udp, (char *) udp, 8);
445 memcpy (buf_udp+8, data, len);
447 buf_udp[8 + len] = '\0';
449 /* calculate checksum and put it to udp header */
450 proto_udp_t *udp_ = (proto_udp_t *) buf_udp;
451 udp_->checksum = checksum16_ipv6 (conn->ip_source, conn->ip_dest, buf_udp, 8 + len, NET_PROTO_IP_TYPE_UDP6);
453 unsigned ret = 0;
455 /* send udp header+data to ip layer */
456 if (!tun6_addr_get ())
457 ret = net_proto_ipv6_send (conn->netif, packet, ip, (char *) buf_udp, 8 + len);
458 else
459 ret = net_proto_tun6_send (conn->netif, packet, ip, (char *) buf_udp, 8 + len);
461 kfree (buf_udp);
462 kfree (udp);
463 kfree (ip);
464 kfree (packet);
466 return ret;
470 /* Create new UDP connection */
471 int net_proto_udp6_conn_add (fd_t *fd)
473 proto_udp6_conn_t *conn;
475 /* alloc and init context */
476 conn = (proto_udp6_conn_t *) kmalloc (sizeof (proto_udp6_conn_t));
478 if (!conn) {
479 errno_set (ENOMEM);
480 return -1;
483 memset (conn, 0, sizeof (proto_udp6_conn_t));
485 conn->flags = 0;
487 conn->fd = fd->id;
489 /* add into list */
490 conn->next = &proto_udp6_conn_list;
491 conn->prev = proto_udp6_conn_list.prev;
492 conn->prev->next = conn;
493 conn->next->prev = conn;
495 return 0;
498 /* Setup new connection */
499 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)
501 if (!conn || !eth)
502 return 0;
504 memcpy (conn->ip_source, (void *) eth->ipv6, sizeof (net_ipv6));
505 memcpy (conn->ip_dest, (void *) ip_dest, sizeof (net_ipv6));
507 conn->port_source = port_source;
508 conn->port_dest = port_dest;
510 conn->netif = eth;
512 conn->bind = 0;
514 conn->len = 0;
515 conn->data = 0;
517 return 1;
520 /* Delete existing connection from list */
521 unsigned net_proto_udp6_conn_del (proto_udp6_conn_t *conn)
523 if (!conn)
524 return 0;
526 if (conn->len)
527 kfree (conn->data);
529 conn->len = 0;
531 conn->next->prev = conn->prev;
532 conn->prev->next = conn->next;
534 kfree (conn);
536 return 1;
539 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)
541 *ret = 0;
542 proto_udp6_conn_t *conn = NULL;
543 proto_udp6_conn_t *conn_ret = NULL;
545 for (conn = proto_udp6_conn_list.next; conn != &proto_udp6_conn_list; conn = conn->next) {
546 if (conn->ip_source == ip_source && conn->port_source == port_source) {
547 if (conn->ip_dest == ip_dest /*&& conn->port_dest == port_dest*/) {
548 *ret = 2;
549 return conn;
552 *ret = 1;
554 conn_ret = conn;
558 if (*ret == 1)
559 if (!conn_ret->bind) {
560 conn_ret = 0;
562 for (conn = proto_udp6_conn_list.next; conn != &proto_udp6_conn_list; conn = conn->next) {
563 if (conn->bind) {
564 if (conn->ip_source == ip_source && conn->port_source == port_source)
565 conn_ret = conn;
570 return conn_ret;
573 proto_udp6_conn_t *net_proto_udp6_conn_find (int fd)
575 proto_udp6_conn_t *conn = NULL;
576 for (conn = proto_udp6_conn_list.next; conn != &proto_udp6_conn_list; conn = conn->next) {
577 if (conn->fd == fd)
578 return conn;
581 return 0;
584 /* init of udpv6 protocol */
585 unsigned init_net_proto_udp6 ()
587 proto_udp6_conn_list.next = &proto_udp6_conn_list;
588 proto_udp6_conn_list.prev = &proto_udp6_conn_list;
590 return 1;