Kernel 0.5.9-r12; UDP protocol stuff support server with sendto
[ZeXOS.git] / kernel / core / net / udp.c
blobd330b3df46b30f8ae65456e5bc7f3919f40d84ce
1 /*
2 * ZeX/OS
3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <system.h>
21 #include <string.h>
22 #include <dev.h>
23 #include <net/eth.h>
24 #include <net/net.h>
25 #include <net/if.h>
26 #include <net/ip.h>
27 #include <net/packet.h>
28 #include <net/udp.h>
29 #include <net/socket.h>
32 extern netif_t netif_list;
33 proto_udp_conn_t proto_udp_conn_list;
35 static net_port proto_udp_client_port;
36 static unsigned proto_udp_fd;
38 /* prototypes */
39 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);
40 int net_proto_udp_read_cache (proto_udp_conn_t *conn, char *data, unsigned len);
41 int net_proto_udp_write (proto_udp_conn_t *conn, char *data, unsigned len);
42 proto_udp_conn_t *net_proto_udp_conn_find (int fd);
43 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);
44 unsigned net_proto_udp_conn_del (proto_udp_conn_t *conn);
45 int net_proto_udp_conn_add ();
47 /** UDP protocol
48 * User-friendly socket functions
50 int net_proto_udp_socket ()
52 return net_proto_udp_conn_add ();
55 int net_proto_udp_connect (int fd, sockaddr_in *addr)
57 int ret = -1;
59 proto_udp_conn_t *conn = net_proto_udp_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_udp_conn_set (conn, netif, swap16 (proto_udp_client_port ++), addr->sin_addr, addr->sin_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_udp_send (int fd, char *msg, unsigned size)
86 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
88 if (!conn)
89 return -1;
91 int ret = net_proto_udp_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_udp_sendto (int fd, char *msg, unsigned size, sockaddr_in *to)
109 proto_udp_conn_t *conn = net_proto_udp_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->sin_addr;
122 int ret = net_proto_udp_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 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 /* TODO: timeout */
155 while (!conn->len)
156 schedule ();
157 } else {
158 if (!conn->len)
159 return 0;
162 if (!conn->data)
163 return -5;
165 if (conn->len >= size)
166 return -2;
168 ret = conn->len;
170 if (conn->len > 0)
171 memcpy (msg, conn->data, conn->len);
173 conn->len = 0;
175 kfree (conn->data);
177 return ret;
180 int net_proto_udp_recvfrom (int fd, char *msg, unsigned size, sockaddr_in *from)
182 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
184 if (!conn)
185 return -3;
187 if (!msg)
188 return -4;
190 int ret = 0;
192 //int ip = conn->ip_dest;
194 from->sin_addr = conn->ip_dest;
195 //kprintf ("recvfrom -> ip: 0x%x\n", from->sin_addr);
197 /* blocking mode */
198 if (!(conn->flags & O_NONBLOCK)) {
199 /* TODO: timeout */
200 while (!conn->len)
201 schedule ();
202 } else {
203 if (!conn->len) {
204 //conn->ip_dest = ip;
205 return 0;
209 //conn->ip_dest = ip; // return old ip address back to structure
211 if (!conn->data)
212 return -5;
214 if (conn->len >= size)
215 return -2;
217 ret = conn->len;
219 if (conn->len > 0)
220 memcpy (msg, conn->data, conn->len);
222 conn->len = 0;
224 kfree (conn->data);
226 return ret;
229 int net_proto_udp_close (int fd)
231 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
233 if (!conn)
234 return -1;
236 int ret = net_proto_udp_conn_del (conn);
238 return ret;
241 int net_proto_udp_fcntl (int fd, int cmd, long arg)
243 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
245 if (!conn)
246 return -1;
248 switch (cmd) {
249 case F_GETFL:
250 return conn->flags;
251 case F_SETFL:
252 conn->flags = arg;
253 return 0;
256 return -1;
259 int net_proto_udp_bind (int fd, sockaddr_in *addr, socklen_t len)
261 proto_udp_conn_t *conn = net_proto_udp_conn_find (fd);
263 if (!conn)
264 return -1;
266 netif_t *netif;
267 for (netif = netif_list.next; netif != &netif_list; netif = netif->next) {
268 net_proto_udp_conn_set (conn, netif, addr->sin_port, 0, 0);
269 conn->bind = 1;
270 return 0;
273 return -1;
276 /** UDP protocol
277 * hardcore code :P
280 /* handler for received udp datagrams */
281 unsigned net_proto_udp_handler (packet_t *packet, proto_ip_t *ip, char *buf, unsigned len)
283 unsigned char ret;
284 proto_udp_t *udp = (proto_udp_t *) buf;
286 /* First check ip address and ports, that we want this data */
287 proto_udp_conn_t *conn = net_proto_udp_conn_check (ip->ip_dest, udp->port_dest, ip->ip_source, udp->port_source, &ret);
289 if (!conn && ret == 0)
290 return 1;
292 if (ret == 1)
293 conn->ip_dest = ip->ip_source;
295 /* HACK: very ugly */
296 conn->port_dest = udp->port_source;
298 /* save data to buffer; +8 because udp packet is 8byte header and then data */
299 int ret2 = net_proto_udp_read_cache (conn, buf+8, len-8);
301 if (ret2 < 1)
302 return 0;
304 return 1;
307 /* save received data to buffer */
308 int net_proto_udp_read_cache (proto_udp_conn_t *conn, char *data, unsigned len)
310 if (!data || !conn || !len)
311 return 0;
313 if (!conn->len)
314 conn->data = (char *) kmalloc (sizeof (char) * (len + 1));
315 else
316 conn->data = (char *) krealloc (conn->data, (sizeof (char) * (conn->len+len)));
318 if (!conn->data)
319 return -1;
321 memcpy (conn->data+conn->len, data, len);
323 conn->len += len;
325 //conn->data[conn->len] = '\0';
327 return conn->len;
330 int net_proto_udp_write (proto_udp_conn_t *conn, char *data, unsigned len)
332 if (!conn || !len || !data)
333 return 0;
335 mac_addr_t mac_dest;
336 unsigned get = arp_cache_get (conn->ip_dest, &mac_dest);
338 if (!get) {
339 arp_send_request (conn->netif, conn->ip_dest);
341 unsigned i = 0;
342 /* 100ms for waiting on ARP reply */
343 while (i < 100) {
344 get = arp_cache_get (conn->ip_dest, &mac_dest);
346 if (get)
347 break;
349 /* TODO: make better waiting for ARP reply */
350 timer_wait (1);
352 schedule ();
354 i ++;
357 if (!get)
358 return 0;
361 /* packet header */
362 packet_t *packet = (packet_t *) kmalloc (sizeof (packet_t));
364 if (!packet)
365 return 0;
367 memcpy (&packet->mac_source, conn->netif->dev->dev_addr, 6);
368 memcpy (&packet->mac_dest, mac_dest, 6);
369 packet->type = NET_PACKET_TYPE_IPV4;
371 /* ip layer */
372 proto_ip_t *ip = (proto_ip_t *) kmalloc (sizeof (proto_ip_t));
374 if (!ip)
375 return 0;
377 /* there are some fixed values - yeah it is horrible */
378 ip->ver = 4;
379 ip->head_len = 5;
381 ip->flags = 0;
382 ip->frag = 0;
383 ip->ttl = 64;
384 ip->checksum = 0;
385 ip->proto = NET_PROTO_IP_TYPE_UDP;
386 ip->ip_source = conn->netif->ip;
387 ip->ip_dest = conn->ip_dest;
390 proto_udp_t *udp = (proto_udp_t *) kmalloc (sizeof (proto_udp_t));
392 if (!udp)
393 return 0;
395 udp->port_source = conn->port_source;
396 udp->port_dest = conn->port_dest;
398 udp->len = swap16 (8 + len);
400 udp->checksum = 0;
403 unsigned l = (ip->head_len * 4);
405 /* calculate total length of packet (udp/ip) */
406 ip->total_len = swap16 (l + 8 + len);
408 char *buf_udp = (char *) kmalloc ((9 + len) * sizeof (char));
410 if (!buf_udp)
411 return 0;
413 memcpy (buf_udp, (char *) udp, 8);
414 memcpy (buf_udp+8, data, len);
416 buf_udp[8 + len] = '\0';
418 /* calculate checksum and put it to udp header */
419 // FIXME: wrong checksum
420 proto_udp_t *udp_ = (proto_udp_t *) buf_udp;
421 udp_->checksum = checksum16_udp (conn->netif->ip, conn->ip_dest, buf_udp, 8 + len); // checksum16 (buf_udp, 8 + len);
423 /* send udp header+data to ip layer */
424 unsigned ret = net_proto_ip_send (conn->netif, packet, ip, (char *) buf_udp, 8 + len);
426 kfree (buf_udp);
427 kfree (udp);
428 kfree (ip);
429 kfree (packet);
431 return ret;
435 /* Create new UDP connection */
436 int net_proto_udp_conn_add ()
438 proto_udp_conn_t *conn;
440 /* alloc and init context */
441 conn = (proto_udp_conn_t *) kmalloc (sizeof (proto_udp_conn_t));
443 if (!conn)
444 return 0;
446 memset (conn, 0, sizeof (proto_udp_conn_t));
448 conn->flags = 0;
450 conn->fd = proto_udp_fd ++;
452 /* add into list */
453 conn->next = &proto_udp_conn_list;
454 conn->prev = proto_udp_conn_list.prev;
455 conn->prev->next = conn;
456 conn->next->prev = conn;
458 return conn->fd;
461 /* Setup new connection */
462 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)
464 if (!conn || !eth)
465 return 0;
467 conn->ip_source = eth->ip;
468 conn->ip_dest = ip_dest;
470 conn->port_source = port_source;
471 conn->port_dest = port_dest;
473 conn->netif = eth;
475 conn->bind = 0;
477 conn->len = 0;
478 conn->data = 0;
480 return 1;
483 /* Delete existing connection from list */
484 unsigned net_proto_udp_conn_del (proto_udp_conn_t *conn)
486 if (!conn)
487 return 0;
489 if (conn->len)
490 kfree (conn->data);
492 conn->len = 0;
494 conn->next->prev = conn->prev;
495 conn->prev->next = conn->next;
497 kfree (conn);
499 return 1;
502 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)
504 *ret = 0;
505 proto_udp_conn_t *conn = NULL;
506 proto_udp_conn_t *conn_ret = NULL;
508 for (conn = proto_udp_conn_list.next; conn != &proto_udp_conn_list; conn = conn->next) {
509 if (conn->ip_source == ip_source && conn->port_source == port_source) {
510 if (conn->ip_dest == ip_dest /*&& conn->port_dest == port_dest*/) {
511 *ret = 2;
512 return conn;
515 *ret = 1;
517 conn_ret = conn;
521 if (*ret == 1)
522 if (!conn_ret->bind) {
523 conn_ret = 0;
525 for (conn = proto_udp_conn_list.next; conn != &proto_udp_conn_list; conn = conn->next) {
526 if (conn->bind) {
527 if (conn->ip_source == ip_source && conn->port_source == port_source)
528 conn_ret = conn;
533 return conn_ret;
536 proto_udp_conn_t *net_proto_udp_conn_find (int fd)
538 proto_udp_conn_t *conn = NULL;
539 for (conn = proto_udp_conn_list.next; conn != &proto_udp_conn_list; conn = conn->next) {
540 if (conn->fd == fd)
541 return conn;
544 return 0;
547 /* init of udp protocol */
548 unsigned init_net_proto_udp ()
550 proto_udp_conn_list.next = &proto_udp_conn_list;
551 proto_udp_conn_list.prev = &proto_udp_conn_list;
553 /* base udp client port, which is used for client's use */
554 proto_udp_client_port = 1024;
555 proto_udp_fd = 4096;
557 return 1;