New version 0.6.6: app edit was improved; app nc was improved + code cleanup; app...
[ZeXOS.git] / kernel / core / net / udp.c
blob77b3212706ae63d2b60f20af374fe916e318dbbf
1 /*
2 * ZeX/OS
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/>.
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>
34 extern netif_t netif_list;
35 proto_udp_conn_t proto_udp_conn_list;
37 /* prototypes */
38 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);
39 int net_proto_udp_read_cache (proto_udp_conn_t *conn, char *data, unsigned len);
40 int net_proto_udp_write (proto_udp_conn_t *conn, char *data, unsigned len);
41 proto_udp_conn_t *net_proto_udp_conn_find (int fd);
42 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);
43 unsigned net_proto_udp_conn_del (proto_udp_conn_t *conn);
44 int net_proto_udp_conn_add ();
46 /** UDP protocol
47 * User-friendly socket functions
49 int net_proto_udp_socket (fd_t *fd)
51 return net_proto_udp_conn_add (fd);
54 int net_proto_udp_connect (int fd, sockaddr_in *addr)
56 int ret = -1;
58 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
60 if (!conn)
61 return -1;
63 netif_t *netif;
64 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
65 ret = net_proto_udp_conn_set (conn, netif, swap16 (netif_port_get ()), addr->sin_addr, addr->sin_port);
67 /* TODO: connect timeout */
69 /* blocking mode */
70 if (!(conn->flags & O_NONBLOCK)) {
71 if (!ret)
72 return -1;
73 } else
74 /* non-blocking mode */
75 return -1;
77 ret = 0;
80 return ret;
83 int net_proto_udp_send (int fd, char *msg, unsigned size)
85 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
87 if (!conn)
88 return -1;
90 int ret = net_proto_udp_write (conn, msg, size);
92 if (ret) {
93 /* blocking mode */
94 if (!(conn->flags & O_NONBLOCK)) {
96 } else {
97 /* non-blocking mode */
98 /* TODO: ? */
103 return size;
106 int net_proto_udp_sendto (int fd, char *msg, unsigned size, sockaddr_in *to)
108 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
110 if (!conn)
111 return -1;
113 //int ip = conn->ip_dest;
115 /*net_proto_ip_print (conn->ip_dest);
116 kprintf (" | ");
117 net_proto_ip_print (conn->ip_source);*/
119 //conn->ip_source = to->sin_addr;
121 int ret = net_proto_udp_write (conn, msg, size);
123 //conn->ip_dest = ip;
125 if (ret) {
126 /* blocking mode */
127 if (!(conn->flags & O_NONBLOCK)) {
129 } else {
130 /* non-blocking mode */
131 /* TODO: ? */
136 return size;
139 extern unsigned long timer_ticks;
140 int net_proto_udp_recv (int fd, char *msg, unsigned size)
142 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
144 if (!conn)
145 return -3;
147 if (!msg)
148 return -4;
150 int ret = 0;
152 /* blocking mode */
153 if (!(conn->flags & O_NONBLOCK)) {
154 unsigned long stime = timer_ticks;
156 while (!conn->len) {
157 if ((stime+10000) < timer_ticks)
158 return 0;
160 schedule ();
162 } else {
163 if (!conn->len)
164 return 0;
167 if (!conn->data)
168 return -5;
170 if (conn->len >= size)
171 return -2;
173 ret = conn->len;
175 if (conn->len > 0)
176 memcpy (msg, conn->data, conn->len);
178 conn->len = 0;
180 kfree (conn->data);
182 return ret;
185 int net_proto_udp_recvfrom (int fd, char *msg, unsigned size, sockaddr_in *from)
187 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
189 if (!conn)
190 return -3;
192 if (!msg)
193 return -4;
195 int ret = 0;
197 //int ip = conn->ip_dest;
199 from->sin_addr = conn->ip_dest;
200 //kprintf ("recvfrom -> ip: 0x%x\n", from->sin_addr);
202 /* blocking mode */
203 if (!(conn->flags & O_NONBLOCK)) {
204 /* TODO: timeout */
205 while (!conn->len)
206 schedule ();
207 } else {
208 if (!conn->len) {
209 //conn->ip_dest = ip;
210 return 0;
214 //conn->ip_dest = ip; // return old ip address back to structure
216 if (!conn->data)
217 return -5;
219 if (conn->len >= size)
220 return -2;
222 ret = conn->len;
224 if (conn->len > 0)
225 memcpy (msg, conn->data, conn->len);
227 conn->len = 0;
229 kfree (conn->data);
231 return ret;
234 int net_proto_udp_close (int fd)
236 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
238 if (!conn)
239 return -1;
241 int ret = net_proto_udp_conn_del (conn);
243 return ret;
246 int net_proto_udp_fcntl (int fd, int cmd, long arg)
248 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
250 if (!conn)
251 return -1;
253 switch (cmd) {
254 case F_GETFL:
255 return conn->flags;
256 case F_SETFL:
257 conn->flags = arg;
258 return 0;
261 return -1;
264 int net_proto_udp_bind (int fd, sockaddr_in *addr, socklen_t len)
266 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
268 if (!conn)
269 return -1;
271 netif_t *netif;
272 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
273 net_proto_udp_conn_set (conn, netif, addr->sin_port, 0, 0);
274 conn->bind = 1;
275 return 0;
278 return -1;
281 /** special functions for kernel purposes **/
282 /* set source ip address as anycast */
283 int net_proto_udp_anycast (int fd)
285 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
287 if (!conn)
288 return -1;
290 conn->ip_source = INADDR_ANY;
292 return 0;
295 /* set source port to specified one */
296 int net_proto_udp_port (int fd, net_port port)
298 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
300 if (!conn)
301 return -1;
303 conn->port_source = port;
305 return 0;
308 /** UDP protocol
309 * hardcore code :P
312 /* handler for received udp datagrams */
313 unsigned net_proto_udp_handler (packet_t *packet, proto_ip_t *ip, char *buf, unsigned len)
315 unsigned char ret;
316 proto_udp_t *udp = (proto_udp_t *) buf;
318 /* First check ip address and ports, that we want this data */
319 proto_udp_conn_t *conn = net_proto_udp_conn_check (ip->ip_dest, udp->port_dest, ip->ip_source, udp->port_source, &ret);
321 if (!conn && ret == 0)
322 return 1;
324 if (ret == 1)
325 conn->ip_dest = ip->ip_source;
327 /* HACK: very ugly */
328 conn->port_dest = udp->port_source;
330 /* save data to buffer; +8 because udp packet is 8byte header and then data */
331 int ret2 = net_proto_udp_read_cache (conn, buf+8, len-8);
333 if (ret2 < 1)
334 return 0;
336 return 1;
339 /* save received data to buffer */
340 int net_proto_udp_read_cache (proto_udp_conn_t *conn, char *data, unsigned len)
342 if (!data || !conn || !len)
343 return 0;
345 if (!conn->len)
346 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
347 else
348 conn->data = (char *) krealloc (conn->data, (sizeof (char) * (conn->len+len)));
350 if (!conn->data)
351 return -1;
353 memcpy (conn->data+conn->len, data, len);
355 conn->len += len;
357 //conn->data[conn->len] = '\0';
359 return conn->len;
362 int net_proto_udp_write (proto_udp_conn_t *conn, char *data, unsigned len)
364 if (!conn || !len || !data)
365 return 0;
367 mac_addr_t mac_dest;
368 unsigned get = arp_cache_get (conn->ip_dest, &mac_dest);
370 if (!get) {
371 arp_send_request (conn->netif, conn->ip_dest);
373 unsigned i = 0;
374 /* 100ms for waiting on ARP reply */
375 while (i < 100) {
376 get = arp_cache_get (conn->ip_dest, &mac_dest);
378 if (get)
379 break;
381 /* TODO: make better waiting for ARP reply */
382 timer_wait (1);
384 schedule ();
386 i ++;
389 if (!get)
390 return 0;
393 /* packet header */
394 packet_t *packet = (packet_t *) kmalloc (sizeof (packet_t));
396 if (!packet)
397 return 0;
399 memcpy (&packet->mac_source, conn->netif->dev->dev_addr, 6);
400 memcpy (&packet->mac_dest, mac_dest, 6);
401 packet->type = NET_PACKET_TYPE_IPV4;
403 /* ip layer */
404 proto_ip_t *ip = (proto_ip_t *) kmalloc (sizeof (proto_ip_t));
406 if (!ip)
407 return 0;
409 /* there are some fixed values - yeah it is horrible */
410 ip->ver = 4;
411 ip->head_len = 5;
413 ip->flags = 0;
414 ip->frag = 0;
415 ip->ttl = 64;
416 ip->checksum = 0;
417 ip->proto = NET_PROTO_IP_TYPE_UDP;
418 ip->ip_source = conn->ip_source;
419 ip->ip_dest = conn->ip_dest;
422 proto_udp_t *udp = (proto_udp_t *) kmalloc (sizeof (proto_udp_t));
424 if (!udp)
425 return 0;
427 udp->port_source = conn->port_source;
428 udp->port_dest = conn->port_dest;
430 udp->len = swap16 (8 + len);
432 udp->checksum = 0;
435 unsigned l = (ip->head_len * 4);
437 /* calculate total length of packet (udp/ip) */
438 ip->total_len = swap16 (l + 8 + len);
440 char *buf_udp = (char *) kmalloc ((9 + len) * sizeof (char));
442 if (!buf_udp)
443 return 0;
445 memcpy (buf_udp, (char *) udp, 8);
446 memcpy (buf_udp+8, data, len);
448 buf_udp[8 + len] = '\0';
450 /* calculate checksum and put it to udp header */
451 // FIXME: wrong checksum
452 proto_udp_t *udp_ = (proto_udp_t *) buf_udp;
453 udp_->checksum = checksum16_udp (conn->ip_source, conn->ip_dest, buf_udp, 8 + len); // checksum16 (buf_udp, 8 + len);
455 /* send udp header+data to ip layer */
456 unsigned ret = net_proto_ip_send (conn->netif, packet, ip, (char *) buf_udp, 8 + len);
458 kfree (buf_udp);
459 kfree (udp);
460 kfree (ip);
461 kfree (packet);
463 return ret;
467 /* Create new UDP connection */
468 int net_proto_udp_conn_add (fd_t *fd)
470 proto_udp_conn_t *conn;
472 /* alloc and init context */
473 conn = (proto_udp_conn_t *) kmalloc (sizeof (proto_udp_conn_t));
475 if (!conn) {
476 errno_set (ENOMEM);
477 return -1;
480 memset (conn, 0, sizeof (proto_udp_conn_t));
482 conn->flags = 0;
484 conn->fd = fd->id;
486 /* add into list */
487 conn->next = &proto_udp_conn_list;
488 conn->prev = proto_udp_conn_list.prev;
489 conn->prev->next = conn;
490 conn->next->prev = conn;
492 return 0;
495 /* Setup new connection */
496 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)
498 if (!conn || !eth)
499 return 0;
501 conn->ip_source = eth->ip;
502 conn->ip_dest = ip_dest;
504 conn->port_source = port_source;
505 conn->port_dest = port_dest;
507 conn->netif = eth;
509 conn->bind = 0;
511 conn->len = 0;
512 conn->data = 0;
514 return 1;
517 /* Delete existing connection from list */
518 unsigned net_proto_udp_conn_del (proto_udp_conn_t *conn)
520 if (!conn)
521 return 0;
523 if (conn->len)
524 kfree (conn->data);
526 conn->len = 0;
528 conn->next->prev = conn->prev;
529 conn->prev->next = conn->next;
531 kfree (conn);
533 return 1;
536 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)
538 *ret = 0;
539 proto_udp_conn_t *conn = NULL;
540 proto_udp_conn_t *conn_ret = NULL;
542 if (conn->ip_dest != INADDR_BROADCAST) {
543 for (conn = proto_udp_conn_list.next; conn != &proto_udp_conn_list; conn = conn->next) {
544 if (conn->ip_source == ip_source && conn->port_source == port_source) {
545 if (conn->ip_dest == ip_dest) {
546 *ret = 2;
547 return conn;
550 *ret = 1;
552 conn_ret = conn;
555 } else { /* broadcast packet */
556 for (conn = proto_udp_conn_list.next; conn != &proto_udp_conn_list; conn = conn->next) {
557 if (conn->port_source == port_source && conn->port_dest == port_dest) {
558 conn->ip_source = ip_dest;
559 conn->ip_dest = ip_source;
561 *ret = 2;
562 return conn;
567 if (*ret == 1)
568 if (!conn_ret->bind) {
569 conn_ret = 0;
571 for (conn = proto_udp_conn_list.next; conn != &proto_udp_conn_list; conn = conn->next) {
572 if (conn->bind) {
573 if (conn->ip_source == ip_source && conn->port_source == port_source)
574 conn_ret = conn;
579 return conn_ret;
582 proto_udp_conn_t *net_proto_udp_conn_find (int fd)
584 proto_udp_conn_t *conn = NULL;
585 for (conn = proto_udp_conn_list.next; conn != &proto_udp_conn_list; conn = conn->next) {
586 if (conn->fd == fd)
587 return conn;
590 return 0;
593 /* init of udp protocol */
594 unsigned init_net_proto_udp ()
596 proto_udp_conn_list.next = &proto_udp_conn_list;
597 proto_udp_conn_list.prev = &proto_udp_conn_list;
599 return 1;