Add a bit of defensive programming
[reactos.git] / reactos / services / dhcp / adapter.c
1 #include "rosdhcp.h"
2
3 static SOCKET DhcpSocket = INVALID_SOCKET;
4 static LIST_ENTRY AdapterList;
5 static WSADATA wsd;
6 extern struct interface_info *ifi;
7
8 PCHAR *GetSubkeyNames( PCHAR MainKeyName, PCHAR Append ) {
9 int i = 0;
10 DWORD Error;
11 HKEY MainKey;
12 PCHAR *Out, OutKeyName;
13 DWORD CharTotal = 0, AppendLen = 1 + strlen(Append);
14 DWORD MaxSubKeyLen = 0, MaxSubKeys = 0;
15
16 Error = RegOpenKey( HKEY_LOCAL_MACHINE, MainKeyName, &MainKey );
17
18 if( Error ) return NULL;
19
20 Error = RegQueryInfoKey
21 ( MainKey,
22 NULL, NULL, NULL,
23 &MaxSubKeys, &MaxSubKeyLen,
24 NULL, NULL, NULL, NULL, NULL, NULL );
25
26 DH_DbgPrint(MID_TRACE,("MaxSubKeys: %d, MaxSubKeyLen %d\n",
27 MaxSubKeys, MaxSubKeyLen));
28
29 CharTotal = (sizeof(PCHAR) + MaxSubKeyLen + AppendLen) * (MaxSubKeys + 1);
30
31 DH_DbgPrint(MID_TRACE,("AppendLen: %d, CharTotal: %d\n",
32 AppendLen, CharTotal));
33
34 Out = malloc( CharTotal );
35 OutKeyName = ((PCHAR)&Out[MaxSubKeys+1]);
36
37 if( !Out ) { RegCloseKey( MainKey ); return NULL; }
38
39 i = 0;
40 do {
41 Out[i] = OutKeyName;
42 Error = RegEnumKey( MainKey, i, OutKeyName, MaxSubKeyLen );
43 if( !Error ) {
44 strcat( OutKeyName, Append );
45 DH_DbgPrint(MID_TRACE,("[%d]: %s\n", i, OutKeyName));
46 OutKeyName += strlen(OutKeyName) + 1;
47 i++;
48 } else Out[i] = 0;
49 } while( Error == ERROR_SUCCESS );
50
51 RegCloseKey( MainKey );
52
53 return Out;
54 }
55
56 PCHAR RegReadString( HKEY Root, PCHAR Subkey, PCHAR Value ) {
57 PCHAR SubOut = NULL;
58 DWORD SubOutLen = 0, Error = 0;
59 HKEY ValueKey = NULL;
60
61 DH_DbgPrint(MID_TRACE,("Looking in %x:%s:%s\n", Root, Subkey, Value ));
62
63 if( Subkey && strlen(Subkey) ) {
64 if( RegOpenKey( Root, Subkey, &ValueKey ) != ERROR_SUCCESS )
65 goto regerror;
66 } else ValueKey = Root;
67
68 DH_DbgPrint(MID_TRACE,("Got Key %x\n", ValueKey));
69
70 if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL,
71 (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS )
72 goto regerror;
73
74 DH_DbgPrint(MID_TRACE,("Value %s has size %d\n", Value, SubOutLen));
75
76 if( !(SubOut = malloc(SubOutLen)) )
77 goto regerror;
78
79 if( (Error = RegQueryValueEx( ValueKey, Value, NULL, NULL,
80 (LPBYTE)SubOut, &SubOutLen )) != ERROR_SUCCESS )
81 goto regerror;
82
83 DH_DbgPrint(MID_TRACE,("Value %s is %s\n", Value, SubOut));
84
85 goto cleanup;
86
87 regerror:
88 if( SubOut ) free( SubOut );
89 cleanup:
90 if( ValueKey && ValueKey != Root ) {
91 DH_DbgPrint(MID_TRACE,("Closing key %x\n", ValueKey));
92 RegCloseKey( ValueKey );
93 }
94
95 DH_DbgPrint(MID_TRACE,("Returning %x with error %d\n", SubOut, Error));
96
97 return SubOut;
98 }
99
100 HKEY FindAdapterKey( PDHCP_ADAPTER Adapter ) {
101 int i = 0;
102 PCHAR EnumKeyName =
103 "SYSTEM\\CurrentControlSet\\Control\\Class\\"
104 "{4D36E972-E325-11CE-BFC1-08002BE10318}";
105 PCHAR TargetKeyNameStart =
106 "SYSTEM\\CurrentControlSet\\Services\\";
107 PCHAR TargetKeyNameEnd = "\\Parameters\\Tcpip";
108 PCHAR TargetKeyName = NULL;
109 PCHAR *EnumKeysLinkage = GetSubkeyNames( EnumKeyName, "\\Linkage" );
110 PCHAR *EnumKeysTop = GetSubkeyNames( EnumKeyName, "" );
111 PCHAR RootDevice = NULL, DriverDesc = NULL;
112 HKEY EnumKey, OutKey = NULL;
113 DWORD Error = ERROR_SUCCESS;
114
115 if( !EnumKeysLinkage || !EnumKeysTop ) goto cleanup;
116
117 Error = RegOpenKey( HKEY_LOCAL_MACHINE, EnumKeyName, &EnumKey );
118
119 if( Error ) goto cleanup;
120
121 for( i = 0; EnumKeysLinkage[i]; i++ ) {
122 RootDevice = RegReadString
123 ( EnumKey, EnumKeysLinkage[i], "RootDevice" );
124 DriverDesc = RegReadString
125 ( EnumKey, EnumKeysTop[i], "DriverDesc" );
126
127 if( DriverDesc &&
128 RootDevice &&
129 !strcmp( DriverDesc, Adapter->DhclientInfo.name ) ) {
130 TargetKeyName =
131 malloc( strlen( TargetKeyNameStart ) +
132 strlen( RootDevice ) +
133 strlen( TargetKeyNameEnd ) + 1 );
134 if( !TargetKeyName ) goto cleanup;
135 sprintf( TargetKeyName, "%s%s%s",
136 TargetKeyNameStart, RootDevice, TargetKeyNameEnd );
137 Error = RegOpenKey( HKEY_LOCAL_MACHINE, TargetKeyName, &OutKey );
138 break;
139 } else {
140 free( RootDevice ); RootDevice = 0;
141 free( DriverDesc ); DriverDesc = 0;
142 }
143 }
144
145 cleanup:
146 if( RootDevice ) free( RootDevice );
147 if( DriverDesc ) free( DriverDesc );
148 if( EnumKeysLinkage ) free( EnumKeysLinkage );
149 if( EnumKeysTop ) free( EnumKeysTop );
150 if( TargetKeyName ) free( TargetKeyName );
151
152 return OutKey;
153 }
154
155 BOOL PrepareAdapterForService( PDHCP_ADAPTER Adapter ) {
156 HKEY AdapterKey = NULL;
157 PCHAR IPAddress = NULL, Netmask = NULL, DefaultGateway = NULL;
158 NTSTATUS Status = STATUS_SUCCESS;
159 DWORD Error = ERROR_SUCCESS;
160 MIB_IPFORWARDROW DefGatewayRow;
161
162 Adapter->DhclientState.config = &Adapter->DhclientConfig;
163 strncpy(Adapter->DhclientInfo.name, (char*)Adapter->IfMib.bDescr,
164 sizeof(Adapter->DhclientInfo.name));
165
166 AdapterKey = FindAdapterKey( Adapter );
167 if( AdapterKey )
168 IPAddress = RegReadString( AdapterKey, NULL, "IPAddress" );
169
170 if( IPAddress && strcmp( IPAddress, "0.0.0.0" ) ) {
171 /* Non-automatic case */
172 DH_DbgPrint
173 (MID_TRACE,("Adapter Name: [%s] (Bind Status %x) (static %s)\n",
174 Adapter->DhclientInfo.name,
175 Adapter->BindStatus,
176 IPAddress));
177
178 Adapter->DhclientState.state = S_STATIC;
179
180 Netmask = RegReadString( AdapterKey, NULL, "Subnetmask" );
181 if( !Netmask ) Netmask = "255.255.255.0";
182
183 Status = AddIPAddress( inet_addr( IPAddress ),
184 inet_addr( Netmask ),
185 Adapter->IfMib.dwIndex,
186 &Adapter->NteContext,
187 &Adapter->NteInstance );
188
189 DefaultGateway = RegReadString( AdapterKey, NULL, "DefaultGateway" );
190
191 if( DefaultGateway ) {
192 DefGatewayRow.dwForwardDest = 0;
193 DefGatewayRow.dwForwardMask = 0;
194 DefGatewayRow.dwForwardMetric1 = 1;
195 DefGatewayRow.dwForwardNextHop = inet_addr(DefaultGateway);
196 Error = CreateIpForwardEntry( &DefGatewayRow );
197 if( Error )
198 warning("Failed to set default gateway %s: %ld\n",
199 DefaultGateway, Error);
200 }
201
202 if( DefaultGateway ) free( DefaultGateway );
203 if( Netmask ) free( Netmask );
204 } else {
205 /* Automatic case */
206 DH_DbgPrint
207 (MID_TRACE,("Adapter Name: [%s] (Bind Status %x) (dynamic)\n",
208 Adapter->DhclientInfo.name,
209 Adapter->BindStatus));
210 }
211
212 if( IPAddress ) free( IPAddress );
213
214 return TRUE;
215 }
216
217 /*
218 * XXX Figure out the way to bind a specific adapter to a socket.
219 */
220
221 void AdapterInit() {
222 PMIB_IFTABLE Table = malloc(sizeof(MIB_IFTABLE));
223 DWORD Error, Size, i;
224 PDHCP_ADAPTER Adapter = NULL;
225
226 WSAStartup(0x0101,&wsd);
227
228 InitializeListHead( &AdapterList );
229
230 DH_DbgPrint(MID_TRACE,("Getting Adapter List...\n"));
231
232 while( (Error = GetIfTable(Table, &Size, 0 )) ==
233 ERROR_INSUFFICIENT_BUFFER ) {
234 DH_DbgPrint(MID_TRACE,("Error %d, New Buffer Size: %d\n", Error, Size));
235 free( Table );
236 Table = malloc( Size );
237 }
238
239 if( Error != NO_ERROR ) goto term;
240
241 DH_DbgPrint(MID_TRACE,("Got Adapter List (%d entries)\n", Table->dwNumEntries));
242
243 for( i = 0; i < Table->dwNumEntries; i++ ) {
244 DH_DbgPrint(MID_TRACE,("Getting adapter %d attributes\n",
245 Table->table[i].dwIndex));
246 Adapter = calloc( sizeof( DHCP_ADAPTER ) + Table->table[i].dwMtu, 1 );
247
248 if( Adapter && Table->table[i].dwType == MIB_IF_TYPE_ETHERNET ) {
249 memcpy( &Adapter->IfMib, &Table->table[i],
250 sizeof(Adapter->IfMib) );
251 Adapter->DhclientInfo.client = &Adapter->DhclientState;
252 Adapter->DhclientInfo.rbuf = Adapter->recv_buf;
253 Adapter->DhclientInfo.rbuf_max = Table->table[i].dwMtu;
254 Adapter->DhclientInfo.rbuf_len =
255 Adapter->DhclientInfo.rbuf_offset = 0;
256 memcpy(Adapter->DhclientInfo.hw_address.haddr,
257 Adapter->IfMib.bPhysAddr,
258 Adapter->IfMib.dwPhysAddrLen);
259 Adapter->DhclientInfo.hw_address.hlen =
260 Adapter->IfMib.dwPhysAddrLen;
261
262 if( DhcpSocket == INVALID_SOCKET ) {
263 DhcpSocket =
264 Adapter->DhclientInfo.rfdesc =
265 Adapter->DhclientInfo.wfdesc =
266 socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
267 Adapter->ListenAddr.sin_family = AF_INET;
268 Adapter->ListenAddr.sin_port = htons(LOCAL_PORT);
269 Adapter->BindStatus =
270 (bind( Adapter->DhclientInfo.rfdesc,
271 (struct sockaddr *)&Adapter->ListenAddr,
272 sizeof(Adapter->ListenAddr) ) == 0) ?
273 0 : WSAGetLastError();
274 } else {
275 Adapter->DhclientInfo.rfdesc =
276 Adapter->DhclientInfo.wfdesc = DhcpSocket;
277 }
278
279 Adapter->DhclientConfig.timeout = DHCP_PANIC_TIMEOUT;
280 Adapter->DhclientConfig.initial_interval = DHCP_DISCOVER_INTERVAL;
281 Adapter->DhclientConfig.retry_interval = DHCP_DISCOVER_INTERVAL;
282 Adapter->DhclientConfig.select_interval = 1;
283 Adapter->DhclientConfig.reboot_timeout = DHCP_REBOOT_TIMEOUT;
284 Adapter->DhclientConfig.backoff_cutoff = DHCP_BACKOFF_MAX;
285 Adapter->DhclientState.interval =
286 Adapter->DhclientConfig.retry_interval;
287
288 if( PrepareAdapterForService( Adapter ) ) {
289 Adapter->DhclientInfo.next = ifi;
290 ifi = &Adapter->DhclientInfo;
291 InsertTailList( &AdapterList, &Adapter->ListEntry );
292 } else { free( Adapter ); Adapter = 0; }
293 } else { free( Adapter ); Adapter = 0; }
294
295 if( !Adapter )
296 DH_DbgPrint(MID_TRACE,("Adapter %d was rejected\n",
297 Table->table[i].dwIndex));
298 }
299
300 DH_DbgPrint(MID_TRACE,("done with AdapterInit\n"));
301
302 term:
303 if( Table ) free( Table );
304 }
305
306 void AdapterStop() {
307 PLIST_ENTRY ListEntry;
308 PDHCP_ADAPTER Adapter;
309 while( !IsListEmpty( &AdapterList ) ) {
310 ListEntry = (PLIST_ENTRY)RemoveHeadList( &AdapterList );
311 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
312 free( Adapter );
313 }
314 WSACleanup();
315 }
316
317 PDHCP_ADAPTER AdapterFindIndex( unsigned int indx ) {
318 PDHCP_ADAPTER Adapter;
319 PLIST_ENTRY ListEntry;
320
321 for( ListEntry = AdapterList.Flink;
322 ListEntry != &AdapterList;
323 ListEntry = ListEntry->Flink ) {
324 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
325 if( Adapter->IfMib.dwIndex == indx ) return Adapter;
326 }
327
328 return NULL;
329 }
330
331 PDHCP_ADAPTER AdapterFindName( const WCHAR *name ) {
332 PDHCP_ADAPTER Adapter;
333 PLIST_ENTRY ListEntry;
334
335 for( ListEntry = AdapterList.Flink;
336 ListEntry != &AdapterList;
337 ListEntry = ListEntry->Flink ) {
338 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
339 if( !wcsicmp( Adapter->IfMib.wszName, name ) ) return Adapter;
340 }
341
342 return NULL;
343 }
344
345 PDHCP_ADAPTER AdapterFindInfo( struct interface_info *ip ) {
346 PDHCP_ADAPTER Adapter;
347 PLIST_ENTRY ListEntry;
348
349 for( ListEntry = AdapterList.Flink;
350 ListEntry != &AdapterList;
351 ListEntry = ListEntry->Flink ) {
352 Adapter = CONTAINING_RECORD( ListEntry, DHCP_ADAPTER, ListEntry );
353 if( ip == &Adapter->DhclientInfo ) return Adapter;
354 }
355
356 return NULL;
357 }
358
359 PDHCP_ADAPTER AdapterGetFirst() {
360 if( IsListEmpty( &AdapterList ) ) return NULL; else {
361 return CONTAINING_RECORD
362 ( AdapterList.Flink, DHCP_ADAPTER, ListEntry );
363 }
364 }
365
366 PDHCP_ADAPTER AdapterGetNext( PDHCP_ADAPTER This )
367 {
368 if( This->ListEntry.Flink == &AdapterList ) return NULL;
369 return CONTAINING_RECORD
370 ( This->ListEntry.Flink, DHCP_ADAPTER, ListEntry );
371 }
372
373 void if_register_send(struct interface_info *ip) {
374
375 }
376
377 void if_register_receive(struct interface_info *ip) {
378 }