We can now tell WLAN interfaces from wired interfaces on Windows.
[olsrd.git] / src / win32 / ifnet.c
1 /*
2  * Functions for the Windows port
3  * Copyright (C) 2004 Thomas Lopatic (thomas@lopatic.de)
4  *
5  * Derived from their Linux counterparts
6  * Copyright (C) 2003 Andreas T√łnnesen (andreto@ifi.uio.no)
7  *
8  * This file is part of olsrd-unik.
9  *
10  * olsrd-unik is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * olsrd-unik is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with olsrd-unik; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  */
25
26 #include "../interfaces.h"
27 #include "../olsr.h"
28 #include "../net.h"
29 #include "../parser.h"
30 #include "../socket_parser.h"
31
32 #include <iphlpapi.h>
33 #include <iprtrmib.h>
34
35 void WinSockPError(char *);
36 char *StrError(unsigned int ErrNo);
37 int inet_pton(int af, char *src, void *dst);
38
39 #define MAX_INTERFACES 25
40
41 int __stdcall SignalHandler(unsigned long Signal);
42
43 static unsigned long __stdcall SignalHandlerWrapper(void *Dummy)
44 {
45   SignalHandler(0);
46   return 0;
47 }
48
49 static void CallSignalHandler(void)
50 {
51   unsigned long ThreadId;
52
53   CreateThread(NULL, 0, SignalHandlerWrapper, NULL, 0, &ThreadId);
54 }
55
56 static void MiniIndexToIntName(char *String, int MiniIndex)
57 {
58   char *HexDigits = "0123456789abcdef";
59
60   String[0] = 'i';
61   String[1] = 'f';
62
63   String[2] = HexDigits[(MiniIndex >> 4) & 15];
64   String[3] = HexDigits[MiniIndex & 15];
65
66   String[4] = 0;
67 }
68
69 static int IntNameToMiniIndex(int *MiniIndex, char *String)
70 {
71   char *HexDigits = "0123456789abcdef";
72   int i, k;
73   char ch;
74
75   if ((String[0] != 'i' && String[0] != 'I') ||
76       (String[1] != 'f' && String[1] != 'F'))
77     return -1;
78
79   *MiniIndex = 0;
80
81   for (i = 2; i < 4; i++)
82   {
83     ch = String[i];
84
85     if (ch >= 'A' && ch <= 'F')
86       ch += 32;
87
88     for (k = 0; k < 16 && ch != HexDigits[k]; k++);
89
90     if (k == 16)
91       return -1;
92
93     *MiniIndex = (*MiniIndex << 4) | k;
94   }
95
96   return 0;
97 }
98
99 static int MiniIndexToGuid(char *Guid, int MiniIndex)
100 {
101   IP_ADAPTER_INFO AdInfo[MAX_INTERFACES], *Walker;
102   unsigned long AdInfoLen;
103   unsigned long Res;
104   
105   if (ipversion == AF_INET6)
106   {
107     fprintf(stderr, "IPv6 not supported by MiniIndexToGuid()!\n");
108     return -1;
109   }
110
111   AdInfoLen = sizeof (AdInfo);
112
113   Res = GetAdaptersInfo(AdInfo, &AdInfoLen);
114
115   if (Res != NO_ERROR)
116   {
117     fprintf(stderr, "GetAdaptersInfo() = %08lx, %s", GetLastError(),
118             StrError(Res));
119     return -1;
120   }
121
122   for (Walker = AdInfo; Walker != NULL; Walker = Walker->Next)
123   {
124     olsr_printf(5, "Index = %08x\n", Walker->Index);
125
126     if ((Walker->Index & 255) == MiniIndex)
127       break;
128   }
129
130   if (Walker != NULL)
131   {
132     olsr_printf(5, "Found interface.\n");
133
134     strcpy(Guid, Walker->AdapterName);
135     return 0;
136   }
137
138   olsr_printf(5, "Cannot map mini index %02x to an adapter GUID.\n",
139               MiniIndex);
140   return -1;
141 }
142
143 static int AddrToIndex(int *Index, unsigned int Addr)
144 {
145   unsigned int IntAddr;
146   IP_ADAPTER_INFO AdInfo[MAX_INTERFACES], *Walker;
147   unsigned long AdInfoLen;
148   IP_ADDR_STRING *Walker2;
149   unsigned long Res;
150   
151   olsr_printf(5, "AddrToIndex(%08x)\n", Addr);
152
153   if (ipversion == AF_INET6)
154   {
155     fprintf(stderr, "IPv6 not supported by AddrToIndex()!\n");
156     return -1;
157   }
158
159   AdInfoLen = sizeof (AdInfo);
160
161   Res = GetAdaptersInfo(AdInfo, &AdInfoLen);
162
163   if (Res != NO_ERROR)
164   {
165     fprintf(stderr, "GetAdaptersInfo() = %08lx, %s", Res, StrError(Res));
166     return -1;
167   }
168
169   for (Walker = AdInfo; Walker != NULL; Walker = Walker->Next)
170   {
171     olsr_printf(5, "Index = %08x\n", Walker->Index);
172
173     for (Walker2 = &Walker->IpAddressList; Walker2 != NULL;
174          Walker2 = Walker2->Next)
175     {
176       inet_pton(AF_INET, Walker2->IpAddress.String, &IntAddr);
177
178       olsr_printf(5, "\tIP address = %08x\n", IntAddr);
179
180       if (Addr == IntAddr)
181       {
182         olsr_printf(5, "Found interface.\n");
183         *Index = Walker->Index;
184         return 0;
185       }
186     }
187   }
188
189   olsr_printf(5, "Cannot map IP address %08x to an adapter index.\n", Addr);
190   return -1;
191 }
192
193 #if !defined OID_802_11_CONFIGURATION
194 #define OID_802_11_CONFIGURATION 0x0d010211
195 #endif
196
197 #if !defined IOCTL_NDIS_QUERY_GLOBAL_STATS
198 #define IOCTL_NDIS_QUERY_GLOBAL_STATS 0x00170002
199 #endif
200
201 static int IsWireless(char *IntName)
202 {
203   int MiniIndex;
204   char DevName[43];
205   HANDLE DevHand;
206   unsigned int ErrNo;
207   unsigned int Oid;
208   unsigned char OutBuff[100];
209   unsigned long OutBytes;
210
211   if (IntNameToMiniIndex(&MiniIndex, IntName) < 0)
212     return -1;
213
214   DevName[0] = '\\';
215   DevName[1] = '\\';
216   DevName[2] = '.';
217   DevName[3] = '\\';
218
219   if (MiniIndexToGuid(DevName + 4, MiniIndex) < 0)
220     return -1;
221
222   olsr_printf(5, "Checking whether interface %s is wireless.\n", DevName);
223
224   DevHand = CreateFile(DevName, GENERIC_READ,
225                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
226                        FILE_ATTRIBUTE_NORMAL, NULL);
227
228   if (DevHand == INVALID_HANDLE_VALUE)
229   {
230     ErrNo = GetLastError();
231
232     olsr_printf(5, "CreateFile() = %08lx, %s\n", ErrNo, StrError(ErrNo));
233     return -1;
234   }
235
236   Oid = OID_802_11_CONFIGURATION;
237
238   if (!DeviceIoControl(DevHand, IOCTL_NDIS_QUERY_GLOBAL_STATS,
239                        &Oid, sizeof (Oid),
240                        OutBuff, sizeof (OutBuff),
241                        &OutBytes, NULL))
242   {
243     ErrNo = GetLastError();
244
245     CloseHandle(DevHand);
246
247     if (ErrNo == ERROR_GEN_FAILURE)
248     {
249       olsr_printf(5, "OID not supported. Device probably not wireless.\n");
250       return 0;
251     }
252
253     olsr_printf(5, "DeviceIoControl() = %08lx, %s\n", ErrNo, StrError(ErrNo));
254     return -1;
255   }
256
257   CloseHandle(DevHand);
258   return 1;
259 }
260
261 void ListInterfaces(void)
262 {
263   IP_ADAPTER_INFO AdInfo[MAX_INTERFACES], *Walker;
264   unsigned long AdInfoLen;
265   char IntName[5];
266   IP_ADDR_STRING *Walker2;
267   unsigned long Res;
268   int IsWlan;
269   
270   if (ipversion == AF_INET6)
271   {
272     fprintf(stderr, "IPv6 not supported by ListInterfaces()!\n");
273     return;
274   }
275
276   AdInfoLen = sizeof (AdInfo);
277
278   Res = GetAdaptersInfo(AdInfo, &AdInfoLen);
279
280   if (Res == ERROR_NO_DATA)
281   {
282     printf("No interfaces detected.\n");
283     return;
284   }
285   
286   if (Res != NO_ERROR)
287   {
288     fprintf(stderr, "GetAdaptersInfo() = %08lx, %s", Res, StrError(Res));
289     return;
290   }
291
292   for (Walker = AdInfo; Walker != NULL; Walker = Walker->Next)
293   {
294     olsr_printf(5, "Index = %08x\n", Walker->Index);
295
296     MiniIndexToIntName(IntName, Walker->Index);
297
298     printf("%s: ", IntName);
299
300     IsWlan = IsWireless(IntName);
301
302     if (IsWlan < 0)
303       printf("?");
304
305     else if (IsWlan == 0)
306       printf("-");
307
308     else
309       printf("+");
310
311     for (Walker2 = &Walker->IpAddressList; Walker2 != NULL;
312          Walker2 = Walker2->Next)
313       printf(" %s", Walker2->IpAddress.String);
314
315     printf("\n");
316   }
317 }
318
319 int InterfaceInfo(INTERFACE_INFO *IntPara, int *Index, struct if_name *IntName)
320 {
321   int MiniIndex;
322   int Sock;
323   INTERFACE_INFO IntInfo[25];
324   long Num;
325   int WsIdx;
326   int CandIndex;
327
328   if (IntNameToMiniIndex(&MiniIndex, IntName->name) < 0)
329   {
330     fprintf(stderr, "No such interface: %s!\n", IntName->name);
331     return -1;
332   }
333
334   Sock = socket(ipversion, SOCK_STREAM, IPPROTO_TCP);
335
336   if (Sock < 0)
337   {
338     WinSockPError("socket()");
339     return -1;
340   }
341
342   if (WSAIoctl(Sock, SIO_GET_INTERFACE_LIST, NULL, 0,
343                IntInfo, sizeof (IntInfo), &Num, NULL, NULL) < 0)
344   {
345     WinSockPError("WSAIoctl(SIO_GET_INTERFACE_LIST)");
346     closesocket(Sock);
347     return -1;
348   }
349
350   closesocket(Sock);
351
352   Num /= sizeof (INTERFACE_INFO);
353
354   olsr_printf(5, "%s:\n", IntName->name);
355
356   for (WsIdx = 0; WsIdx < Num; WsIdx++)
357   {
358     if (AddrToIndex(&CandIndex,
359                     IntInfo[WsIdx].iiAddress.AddressIn.sin_addr.s_addr) < 0)
360       continue;
361
362     if ((CandIndex & 255) == MiniIndex)
363       break;
364   }
365
366   if (WsIdx == Num)
367   {
368     fprintf(stderr, "No such interface: %s!\n", IntName->name);
369     return -1;
370   }
371     
372   *Index = CandIndex;
373
374   olsr_printf(5, "\tIndex: %08x\n", *Index);
375
376   olsr_printf(5, "\tFlags: %08x\n", IntInfo[WsIdx].iiFlags);
377
378   if ((IntInfo[WsIdx].iiFlags & IFF_UP) == 0)
379   {
380     olsr_printf(1, "\tInterface not up - skipping it...\n");
381     return -1;
382   }
383
384   if (ipversion == AF_INET && (IntInfo[WsIdx].iiFlags & IFF_BROADCAST) == 0)
385   {
386     olsr_printf(1, "\tNo broadcast - skipping it...\n");
387     return -1;
388   }
389
390   if ((IntInfo[WsIdx].iiFlags & IFF_LOOPBACK) != 0)
391   {
392     olsr_printf(1, "\tThis is a loopback interface - skipping it...\n");
393     return -1;
394   }
395
396   // Windows seems to always return 255.255.255.255 as broadcast
397   // address, so I've tried using (address | ~netmask).
398
399   {
400     struct sockaddr_in *sin_a, *sin_n, *sin_b;
401     unsigned int a, n, b;
402
403     sin_a = (struct sockaddr_in *)&IntInfo[WsIdx].iiAddress;
404     sin_n = (struct sockaddr_in *)&IntInfo[WsIdx].iiNetmask;
405     sin_b = (struct sockaddr_in *)&IntInfo[WsIdx].iiBroadcastAddress;
406
407     a = sin_a->sin_addr.s_addr;
408     n = sin_n->sin_addr.s_addr;
409     b = sin_b->sin_addr.s_addr =
410       sin_a->sin_addr.s_addr | ~sin_n->sin_addr.s_addr;
411   }
412
413   memcpy(IntPara, &IntInfo[WsIdx], sizeof (INTERFACE_INFO));
414   return 0;
415 }
416
417 void RemoveInterface(struct if_name *IntName)
418 {
419   struct interface *Int, *Prev;
420   struct ifchgf *Walker;
421
422   olsr_printf(1, "Removing interface %s.\n", IntName->name);
423   
424   Int = IntName->interf;
425
426   for (Walker = ifchgf_list; Walker != NULL; Walker = Walker->next)
427     Walker->function(Int, IFCHG_IF_REMOVE);
428
429   if (Int == ifnet)
430     ifnet = Int->int_next;
431
432   else
433   {
434     for (Prev = ifnet; Prev->int_next != Int; Prev = Prev->int_next);
435
436     Prev->int_next = Int->int_next;
437   }
438
439   if(COMP_IP(&main_addr, &Int->ip_addr))
440   {
441     if(ifnet == NULL)
442     {
443       memset(&main_addr, 0, ipsize);
444       olsr_printf(1, "Removed last interface. Cleared main address.\n");
445     }
446
447     else
448     {
449       COPY_IP(&main_addr, &ifnet->ip_addr);
450       olsr_printf(1, "New main address: %s.\n", olsr_ip_to_string(&main_addr));
451     }
452   }
453
454   nbinterf--;
455
456   IntName->configured = 0;
457   IntName->interf = NULL;
458
459   closesocket(Int->olsr_socket);
460   remove_olsr_socket(Int->olsr_socket, &olsr_input);
461
462   free(Int->int_name);
463   free(Int);
464
465   if(nbinterf == 0 && !allow_no_int)
466   {
467     olsr_printf(1, "No more active interfaces - exiting.\n");
468     exit_value = EXIT_FAILURE;
469     CallSignalHandler();
470   }
471 }
472
473 int chk_if_changed(struct if_name *IntName)
474 {
475   struct interface *Int;
476   INTERFACE_INFO IntInfo;
477   int Index;
478   int Res;
479   union olsr_ip_addr OldVal, NewVal;
480   struct ifchgf *Walker;
481
482   if (ipversion == AF_INET6)
483   {
484     fprintf(stderr, "IPv6 not supported by chk_if_changed()!\n");
485     return 0;
486   }
487
488 #ifdef DEBUG
489   olsr_printf(3, "Checking if %s is set down or changed\n", IntName->name);
490 #endif
491
492   Int = IntName->interf;
493
494   if (InterfaceInfo(&IntInfo, &Index, IntName) < 0)
495   {
496     RemoveInterface(IntName);
497     return 1;
498   }
499
500   Res = 0;
501
502   OldVal.v4 = ((struct sockaddr_in *)&Int->int_addr)->sin_addr.s_addr;
503   NewVal.v4 = ((struct sockaddr_in *)&IntInfo.iiAddress)->sin_addr.s_addr;
504
505 #ifdef DEBUG
506   olsr_printf(3, "\tAddress: %s\n", olsr_ip_to_string(&NewVal));
507 #endif
508
509   if(NewVal.v4 != OldVal.v4)
510   {
511     olsr_printf(1, "\tAddress change.\n");
512     olsr_printf(1, "\tOld: %s\n", olsr_ip_to_string(&OldVal));
513     olsr_printf(1, "\tNew: %s\n", olsr_ip_to_string(&NewVal));
514
515     Int->ip_addr.v4 = NewVal.v4;
516
517     memcpy(&Int->int_addr, &IntInfo.iiAddress, sizeof (struct sockaddr_in));
518
519     if (main_addr.v4 == OldVal.v4)
520     {
521       olsr_printf(1, "\tMain address change.\n");
522
523       main_addr.v4 = NewVal.v4;
524     }
525
526     Res = 1;
527   }
528
529   else
530     olsr_printf(3, "\tNo address change.\n");
531
532   OldVal.v4 = ((struct sockaddr_in *)&Int->int_netmask)->sin_addr.s_addr;
533   NewVal.v4 = ((struct sockaddr_in *)&IntInfo.iiNetmask)->sin_addr.s_addr;
534
535 #ifdef DEBUG
536   olsr_printf(3, "\tNetmask: %s\n", olsr_ip_to_string(&NewVal));
537 #endif
538
539   if(NewVal.v4 != OldVal.v4)
540   {
541     olsr_printf(1, "\tNetmask change.\n");
542     olsr_printf(1, "\tOld: %s\n", olsr_ip_to_string(&OldVal));
543     olsr_printf(1, "\tNew: %s\n", olsr_ip_to_string(&NewVal));
544
545     memcpy(&Int->int_netmask, &IntInfo.iiNetmask, sizeof (struct sockaddr_in));
546
547     Res = 1;
548   }
549
550   else
551     olsr_printf(3, "\tNo netmask change.\n");
552
553   OldVal.v4 = ((struct sockaddr_in *)&Int->int_broadaddr)->sin_addr.s_addr;
554   NewVal.v4 =
555     ((struct sockaddr_in *)&IntInfo.iiBroadcastAddress)->sin_addr.s_addr;
556
557 #ifdef DEBUG
558   olsr_printf(3, "\tBroadcast address: %s\n", olsr_ip_to_string(&NewVal));
559 #endif
560
561   if(NewVal.v4 != OldVal.v4)
562   {
563     olsr_printf(1, "\tBroadcast address change.\n");
564     olsr_printf(1, "\tOld: %s\n", olsr_ip_to_string(&OldVal));
565     olsr_printf(1, "\tNew: %s\n", olsr_ip_to_string(&NewVal));
566
567     memcpy(&Int->int_broadaddr, &IntInfo.iiBroadcastAddress,
568            sizeof (struct sockaddr_in));
569
570     Res = 1;
571   }
572
573   else
574     olsr_printf(3, "\tNo broadcast address change.\n");
575
576   if (Res != 0)
577     for (Walker = ifchgf_list; Walker != NULL; Walker = Walker->next)
578       Walker->function(Int, IFCHG_IF_UPDATE);
579
580   return Res;
581 }
582
583 int chk_if_up(struct if_name *IntName, int DebugLevel)
584 {
585   struct interface *New;
586   union olsr_ip_addr NullAddr;
587   INTERFACE_INFO IntInfo;
588   int Index;
589   unsigned int AddrSockAddr;
590   struct ifchgf *Walker;
591   int IsWlan;
592   
593   if (ipversion == AF_INET6)
594   {
595     fprintf(stderr, "IPv6 not supported by chk_if_up()!\n");
596     return 0;
597   }
598
599   if (InterfaceInfo(&IntInfo, &Index, IntName) < 0)
600     return 0;
601
602   New = olsr_malloc(sizeof (struct interface), "Interface 1");
603       
604   memcpy(&New->int_addr, &IntInfo.iiAddress, sizeof (struct sockaddr_in));
605
606   memcpy(&New->int_netmask, &IntInfo.iiNetmask, sizeof (struct sockaddr_in));
607
608   memcpy(&New->int_broadaddr, &IntInfo.iiBroadcastAddress,
609          sizeof (struct sockaddr_in));
610
611   New->int_metric = 1;
612   New->int_flags = IntInfo.iiFlags;
613
614   New->int_name = olsr_malloc(strlen (IntName->name) + 1, "Interface 2");
615   strcpy(New->int_name, IntName->name);
616
617   New->if_nr = IntName->index;
618
619   IsWlan = IsWireless(IntName->name);
620
621   if (IsWlan < 0)
622     New->is_wireless = 1;
623
624   else
625     New->is_wireless = IsWlan;
626
627   New->olsr_seqnum = random() & 0xffff;
628     
629   olsr_printf(1, "\tInterface %s set up for use with index %d\n\n",
630               IntName->name, New->if_nr);
631       
632   olsr_printf(1, "\tAddress: %s\n", sockaddr_to_string(&New->int_addr));
633   olsr_printf(1, "\tNetmask: %s\n", sockaddr_to_string(&New->int_netmask));
634   olsr_printf(1, "\tBroadcast address: %s\n",
635               sockaddr_to_string(&New->int_broadaddr));
636
637   New->ip_addr.v4 =
638     ((struct sockaddr_in *)&New->int_addr)->sin_addr.s_addr;
639       
640   New->if_index = Index;
641
642   olsr_printf(3, "\tKernel index: %08x\n", New->if_index);
643
644   AddrSockAddr = addrsock.sin_addr.s_addr;
645   addrsock.sin_addr.s_addr = New->ip_addr.v4;
646
647   New->olsr_socket = getsocket((struct sockaddr *)&addrsock,
648                                bufspace, New->int_name);
649       
650   addrsock.sin_addr.s_addr = AddrSockAddr;
651
652   if (New->olsr_socket < 0)
653   {
654     fprintf(stderr, "Could not initialize socket... exiting!\n\n");
655     exit(1);
656   }
657
658   add_olsr_socket(New->olsr_socket, &olsr_input);
659
660   New->int_next = ifnet;
661   ifnet = New;
662
663   IntName->interf = New;
664   IntName->configured = 1;
665
666   nbinterf++;
667
668   memset(&NullAddr, 0, ipsize);
669   
670   if(COMP_IP(&NullAddr, &main_addr))
671   {
672     COPY_IP(&main_addr, &New->ip_addr);
673
674     olsr_printf(1, "New main address: %s\n", olsr_ip_to_string(&main_addr));
675   }
676
677   for (Walker = ifchgf_list; Walker != NULL; Walker = Walker->next)
678     Walker->function(New, IFCHG_IF_ADD);
679
680   return 1;
681 }
682
683 void check_interface_updates()
684 {
685   struct if_name *tmp_if;
686
687 #ifdef DEBUG
688   olsr_printf(3, "Checking for updates in the interface set\n");
689 #endif
690
691   for(tmp_if = if_names; tmp_if != NULL; tmp_if = tmp_if->next)
692   {
693     if(tmp_if->configured)    
694       chk_if_changed(tmp_if);
695
696     else
697       chk_if_up(tmp_if, 3);
698   }
699 }