fix issue with HBC stub + 64B L2 cache (tueidj)
[libogc.git] / libogc / network_wii.c
blobd908082bfa71f4b18aff0ee29886b9fd965e2c54
1 /*-------------------------------------------------------------
3 network_wii.c -- Wii network subsystem
5 Copyright (C) 2008 bushing
7 This software is provided 'as-is', without any express or implied
8 warranty. In no event will the authors be held liable for any
9 damages arising from the use of this software.
11 Permission is granted to anyone to use this software for any
12 purpose, including commercial applications, and to alter it and
13 redistribute it freely, subject to the following restrictions:
15 1. The origin of this software must not be misrepresented; you
16 must not claim that you wrote the original software. If you use
17 this software in a product, an acknowledgment in the product
18 documentation would be appreciated but is not required.
20 2. Altered source versions must be plainly marked as such, and
21 must not be misrepresented as being the original software.
23 3. This notice may not be removed or altered from any source
24 distribution.
26 -------------------------------------------------------------*/
28 #if defined(HW_RVL)
31 #define MAX_IP_RETRIES 100
32 #define MAX_INIT_RETRIES 32
34 //#define DEBUG_NET
36 #ifdef DEBUG_NET
37 #define debug_printf(fmt, args...) \
38 do { \
39 fprintf(stderr, "%s:%d:" fmt, __FUNCTION__, __LINE__, ##args); \
40 } while (0)
41 #else
42 #define debug_printf(fmt, args...) do { } while (0)
43 #endif // DEBUG_NET
45 #include <stdio.h>
46 #include <stdarg.h>
47 #include <string.h>
48 #define __LINUX_ERRNO_EXTENSIONS__
49 #include <errno.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 #include <malloc.h>
54 #include "ipc.h"
55 #include "processor.h"
56 #include "network.h"
57 #include "ogcsys.h"
58 #include "lwp_heap.h"
60 #define NET_HEAP_SIZE 64*1024
62 #define IOS_O_NONBLOCK 0x04 //(O_NONBLOCK >> 16) - it's in octal representation, so this shift leads to 0 and hence nonblocking sockets didn't work. changed it to the right value.
64 #define IOCTL_NWC24_STARTUP 0x06
66 #define IOCTL_NCD_SETIFCONFIG3 0x03
67 #define IOCTL_NCD_SETIFCONFIG4 0x04
68 #define IOCTL_NCD_GETLINKSTATUS 0x07
69 #define IOCTLV_NCD_GETMACADDRESS 0x08
71 #define NET_UNKNOWN_ERROR_OFFSET -10000
73 enum {
74 IOCTL_SO_ACCEPT = 1,
75 IOCTL_SO_BIND,
76 IOCTL_SO_CLOSE,
77 IOCTL_SO_CONNECT,
78 IOCTL_SO_FCNTL,
79 IOCTL_SO_GETPEERNAME, // todo
80 IOCTL_SO_GETSOCKNAME, // todo
81 IOCTL_SO_GETSOCKOPT, // todo 8
82 IOCTL_SO_SETSOCKOPT,
83 IOCTL_SO_LISTEN,
84 IOCTL_SO_POLL, // todo b
85 IOCTLV_SO_RECVFROM,
86 IOCTLV_SO_SENDTO,
87 IOCTL_SO_SHUTDOWN, // todo e
88 IOCTL_SO_SOCKET,
89 IOCTL_SO_GETHOSTID,
90 IOCTL_SO_GETHOSTBYNAME,
91 IOCTL_SO_GETHOSTBYADDR,// todo
92 IOCTLV_SO_GETNAMEINFO, // todo 13
93 IOCTL_SO_UNK14, // todo
94 IOCTL_SO_INETATON, // todo
95 IOCTL_SO_INETPTON, // todo
96 IOCTL_SO_INETNTOP, // todo
97 IOCTLV_SO_GETADDRINFO, // todo
98 IOCTL_SO_SOCKATMARK, // todo
99 IOCTLV_SO_UNK1A, // todo
100 IOCTLV_SO_UNK1B, // todo
101 IOCTLV_SO_GETINTERFACEOPT, // todo
102 IOCTLV_SO_SETINTERFACEOPT, // todo
103 IOCTL_SO_SETINTERFACE, // todo
104 IOCTL_SO_STARTUP, // 0x1f
105 IOCTL_SO_ICMPSOCKET = 0x30, // todo
106 IOCTLV_SO_ICMPPING, // todo
107 IOCTL_SO_ICMPCANCEL, // todo
108 IOCTL_SO_ICMPCLOSE // todo
111 struct init_data {
112 u32 state;
113 s32 fd;
114 s32 prevres;
115 s32 result;
116 syswd_t alarm;
117 u32 retries;
118 netcallback cb;
119 void *usrdata;
120 u8 *buf;
123 struct init_default_cb {
124 lwpq_t queue;
125 s32 result;
128 struct bind_params {
129 u32 socket;
130 u32 has_name;
131 u8 name[28];
134 struct connect_params {
135 u32 socket;
136 u32 has_addr;
137 u8 addr[28];
140 struct sendto_params {
141 u32 socket;
142 u32 flags;
143 u32 has_destaddr;
144 u8 destaddr[28];
147 struct setsockopt_params {
148 u32 socket;
149 u32 level;
150 u32 optname;
151 u32 optlen;
152 u8 optval[20];
155 // 0 means we don't know what this error code means
156 // I sense a pattern here...
157 static u8 _net_error_code_map[] = {
158 0, // 0
159 E2BIG,
160 EACCES,
161 EADDRINUSE,
162 EADDRNOTAVAIL,
163 EAFNOSUPPORT, // 5
164 EAGAIN,
165 EALREADY,
166 EBADFD,
167 EBADMSG,
168 EBUSY, // 10
169 ECANCELED,
170 ECHILD,
171 ECONNABORTED,
172 ECONNREFUSED,
173 ECONNRESET, // 15
174 EDEADLK,
175 EDESTADDRREQ,
176 EDOM,
177 EDQUOT,
178 EEXIST, // 20
179 EFAULT,
180 EFBIG,
181 EHOSTUNREACH,
182 EIDRM,
183 EILSEQ, // 25
184 EINPROGRESS,
185 EINTR,
186 EINVAL,
187 EIO,
188 EISCONN, // 30
189 EISDIR,
190 ELOOP,
191 EMFILE,
192 EMLINK,
193 EMSGSIZE, // 35
194 EMULTIHOP,
195 ENAMETOOLONG,
196 ENETDOWN,
197 ENETRESET,
198 ENETUNREACH, // 40
199 ENFILE,
200 ENOBUFS,
201 ENODATA,
202 ENODEV,
203 ENOENT, // 45
204 ENOEXEC,
205 ENOLCK,
206 ENOLINK,
207 ENOMEM,
208 ENOMSG, // 50
209 ENOPROTOOPT,
210 ENOSPC,
211 ENOSR,
212 ENOSTR,
213 ENOSYS, // 55
214 ENOTCONN,
215 ENOTDIR,
216 ENOTEMPTY,
217 ENOTSOCK,
218 ENOTSUP, // 60
219 ENOTTY,
220 ENXIO,
221 EOPNOTSUPP,
222 EOVERFLOW,
223 EPERM, // 65
224 EPIPE,
225 EPROTO,
226 EPROTONOSUPPORT,
227 EPROTOTYPE,
228 ERANGE, // 70
229 EROFS,
230 ESPIPE,
231 ESRCH,
232 ESTALE,
233 ETIME, // 75
234 ETIMEDOUT,
237 static volatile bool _init_busy = false;
238 static volatile bool _init_abort = false;
239 static vs32 _last_init_result = -ENETDOWN;
240 static s32 net_ip_top_fd = -1;
241 static u8 __net_heap_inited = 0;
242 static s32 __net_hid=-1;
243 static heap_cntrl __net_heap;
245 static char __manage_fs[] ATTRIBUTE_ALIGN(32) = "/dev/net/ncd/manage";
246 static char __iptop_fs[] ATTRIBUTE_ALIGN(32) = "/dev/net/ip/top";
247 static char __kd_fs[] ATTRIBUTE_ALIGN(32) = "/dev/net/kd/request";
249 #define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
251 static s32 NetCreateHeap()
253 u32 level;
254 void *net_heap_ptr;
256 _CPU_ISR_Disable(level);
258 if(__net_heap_inited)
260 _CPU_ISR_Restore(level);
261 return IPC_OK;
264 net_heap_ptr = (void *)ROUNDDOWN32(((u32)SYS_GetArena2Hi() - NET_HEAP_SIZE));
265 if((u32)net_heap_ptr < (u32)SYS_GetArena2Lo())
267 _CPU_ISR_Restore(level);
268 return IPC_ENOMEM;
270 SYS_SetArena2Hi(net_heap_ptr);
271 __lwp_heap_init(&__net_heap, net_heap_ptr, NET_HEAP_SIZE, 32);
272 __net_heap_inited=1;
273 _CPU_ISR_Restore(level);
274 return IPC_OK;
277 static void* net_malloc(u32 size)
279 return __lwp_heap_allocate(&__net_heap, size);
282 static BOOL net_free(void *ptr)
284 return __lwp_heap_free(&__net_heap, ptr);
287 static s32 _net_convert_error(s32 ios_retval)
289 // return ios_retval;
290 if (ios_retval >= 0) return ios_retval;
291 if (ios_retval < -sizeof(_net_error_code_map)
292 || !_net_error_code_map[-ios_retval])
293 return NET_UNKNOWN_ERROR_OFFSET + ios_retval;
294 return -_net_error_code_map[-ios_retval];
297 u32 net_gethostip(void)
299 u32 ip_addr=0;
300 int retries;
302 if (net_ip_top_fd < 0) return 0;
303 for (retries=0, ip_addr=0; !ip_addr && retries < 5; retries++) {
304 ip_addr = IOS_Ioctl(net_ip_top_fd, IOCTL_SO_GETHOSTID, 0, 0, 0, 0);
305 #ifdef DEBUG_NET
306 debug_printf(".");
307 fflush(stdout);
308 #endif
309 if (!ip_addr)
310 usleep(100000);
313 return ip_addr;
316 static s32 net_init_chain(s32 result, void *usrdata);
318 static void net_init_alarm(syswd_t alarm, void *cb_arg) {
319 debug_printf("net_init alarm\n");
320 net_init_chain(0, cb_arg);
323 static s32 net_init_chain(s32 result, void *usrdata) {
324 struct init_data *data = (struct init_data *) usrdata;
325 struct timespec tb;
327 debug_printf("net_init chain entered: %u %d\n", data->state, result);
329 if (_init_abort) {
330 data->state = 0xff;
331 goto error;
334 switch (data->state) {
335 case 0: // open manage fd
336 data->state = 1;
337 data->result = IOS_OpenAsync(__manage_fs, 0, net_init_chain, data);
338 if (data->result < 0) {
339 data->result = _net_convert_error(data->result);
340 goto done;
342 return 0;
344 case 1: // get link status
345 if (result == IPC_ENOENT) {
346 debug_printf("IPC_ENOENT, retrying...\n");
347 data->state = 0;
348 tb.tv_sec = 0;
349 tb.tv_nsec = 100000000;
350 data->result = SYS_SetAlarm(data->alarm, &tb, net_init_alarm, data);
351 if (data->result) {
352 debug_printf("error setting the alarm: %d\n", data->result);
353 goto done;
355 return 0;
358 if (result < 0) {
359 data->result = _net_convert_error(result);
360 debug_printf("error opening the manage fd: %d\n", data->result);
361 goto done;
364 data->fd = result;
365 data->state = 2;
366 data->result = IOS_IoctlvFormatAsync(__net_hid, data->fd, IOCTL_NCD_GETLINKSTATUS, net_init_chain, data, ":d", data->buf, 0x20);
367 if (data->result < 0) {
368 data->result = _net_convert_error(data->result);
369 data->state = 0xff;
370 if (IOS_CloseAsync(data->fd, net_init_chain, data) < 0)
371 goto done;
373 return 0;
375 case 2: // close manage fd
376 data->prevres = result;
377 data->state = 3;
378 data->result = IOS_CloseAsync(data->fd, net_init_chain, data);
379 if (data->result < 0) {
380 data->result = _net_convert_error(data->result);
381 goto done;
383 return 0;
385 case 3: // open top fd
386 if (data->prevres < 0) {
387 data->result = _net_convert_error(data->prevres);
388 debug_printf("invalid link status %d\n", data->result);
389 goto done;
392 data->state = 4;
393 data->result = IOS_OpenAsync(__iptop_fs, 0, net_init_chain, data);
394 if (data->result < 0) {
395 data->result = _net_convert_error(data->result);
396 goto done;
398 return 0;
400 case 4: // open request fd
401 if (result < 0) {
402 data->result = _net_convert_error(result);
403 debug_printf("error opening the top fd: %d\n", data->result);
404 goto done;
407 net_ip_top_fd = result;
408 data->state = 5;
409 data->result = IOS_OpenAsync(__kd_fs, 0, net_init_chain, data);
410 if (data->result < 0) {
411 data->result = _net_convert_error(data->result);
412 data->state = 0xff;
413 goto error;
415 return 0;
417 case 5: // NWC24 startup
418 if (result < 0) {
419 data->result = _net_convert_error(result);
420 debug_printf("error opening the request fd: %d\n", data->result);
421 data->state = 0xff;
422 goto error;
425 data->fd = result;
426 data->retries = MAX_INIT_RETRIES;
427 case 6:
428 data->state = 7;
429 data->result = IOS_IoctlAsync(data->fd, IOCTL_NWC24_STARTUP, NULL, 0, data->buf, 0x20, net_init_chain, data);
430 if (data->result < 0) {
431 data->result = _net_convert_error(data->result);
432 data->state = 0xff;
433 if (IOS_CloseAsync(data->fd, net_init_chain, data) < 0)
434 goto done;
436 return 0;
437 case 7:
438 if (result==0) {
439 memcpy(&result, data->buf, sizeof(result));
440 if(result==-29 && --data->retries) {
441 data->state = 6;
442 tb.tv_sec = 0;
443 tb.tv_nsec = 100000000;
444 data->result = SYS_SetAlarm(data->alarm, &tb, net_init_alarm, data);
445 if (data->result) {
446 data->state = 0xff;
447 debug_printf("error setting the alarm: %d\n", data->result);
448 if (IOS_CloseAsync(data->fd, net_init_chain, data) < 0)
449 goto error;
451 return 0;
452 } else if (result == -15) // this happens if it's already been started
453 result = 0;
456 data->prevres = result;
457 data->state = 8;
458 data->result = IOS_CloseAsync(data->fd, net_init_chain, data);
459 if (data->result < 0) {
460 data->result = _net_convert_error(data->result);
461 data->state = 0xff;
462 goto error;
464 return 0;
466 case 8: // socket startup
467 if (data->prevres < 0) {
468 data->result = _net_convert_error(data->prevres);
469 debug_printf("NWC24 startup failed: %d\n", data->result);
470 data->state = 0xff;
471 goto error;
474 data->state = 9;
475 data->retries = MAX_IP_RETRIES;
476 data->result = IOS_IoctlAsync(net_ip_top_fd, IOCTL_SO_STARTUP, 0, 0, 0, 0, net_init_chain, data);
477 if (data->result < 0) {
478 data->result = _net_convert_error(data->result);
479 data->state = 0xff;
480 goto error;
482 return 0;
484 case 9: // check ip
485 if (result < 0) {
486 data->result = _net_convert_error(result);
487 debug_printf("socket startup failed: %d\n", data->result);
488 data->state = 0xff;
489 goto error;
492 data->state = 10;
493 data->result = IOS_IoctlAsync(net_ip_top_fd, IOCTL_SO_GETHOSTID, 0, 0, 0, 0, net_init_chain, data);
494 if (data->result < 0) {
495 data->result = _net_convert_error(data->result);
496 data->state = 0xff;
497 goto error;
499 return 0;
501 case 10: // done, check result
502 if (result == 0) {
503 if (!data->retries) {
504 data->result = -ETIMEDOUT;
505 debug_printf("unable to obtain ip\n");
506 data->state = 0xff;
507 goto error;
510 debug_printf("unable to obtain ip, retrying...\n");
511 data->state = 9;
512 data->retries--;
513 tb.tv_sec = 0;
514 tb.tv_nsec = 100000000;
515 data->result = SYS_SetAlarm(data->alarm, &tb, net_init_alarm, data);
516 if (data->result) {
517 data->state = 0xff;
518 debug_printf("error setting the alarm: %d\n", data->result);
519 goto error;
521 return 0;
524 data->result = 0;
525 goto done;
527 error:
528 case 0xff: // error occured before, last async call finished
529 if (net_ip_top_fd >= 0) {
530 data->fd = net_ip_top_fd;
531 net_ip_top_fd = -1;
532 if (IOS_CloseAsync(data->fd, net_init_chain, data) < 0)
533 goto done;
534 return 0;
536 goto done;
538 default:
539 debug_printf("unknown state in chain %d\n", data->state);
540 data->result = -1;
542 break;
545 done:
546 SYS_RemoveAlarm(data->alarm);
548 _last_init_result = data->result;
550 if (data->cb)
551 data->cb(data->result, data->usrdata);
553 free(data->buf);
554 free(data);
556 _init_busy = false;
558 return 0;
561 s32 net_init_async(netcallback cb, void *usrdata) {
562 s32 ret;
563 struct init_data *data;
565 if (net_ip_top_fd >= 0)
566 return 0;
568 if (_init_busy)
569 return -EBUSY;
571 ret = NetCreateHeap();
572 if (ret != IPC_OK)
573 return ret;
575 if (__net_hid == -1)
576 __net_hid = iosCreateHeap(1024); //only needed for ios calls
578 if (__net_hid < 0)
579 return __net_hid;
581 data = malloc(sizeof(struct init_data));
582 if (!data)
583 return -1;
585 memset(data, 0, sizeof(struct init_data));
587 if (SYS_CreateAlarm(&data->alarm)) {
588 debug_printf("error creating alarm\n");
589 free(data);
590 return -1;
593 data->buf = memalign(32, 0x20);
594 if (!data->buf) {
595 free(data);
596 return -1;
599 data->cb = cb;
600 data->usrdata = usrdata;
602 // kick off the callback chain
603 _init_busy = true;
604 _init_abort = false;
605 _last_init_result = -EBUSY;
606 net_init_chain(IPC_ENOENT, data);
608 return 0;
611 static void net_init_callback(s32 result, void *usrdata) {
612 struct init_default_cb *data = (struct init_default_cb *) usrdata;
614 data->result = result;
615 LWP_ThreadBroadcast(data->queue);
617 return;
620 s32 net_init(void) {
621 struct init_default_cb data;
623 if (net_ip_top_fd >= 0)
624 return 0;
626 LWP_InitQueue(&data.queue);
627 net_init_async((netcallback)net_init_callback, &data);
628 LWP_ThreadSleep(data.queue);
629 LWP_CloseQueue(data.queue);
631 return data.result;
634 s32 net_get_status(void) {
635 return _last_init_result;
638 void net_deinit() {
639 if (_init_busy) {
640 debug_printf("aborting net_init_async\n");
641 _init_abort = true;
642 while (_init_busy)
643 usleep(50);
644 debug_printf("net_init_async done\n");
647 if (net_ip_top_fd >= 0) IOS_Close(net_ip_top_fd);
648 net_ip_top_fd = -1;
649 _last_init_result = -ENETDOWN;
652 void net_wc24cleanup() {
653 s32 kd_fd, ret;
654 STACK_ALIGN(u8, kd_buf, 0x20, 32);
656 kd_fd = IOS_Open(__kd_fs, 0);
657 if (kd_fd >= 0) {
658 ret = IOS_Ioctl(kd_fd, 7, NULL, 0, kd_buf, 0x20);
659 IOS_Close(kd_fd);
663 s32 net_get_mac_address(void *mac_buf) {
664 s32 fd;
665 s32 result;
666 void *_mac_buf;
667 STACK_ALIGN(u32, manage_buf, 0x20, 32);
669 if (mac_buf==NULL) return -EINVAL;
671 result = NetCreateHeap();
672 if (result!=IPC_OK) return result;
674 _mac_buf = net_malloc(6);
675 if (_mac_buf==NULL) return IPC_ENOMEM;
677 fd = IOS_Open(__manage_fs, 0);
678 if (fd<0) {
679 net_free(_mac_buf);
680 return fd;
683 result = IOS_IoctlvFormat(__net_hid, fd, IOCTLV_NCD_GETMACADDRESS, ":dd", manage_buf, 0x20, _mac_buf, 0x06);
684 IOS_Close(fd);
686 if (result>=0) {
687 memcpy(mac_buf, _mac_buf, 6);
688 if (manage_buf[0]) result = manage_buf[0];
691 net_free(_mac_buf);
692 return result;
695 /* Returned value is a static buffer -- this function is not threadsafe! */
696 struct hostent * net_gethostbyname(const char *addrString)
698 s32 ret, len, i;
699 u8 *params;
700 struct hostent *ipData;
701 u32 addrOffset;
702 static u8 ipBuffer[0x460] ATTRIBUTE_ALIGN(32);
704 memset(ipBuffer, 0, 0x460);
706 if (net_ip_top_fd < 0) {
707 errno = -ENXIO;
708 return NULL;
711 len = strlen(addrString) + 1;
712 params = net_malloc(len);
713 if (params==NULL) {
714 errno = IPC_ENOMEM;
715 return NULL;
718 memcpy(params, addrString, len);
720 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_GETHOSTBYNAME, params, len, ipBuffer, 0x460));
722 if(params!=NULL) net_free(params);
724 if (ret < 0) {
725 errno = ret;
726 return NULL;
729 ipData = ((struct hostent*)ipBuffer);
730 addrOffset = (u32)MEM_PHYSICAL_TO_K0(ipData->h_name) - ((u32)ipBuffer + 0x10);
732 ipData->h_name = MEM_PHYSICAL_TO_K0(ipData->h_name) - addrOffset;
733 ipData->h_aliases = MEM_PHYSICAL_TO_K0(ipData->h_aliases) - addrOffset;
735 for (i=0; (i < 0x40) && (ipData->h_aliases[i] != 0); i++) {
736 ipData->h_aliases[i] = MEM_PHYSICAL_TO_K0(ipData->h_aliases[i]) - addrOffset;
739 ipData->h_addr_list = MEM_PHYSICAL_TO_K0(ipData->h_addr_list) - addrOffset;
741 for (i=0; (i < 0x40) && (ipData->h_addr_list[i] != 0); i++) {
742 ipData->h_addr_list[i] = MEM_PHYSICAL_TO_K0(ipData->h_addr_list[i]) - addrOffset;
745 errno = 0;
746 return ipData;
749 s32 net_socket(u32 domain, u32 type, u32 protocol)
751 s32 ret;
752 STACK_ALIGN(u32, params, 3, 32);
754 if (net_ip_top_fd < 0) return -ENXIO;
756 params[0] = domain;
757 params[1] = type;
758 params[2] = protocol;
760 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_SOCKET, params, 12, NULL, 0));
761 if(ret>=0) // set tcp window size to 24kb
763 int window_size = 24576;
764 net_setsockopt(ret, SOL_SOCKET, SO_RCVBUF, (char *) &window_size, sizeof(window_size));
766 debug_printf("net_socket(%d, %d, %d)=%d\n", domain, type, protocol, ret);
767 return ret;
770 s32 net_shutdown(s32 s, u32 how)
772 s32 ret;
773 STACK_ALIGN(u32, params, 2, 32);
775 if (net_ip_top_fd < 0) return -ENXIO;
777 params[0] = s;
778 params[1] = how;
779 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_SHUTDOWN, params, 8, NULL, 0));
781 debug_printf("net_shutdown(%d, %d)=%d\n", s, how, ret);
782 return ret;
785 s32 net_bind(s32 s, struct sockaddr *name, socklen_t namelen)
787 s32 ret;
788 STACK_ALIGN(struct bind_params,params,1,32);
790 if (net_ip_top_fd < 0) return -ENXIO;
791 if (name->sa_family != AF_INET) return -EAFNOSUPPORT;
793 name->sa_len = 8;
795 memset(params, 0, sizeof(struct bind_params));
796 params->socket = s;
797 params->has_name = 1;
798 memcpy(params->name, name, 8);
800 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_BIND, params, sizeof (struct bind_params), NULL, 0));
801 debug_printf("net_bind(%d, %p)=%d\n", s, name, ret);
803 return ret;
806 s32 net_listen(s32 s, u32 backlog)
808 s32 ret;
809 STACK_ALIGN(u32, params, 2, 32);
811 if (net_ip_top_fd < 0) return -ENXIO;
813 params[0] = s;
814 params[1] = backlog;
816 debug_printf("calling ios_ioctl(%d, %d, %p, %d)\n", net_ip_top_fd, IOCTL_SO_SOCKET, params, 8);
818 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_LISTEN, params, 8, NULL, 0));
819 debug_printf("net_listen(%d, %d)=%d\n", s, backlog, ret);
820 return ret;
823 s32 net_accept(s32 s, struct sockaddr *addr, socklen_t *addrlen)
825 s32 ret;
826 STACK_ALIGN(u32, _socket, 1, 32);
828 debug_printf("net_accept()\n");
830 if (net_ip_top_fd < 0) return -ENXIO;
832 if (!addr) return -EINVAL;
833 addr->sa_len = 8;
834 addr->sa_family = AF_INET;
836 if (!addrlen) return -EINVAL;
838 if (*addrlen < 8) return -ENOMEM;
840 *addrlen = 8;
842 *_socket = s;
843 debug_printf("calling ios_ioctl(%d, %d, %p, %d)\n", net_ip_top_fd, IOCTL_SO_ACCEPT, _socket, 4);
844 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_ACCEPT, _socket, 4, addr, *addrlen));
846 debug_printf("net_accept(%d, %p)=%d\n", s, addr, ret);
847 return ret;
850 s32 net_connect(s32 s, struct sockaddr *addr, socklen_t addrlen)
852 s32 ret;
853 STACK_ALIGN(struct connect_params,params,1,32);
855 if (net_ip_top_fd < 0) return -ENXIO;
856 if (addr->sa_family != AF_INET) return -EAFNOSUPPORT;
857 if (addrlen < 8) return -EINVAL;
859 addr->sa_len = 8;
861 memset(params, 0, sizeof(struct connect_params));
862 params->socket = s;
863 params->has_addr = 1;
864 memcpy(&params->addr, addr, addrlen);
866 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_CONNECT, params, sizeof(struct connect_params), NULL, 0));
867 if (ret < 0)
868 debug_printf("SOConnect(%d, %p)=%d\n", s, addr, ret);
870 return ret;
873 s32 net_write(s32 s, const void *data, s32 size)
875 return net_send(s, data, size, 0);
878 s32 net_send(s32 s, const void *data, s32 size, u32 flags)
880 return net_sendto(s, data, size, flags, NULL, 0);
883 s32 net_sendto(s32 s, const void *data, s32 len, u32 flags, struct sockaddr *to, socklen_t tolen)
885 s32 ret;
886 u8 * message_buf = NULL;
887 STACK_ALIGN(struct sendto_params,params,1,32);
889 if (net_ip_top_fd < 0) return -ENXIO;
890 if (tolen > 28) return -EOVERFLOW;
892 message_buf = net_malloc(len);
893 if (message_buf == NULL) {
894 debug_printf("net_send: failed to alloc %d bytes\n", len);
895 return IPC_ENOMEM;
898 debug_printf("net_sendto(%d, %p, %d, %d, %p, %d)\n", s, data, len, flags, to, tolen);
900 if (to && to->sa_len != tolen) {
901 debug_printf("warning: to->sa_len was %d, setting to %d\n", to->sa_len, tolen);
902 to->sa_len = tolen;
905 memset(params, 0, sizeof(struct sendto_params));
906 memcpy(message_buf, data, len); // ensure message buf is aligned
908 params->socket = s;
909 params->flags = flags;
910 if (to) {
911 params->has_destaddr = 1;
912 memcpy(params->destaddr, to, to->sa_len);
913 } else {
914 params->has_destaddr = 0;
917 ret = _net_convert_error(IOS_IoctlvFormat(__net_hid, net_ip_top_fd, IOCTLV_SO_SENDTO, "dd:", message_buf, len, params, sizeof(struct sendto_params)));
918 debug_printf("net_send retuned %d\n", ret);
920 if(message_buf!=NULL) net_free(message_buf);
921 return ret;
924 s32 net_recv(s32 s, void *mem, s32 len, u32 flags)
926 return net_recvfrom(s, mem, len, flags, NULL, NULL);
929 s32 net_recvfrom(s32 s, void *mem, s32 len, u32 flags, struct sockaddr *from, socklen_t *fromlen)
931 s32 ret;
932 u8* message_buf = NULL;
933 STACK_ALIGN(u32, params, 2, 32);
935 if (net_ip_top_fd < 0) return -ENXIO;
936 if (len<=0) return -EINVAL;
938 if (fromlen && from->sa_len != *fromlen) {
939 debug_printf("warning: from->sa_len was %d, setting to %d\n",from->sa_len, *fromlen);
940 from->sa_len = *fromlen;
943 message_buf = net_malloc(len);
944 if (message_buf == NULL) {
945 debug_printf("SORecv: failed to alloc %d bytes\n", len);
946 return IPC_ENOMEM;
949 debug_printf("net_recvfrom(%d, '%s', %d, %d, %p, %d)\n", s, (char *)mem, len, flags, from, fromlen?*fromlen:0);
951 memset(message_buf, 0, len);
952 params[0] = s;
953 params[1] = flags;
955 ret = _net_convert_error(IOS_IoctlvFormat(__net_hid, net_ip_top_fd, IOCTLV_SO_RECVFROM, "d:dd", params, 8, message_buf, len, from, (fromlen?*fromlen:0)));
956 debug_printf("net_recvfrom returned %d\n", ret);
958 if (ret > 0) {
959 if (ret > len) {
960 ret = -EOVERFLOW;
961 goto done;
964 memcpy(mem, message_buf, ret);
967 if (fromlen && from) *fromlen = from->sa_len;
969 done:
970 if(message_buf!=NULL) net_free(message_buf);
971 return ret;
974 s32 net_read(s32 s, void *mem, s32 len)
976 return net_recvfrom(s, mem, len, 0, NULL, NULL);
979 s32 net_close(s32 s)
981 s32 ret;
982 STACK_ALIGN(u32, _socket, 1, 32);
984 if (net_ip_top_fd < 0) return -ENXIO;
986 *_socket = s;
987 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_CLOSE, _socket, 4, NULL, 0));
989 if (ret < 0)
990 debug_printf("net_close(%d)=%d\n", s, ret);
992 return ret;
995 s32 net_select(s32 maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout)
997 // not yet implemented
998 return -EINVAL;
1001 s32 net_setsockopt(s32 s, u32 level, u32 optname, const void *optval, socklen_t optlen)
1003 s32 ret;
1004 STACK_ALIGN(struct setsockopt_params,params,1,32);
1006 if (net_ip_top_fd < 0) return -ENXIO;
1007 if (optlen < 0 || optlen > 20) return -EINVAL;
1009 memset(params, 0, sizeof(struct setsockopt_params));
1010 params->socket = s;
1011 params->level = level;
1012 params->optname = optname;
1013 params->optlen = optlen;
1014 if (optval && optlen) memcpy (params->optval, optval, optlen);
1016 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_SETSOCKOPT, params, sizeof(struct setsockopt_params), NULL, 0));
1018 debug_printf("net_setsockopt(%d, %u, %u, %p, %d)=%d\n", s, level, optname, optval, optlen, ret);
1019 return ret;
1022 s32 net_ioctl(s32 s, u32 cmd, void *argp)
1024 u32 flags;
1025 u32 *intp = (u32 *)argp;
1027 if (net_ip_top_fd < 0) return -ENXIO;
1028 if (!intp) return -EINVAL;
1030 switch (cmd) {
1031 case FIONBIO:
1032 flags = net_fcntl(s, F_GETFL, 0);
1033 flags &= ~IOS_O_NONBLOCK;
1034 if (*intp) flags |= IOS_O_NONBLOCK;
1035 return net_fcntl(s, F_SETFL, flags);
1036 default:
1037 return -EINVAL;
1041 s32 net_fcntl(s32 s, u32 cmd, u32 flags)
1043 s32 ret;
1044 STACK_ALIGN(u32, params, 3, 32);
1046 if (net_ip_top_fd < 0) return -ENXIO;
1047 if (cmd != F_GETFL && cmd != F_SETFL) return -EINVAL;
1050 params[0] = s;
1051 params[1] = cmd;
1052 params[2] = flags;
1054 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_FCNTL, params, 12, NULL, 0));
1056 debug_printf("net_fcntl(%d, %d, %x)=%d\n", params[0], params[1], params[2], ret);
1058 return ret;
1063 * \fn s32 net_poll(struct pollsd *sds, u32 nsds, s64 timeout)
1064 * \brief Poll a set of sockets for a set of events.
1066 * \param[in] sds a pointer to an array of pollsd structures
1067 * \param[in] nsds the number of elements in the sds array
1068 * \param[in] time in milliseconds before the function should timeout
1070 * \return the number of structures in sds that now have non-zero revent fields
1072 s32 net_poll(struct pollsd *sds,s32 nsds,s32 timeout)
1074 union ullc {
1075 u64 ull;
1076 u32 ul[2];
1079 s32 ret;
1080 union ullc outv;
1081 struct pollsd *psds;
1082 STACK_ALIGN(u64,params,1,32);
1084 if(net_ip_top_fd<0) return -ENXIO;
1085 if(sds==NULL || nsds==0) return -EINVAL;
1087 psds = net_malloc((nsds*sizeof(struct pollsd)));
1088 if(psds==NULL) {
1089 debug_printf("net_poll: failed to alloc %d bytes\n", nsds * sizeof(struct pollsd));
1090 return IPC_ENOMEM;
1093 outv.ul[0] = 0;
1094 outv.ul[1] = timeout;
1095 params[0] = outv.ull;
1096 memcpy(psds,sds,(nsds*sizeof(struct pollsd)));
1098 ret = _net_convert_error(IOS_Ioctl(net_ip_top_fd, IOCTL_SO_POLL, params, 8, psds, (nsds * sizeof(struct pollsd))));
1100 memcpy(sds,psds,(nsds*sizeof(struct pollsd)));
1102 net_free(psds);
1104 debug_printf("net_poll(sds, %d, %lld)=%d\n", nsds, params[0], ret);
1106 return ret;
1109 s32 if_config(char *local_ip, char *netmask, char *gateway,bool use_dhcp)
1111 s32 i,ret;
1112 struct in_addr hostip;
1114 if (!use_dhcp)
1115 return -EINVAL;
1117 for (i = 0; i < MAX_INIT_RETRIES; ++i) {
1118 ret = net_init();
1120 if ((ret != -EAGAIN) && (ret != -ETIMEDOUT))
1121 break;
1123 usleep(50 * 1000);
1126 if (ret < 0)
1127 return ret;
1129 hostip.s_addr = net_gethostip();
1130 if (local_ip && hostip.s_addr) {
1131 strcpy(local_ip, inet_ntoa(hostip));
1132 return 0;
1135 return -1;
1138 s32 if_configex(struct in_addr *local_ip, struct in_addr *netmask, struct in_addr *gateway,bool use_dhcp)
1140 s32 i,ret;
1141 struct in_addr hostip;
1143 if (!use_dhcp)
1144 return -EINVAL;
1146 for (i = 0; i < MAX_INIT_RETRIES; ++i) {
1147 ret = net_init();
1149 if ((ret != -EAGAIN) && (ret != -ETIMEDOUT))
1150 break;
1152 usleep(50 * 1000);
1155 if (ret < 0)
1156 return ret;
1158 hostip.s_addr = net_gethostip();
1159 if (local_ip && hostip.s_addr) {
1160 *local_ip = hostip;
1161 return 0;
1164 return -1;
1167 #endif /* defined(HW_RVL) */