Fix win32 compile
[olsrd.git] / src / win32 / net.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #if defined WINCE
43 #include <sys/types.h>          // for time_t
44 #endif
45
46 #define WIN32_LEAN_AND_MEAN
47 #include <windows.h>
48 #include <winsock2.h>
49 #include <ws2tcpip.h>
50 #include <iphlpapi.h>
51 #undef interface
52
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <errno.h>
56
57 #include "defs.h"
58 #include "os_net.h"
59 #include "os_system.h"
60 #include "net_olsr.h"
61 #include "ipcalc.h"
62 #include "olsr_logging.h"
63 #include "win32/compat.h"
64 #include "os_system.h"
65 #if defined WINCE
66 #define WIDE_STRING(s) L##s
67 #else
68 #define WIDE_STRING(s) s
69 #endif
70
71 void WinSockPError(const char *Str);
72 void PError(const char *);
73
74 static void DisableIcmpRedirects(void);
75
76 /**
77  * Argument preprocessor
78  * @param argc
79  * @param argv
80  */
81 void
82 os_arg(int *argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) {
83   return;
84 }
85
86 /**
87  * Wrapper for exit call
88  * @param ret return value
89  */
90 void  __attribute__((noreturn))
91 os_exit(int ret) {
92   exit(ret);
93 }
94
95 /**
96  * Wrapper for closing sockets
97  * @param
98  * @param sock
99  * @return
100  */
101 int
102 os_close(int sock) {
103   return os_close(sock);
104 }
105
106 int
107 os_socket_set_nonblocking(int fd)
108 {
109   /* make the fd non-blocking */
110   unsigned long flags = 1;
111   if (ioctlsocket(fd, FIONBIO, &flags) != 0) {
112     OLSR_WARN(LOG_NETWORKING, "Cannot set the socket flags: %s", win32_strerror(WSAGetLastError()));
113     return -1;
114   }
115   return 0;
116 }
117
118 int
119 os_getsocket4(const char *if_name __attribute__ ((unused)), uint16_t port, int bufspace, union olsr_sockaddr *bindto)
120 {
121   struct sockaddr_in Addr;
122   int On = 1;
123   unsigned long Len;
124   int Sock = socket(AF_INET, SOCK_DGRAM, 0);
125   if (Sock < 0) {
126     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
127     olsr_exit(EXIT_FAILURE);
128   }
129
130   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
131     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
132     os_close(Sock);
133     olsr_exit(EXIT_FAILURE);
134   }
135
136   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
137     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
138     os_close(Sock);
139     olsr_exit(EXIT_FAILURE);
140   }
141
142   while (bufspace > 8192) {
143     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
144       break;
145
146     bufspace -= 1024;
147   }
148
149   if (bufspace <= 8192)
150     OLSR_WARN(LOG_NETWORKING, "Cannot set IPv4 socket receive buffer.\n");
151
152   if (bindto == NULL) {
153     memset(&Addr, 0, sizeof(Addr));
154     Addr.sin_family = AF_INET;
155     Addr.sin_port = htons(port);
156     Addr.sin_addr.s_addr = INADDR_ANY;
157
158     bindto = (union olsr_sockaddr *)&Addr;
159   }
160
161   if (bind(Sock, &bindto->std, sizeof(Addr)) < 0) {
162     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
163     os_close(Sock);
164     olsr_exit(EXIT_FAILURE);
165   }
166
167   if (WSAIoctl(Sock, FIONBIO, &On, sizeof(On), NULL, 0, &Len, NULL, NULL) < 0) {
168     OLSR_ERROR(LOG_NETWORKING, "WSAIoctl");
169     os_close(Sock);
170     olsr_exit(EXIT_FAILURE);
171   }
172
173   return Sock;
174 }
175
176 int
177 os_getsocket6(const char *if_name __attribute__ ((unused)), uint16_t port, int bufspace, union olsr_sockaddr *bindto)
178 {
179   struct sockaddr_in6 Addr6;
180   int On = 1;
181   int Sock = socket(AF_INET6, SOCK_DGRAM, 0);
182   if (Sock < 0) {
183     OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno));
184     olsr_exit(EXIT_FAILURE);
185   }
186
187   if (setsockopt(Sock, SOL_SOCKET, SO_BROADCAST, (char *)&On, sizeof(On)) < 0) {
188     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
189     os_close(Sock);
190     olsr_exit(EXIT_FAILURE);
191   }
192
193   if (setsockopt(Sock, SOL_SOCKET, SO_REUSEADDR, (char *)&On, sizeof(On)) < 0) {
194     OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno));
195     os_close(Sock);
196     olsr_exit(EXIT_FAILURE);
197   }
198
199   while (bufspace > 8192) {
200     if (setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char *)&bufspace, sizeof(bufspace)) == 0)
201       break;
202
203     bufspace -= 1024;
204   }
205
206   if (bufspace <= 8192)
207     OLSR_WARN(LOG_NETWORKING, "Cannot set IPv6 socket receive buffer.\n");
208
209   if (bindto == NULL) {
210     memset(&Addr6, 0, sizeof(Addr6));
211     Addr6.sin6_family = AF_INET6;
212     Addr6.sin6_port = htons(port);
213     bindto = (union olsr_sockaddr *)&Addr6;
214   }
215
216   if (bind(Sock, &bindto->std, sizeof(Addr6)) < 0) {
217     OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to device (%s)\n", strerror(errno));
218     os_close(Sock);
219     olsr_exit(EXIT_FAILURE);
220   }
221
222   return Sock;
223 }
224
225 static int
226 join_mcast(struct interface *Nic, int Sock, union olsr_sockaddr *mcast)
227 {
228   /* See linux/in6.h */
229   struct ipaddr_str buf;
230   struct ipv6_mreq McastReq;
231
232   McastReq.ipv6mr_multiaddr = mcast->v6.sin6_addr;
233   McastReq.ipv6mr_interface = Nic->if_index;
234
235   OLSR_DEBUG(LOG_NETWORKING, "Interface %s joining multicast %s...", Nic->int_name,
236              olsr_ip_to_string(&buf, (union olsr_ip_addr *)&Nic->int_multicast.v6.sin6_addr));
237   /* Send multicast */
238   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&McastReq, sizeof(struct ipv6_mreq))
239       < 0) {
240     OLSR_WARN(LOG_NETWORKING, "Join multicast: %s\n", strerror(errno));
241     return -1;
242   }
243
244   /* Old libc fix */
245 #ifdef IPV6_JOIN_GROUP
246   /* Join reciever group */
247   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&McastReq, sizeof(struct ipv6_mreq))
248       < 0)
249 #else
250   /* Join reciever group */
251   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&McastReq, sizeof(struct ipv6_mreq))
252       < 0)
253 #endif
254   {
255     OLSR_WARN(LOG_NETWORKING, "Join multicast send: %s\n", strerror(errno));
256     return -1;
257   }
258
259
260   if (setsockopt(Sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&McastReq.ipv6mr_interface, sizeof(McastReq.ipv6mr_interface))
261       < 0) {
262     OLSR_WARN(LOG_NETWORKING, "Join multicast if: %s\n", strerror(errno));
263     return -1;
264   }
265
266   return 0;
267 }
268
269 void
270 os_socket_set_olsr_options(struct interface *ifs,
271     int sock, union olsr_sockaddr *mcast) {
272   join_mcast(ifs, sock, mcast);
273 }
274
275 static int
276 SetEnableRedirKey(unsigned long New)
277 {
278 #if !defined WINCE
279   HKEY Key;
280   unsigned long Type;
281   unsigned long Len;
282   unsigned long Old;
283
284   if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
285                    "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ | KEY_WRITE, &Key) != ERROR_SUCCESS)
286     return -1;
287
288   Len = sizeof(Old);
289
290   if (RegQueryValueEx(Key, "EnableICMPRedirect", NULL, &Type, (unsigned char *)&Old, &Len) != ERROR_SUCCESS || Type != REG_DWORD)
291     Old = 1;
292
293   if (RegSetValueEx(Key, "EnableICMPRedirect", 0, REG_DWORD, (unsigned char *)&New, sizeof(New))) {
294     RegCloseKey(Key);
295     return -1;
296   }
297
298   RegCloseKey(Key);
299   return Old;
300 #else
301   return 0;
302 #endif
303 }
304
305 static void
306 DisableIcmpRedirects(void)
307 {
308   int Res;
309
310   Res = SetEnableRedirKey(0);
311
312   if (Res != 1)
313     return;
314
315   OLSR_ERROR(LOG_NETWORKING, "\n*** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT *** IMPORTANT ***\n\n");
316
317 #if 0
318   if (Res < 0) {
319     OLSR_ERROR(LOG_NETWORKING, "Cannot disable ICMP redirect processing in the registry.\n");
320     OLSR_ERROR(LOG_NETWORKING, "Please disable it manually. Continuing in 3 seconds...\n");
321     Sleep(3000);
322
323     return;
324   }
325 #endif
326
327   OLSR_ERROR(LOG_NETWORKING, "I have disabled ICMP redirect processing in the registry for you.\n");
328   OLSR_ERROR(LOG_NETWORKING, "REBOOT NOW, so that these changes take effect. Exiting...\n\n");
329
330   exit(0);
331 }
332
333 static OVERLAPPED RouterOver;
334
335 /* enable IP forwarding */
336 void os_init(void)
337 {
338   HMODULE Lib;
339   unsigned int __stdcall(*EnableRouterFunc) (HANDLE * Hand, OVERLAPPED * Over);
340   HANDLE Hand;
341
342   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
343
344   if (Lib == NULL)
345     return;
346
347   EnableRouterFunc = (unsigned int __stdcall(*)(HANDLE *, OVERLAPPED *))
348     GetProcAddress(Lib, WIDE_STRING("EnableRouter"));
349
350   if (EnableRouterFunc == NULL)
351     return;
352
353   memset(&RouterOver, 0, sizeof(OVERLAPPED));
354
355   RouterOver.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
356
357   if (RouterOver.hEvent == NULL) {
358     OLSR_WARN(LOG_NETWORKING, "CreateEvent()");
359     return;
360   }
361
362   if (EnableRouterFunc(&Hand, &RouterOver) != ERROR_IO_PENDING) {
363     OLSR_WARN(LOG_NETWORKING, "EnableRouter()");
364     return;
365   }
366
367   OLSR_DEBUG(LOG_NETWORKING, "Routing enabled.\n");
368
369   DisableIcmpRedirects();
370
371   return;
372 }
373
374 /**
375  * disable IP forwarding
376  */
377 void os_cleanup(void) {
378   HMODULE Lib;
379   unsigned int __stdcall(*UnenableRouterFunc) (OVERLAPPED * Over, unsigned int *Count);
380   unsigned int Count;
381
382   Lib = LoadLibrary(WIDE_STRING("iphlpapi.dll"));
383
384   if (Lib == NULL)
385     return;
386
387   UnenableRouterFunc = (unsigned int __stdcall(*)(OVERLAPPED *, unsigned int *))
388     GetProcAddress(Lib, WIDE_STRING("UnenableRouter"));
389
390   if (UnenableRouterFunc == NULL)
391     return;
392
393   if (UnenableRouterFunc(&RouterOver, &Count) != NO_ERROR) {
394     OLSR_WARN(LOG_NETWORKING, "UnenableRouter()");
395     return;
396   }
397
398   OLSR_DEBUG(LOG_NETWORKING, "Routing disabled, count = %u.\n", Count);
399 }
400
401 /**
402  * Wrapper for sendto(2)
403  */
404
405 ssize_t
406 os_sendto(int s, const void *buf, size_t len, int flags, const union olsr_sockaddr *sock)
407 {
408   return sendto(s, buf, len, flags, &sock->std, sizeof(*sock));
409 }
410
411
412 /**
413  * Wrapper for recvfrom(2)
414  */
415
416 ssize_t
417 os_recvfrom(int s, void *buf, size_t len, int flags __attribute__ ((unused)), union olsr_sockaddr *sock, socklen_t * fromlen)
418 {
419   return recvfrom(s, buf, len, 0, &sock->std, fromlen);
420 }
421
422 /**
423  * Wrapper for select(2)
424  */
425
426 int
427 os_select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
428 {
429   return select(nfds, readfds, writefds, exceptfds, timeout);
430 }
431
432 /*
433  * Local Variables:
434  * c-basic-offset: 2
435  * indent-tabs-mode: nil
436  * End:
437  */