1 /* $OpenBSD: dispatch.c,v 1.31 2004/09/21 04:07:03 david Exp $ */ 2 3 /* 4 * Copyright 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 1995, 1996, 1997, 1998, 1999 6 * The Internet Software Consortium. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of The Internet Software Consortium nor the names 18 * of its 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 INTERNET SOFTWARE CONSORTIUM AND 22 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR 26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * This software has been written for the Internet Software Consortium 36 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie 37 * Enterprises. To learn more about the Internet Software Consortium, 38 * see ``http://www.vix.com/isc''. To learn more about Vixie 39 * Enterprises, see ``http://www.vix.com''. 40 */ 41 42 #include <rosdhcp.h> 43 44 #define NDEBUG 45 #include <reactos/debug.h> 46 47 //#include <sys/ioctl.h> 48 49 //#include <net/if_media.h> 50 //#include <ifaddrs.h> 51 //#include <poll.h> 52 53 extern SOCKET DhcpSocket; 54 extern HANDLE hAdapterStateChangedEvent; 55 56 struct protocol *protocols = NULL; 57 struct timeout *timeouts = NULL; 58 static struct timeout *free_timeouts = NULL; 59 void (*bootp_packet_handler)(struct interface_info *, 60 struct dhcp_packet *, int, unsigned int, 61 struct iaddr, struct hardware *); 62 63 /* 64 * Wait for packets to come in using poll(). When a packet comes in, 65 * call receive_packet to receive the packet and possibly strip hardware 66 * addressing information from it, and then call through the 67 * bootp_packet_handler hook to try to do something with it. 68 */ 69 void 70 dispatch(HANDLE hStopEvent) 71 { 72 int count, to_msec; 73 struct protocol *l; 74 time_t howlong, cur_time; 75 HANDLE Events[3]; 76 int EventCount = 2; 77 78 Events[0] = hAdapterStateChangedEvent; 79 Events[1] = hStopEvent; 80 Events[2] = WSA_INVALID_EVENT; 81 82 ApiLock(); 83 84 do { 85 /* 86 * Call any expired timeouts, and then if there's still 87 * a timeout registered, time out the select call then. 88 */ 89 time(&cur_time); 90 91 if (timeouts) 92 { 93 struct timeout *t; 94 95 if (timeouts->when <= cur_time) { 96 t = timeouts; 97 timeouts = timeouts->next; 98 (*(t->func))(t->what); 99 t->next = free_timeouts; 100 free_timeouts = t; 101 continue; 102 } 103 104 /* 105 * Figure timeout in milliseconds, and check for 106 * potential overflow, so we can cram into an 107 * int for poll, while not polling with a 108 * negative timeout and blocking indefinitely. 109 */ 110 howlong = timeouts->when - cur_time; 111 if (howlong > INT_MAX / 1000) 112 howlong = INT_MAX / 1000; 113 to_msec = howlong * 1000; 114 } 115 else 116 { 117 to_msec = INFINITE; 118 } 119 120 if (Events[2] == WSA_INVALID_EVENT && DhcpSocket != INVALID_SOCKET) 121 { 122 Events[2] = WSACreateEvent(); 123 if (Events[2] != WSA_INVALID_EVENT) 124 { 125 count = WSAEventSelect(DhcpSocket, Events[2], FD_READ | FD_CLOSE); 126 if (count != NO_ERROR) 127 { 128 WSACloseEvent(Events[2]); 129 Events[2] = WSA_INVALID_EVENT; 130 } 131 else 132 { 133 EventCount = 3; 134 } 135 } 136 } 137 else if (Events[2] != WSA_INVALID_EVENT && DhcpSocket == INVALID_SOCKET) 138 { 139 WSACloseEvent(Events[2]); 140 Events[2] = WSA_INVALID_EVENT; 141 142 EventCount = 2; 143 } 144 145 ApiUnlock(); 146 count = WaitForMultipleObjects(EventCount, 147 Events, 148 FALSE, 149 to_msec); 150 ApiLock(); 151 if (count == WAIT_OBJECT_0) 152 { 153 /* Adapter state change */ 154 continue; 155 } 156 else if (count == WAIT_OBJECT_0 + 1) 157 { 158 /* Stop event signalled */ 159 DPRINT("Dispatch thread stop event!\n"); 160 break; 161 } 162 else if (count == WAIT_OBJECT_0 + 2) 163 { 164 /* Packet received */ 165 166 /* WSA events are manual reset events */ 167 WSAResetEvent(Events[2]); 168 } 169 else 170 { 171 /* Timeout */ 172 continue; 173 } 174 175 for (l = protocols; l; l = l->next) { 176 struct interface_info *ip; 177 ip = l->local; 178 if (ip && (l->handler != got_one || 179 !ip->dead)) { 180 DH_DbgPrint(MID_TRACE,("Handling %x\n", l)); 181 (*(l->handler))(l); 182 } 183 } 184 } while (1); 185 186 WSACloseEvent(Events[2]); 187 188 ApiUnlock(); 189 190 DPRINT("Dispatch thread stopped!\n"); 191 } 192 193 void 194 got_one(struct protocol *l) 195 { 196 struct sockaddr_in from; 197 struct hardware hfrom; 198 struct iaddr ifrom; 199 ssize_t result; 200 union { 201 /* 202 * Packet input buffer. Must be as large as largest 203 * possible MTU. 204 */ 205 unsigned char packbuf[4095]; 206 struct dhcp_packet packet; 207 } u; 208 struct interface_info *ip = l->local; 209 PDHCP_ADAPTER adapter; 210 211 if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from, 212 &hfrom)) == -1) { 213 warning("receive_packet failed on %s: %d", ip->name, 214 WSAGetLastError()); 215 ip->errors++; 216 if (ip->errors > 20) { 217 /* our interface has gone away. */ 218 warning("Interface %s no longer appears valid.", 219 ip->name); 220 ip->dead = 1; 221 closesocket(l->fd); 222 remove_protocol(l); 223 adapter = AdapterFindInfo(ip); 224 if (adapter) { 225 RemoveEntryList(&adapter->ListEntry); 226 free(adapter); 227 } 228 } 229 return; 230 } 231 if (result == 0) 232 return; 233 234 if (bootp_packet_handler) { 235 ifrom.len = 4; 236 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); 237 238 239 adapter = AdapterFindByHardwareAddress(u.packet.chaddr, 240 u.packet.hlen); 241 242 if (!adapter) { 243 warning("Discarding packet with a non-matching target physical address\n"); 244 return; 245 } 246 247 (*bootp_packet_handler)(&adapter->DhclientInfo, &u.packet, result, 248 from.sin_port, ifrom, &hfrom); 249 } 250 } 251 252 void 253 add_timeout(time_t when, void (*where)(void *), void *what) 254 { 255 struct timeout *t, *q; 256 257 DH_DbgPrint(MID_TRACE,("Adding timeout %x %p %x\n", when, where, what)); 258 /* See if this timeout supersedes an existing timeout. */ 259 t = NULL; 260 for (q = timeouts; q; q = q->next) { 261 if (q->func == where && q->what == what) { 262 if (t) 263 t->next = q->next; 264 else 265 timeouts = q->next; 266 break; 267 } 268 t = q; 269 } 270 271 /* If we didn't supersede a timeout, allocate a timeout 272 structure now. */ 273 if (!q) { 274 if (free_timeouts) { 275 q = free_timeouts; 276 free_timeouts = q->next; 277 q->func = where; 278 q->what = what; 279 } else { 280 q = malloc(sizeof(struct timeout)); 281 if (!q) { 282 error("Can't allocate timeout structure!"); 283 return; 284 } 285 q->func = where; 286 q->what = what; 287 } 288 } 289 290 q->when = when; 291 292 /* Now sort this timeout into the timeout list. */ 293 294 /* Beginning of list? */ 295 if (!timeouts || timeouts->when > q->when) { 296 q->next = timeouts; 297 timeouts = q; 298 return; 299 } 300 301 /* Middle of list? */ 302 for (t = timeouts; t->next; t = t->next) { 303 if (t->next->when > q->when) { 304 q->next = t->next; 305 t->next = q; 306 return; 307 } 308 } 309 310 /* End of list. */ 311 t->next = q; 312 q->next = NULL; 313 } 314 315 void 316 cancel_timeout(void (*where)(void *), void *what) 317 { 318 struct timeout *t, *q; 319 320 /* Look for this timeout on the list, and unlink it if we find it. */ 321 t = NULL; 322 for (q = timeouts; q; q = q->next) { 323 if (q->func == where && q->what == what) { 324 if (t) 325 t->next = q->next; 326 else 327 timeouts = q->next; 328 break; 329 } 330 t = q; 331 } 332 333 /* If we found the timeout, put it on the free list. */ 334 if (q) { 335 q->next = free_timeouts; 336 free_timeouts = q; 337 } 338 } 339 340 /* Add a protocol to the list of protocols... */ 341 void 342 add_protocol(char *name, int fd, void (*handler)(struct protocol *), 343 void *local) 344 { 345 struct protocol *p; 346 347 p = malloc(sizeof(*p)); 348 if (!p) 349 error("can't allocate protocol struct for %s", name); 350 351 p->fd = fd; 352 p->handler = handler; 353 p->local = local; 354 p->next = protocols; 355 protocols = p; 356 } 357 358 void 359 remove_protocol(struct protocol *proto) 360 { 361 struct protocol *p, *next, *prev; 362 struct interface_info *ip = proto->local; 363 struct timeout *t, *q, *u; 364 365 t = NULL; 366 q = timeouts; 367 while (q != NULL) 368 { 369 /* Remove all timeouts for this protocol */ 370 if (q->what == ip) 371 { 372 /* Unlink the timeout from previous */ 373 if (t) 374 t->next = q->next; 375 else 376 timeouts = q->next; 377 378 /* Advance to the next timeout */ 379 u = q->next; 380 381 /* Add it to the free list */ 382 q->next = free_timeouts; 383 free_timeouts = q; 384 } 385 else 386 { 387 /* Advance to the next timeout */ 388 u = q->next; 389 390 /* Update the previous pointer */ 391 t = q; 392 } 393 394 /* Advance */ 395 q = u; 396 } 397 398 prev = NULL; 399 for (p = protocols; p; p = next) { 400 next = p->next; 401 if (p == proto) { 402 if (prev) 403 prev->next = p->next; 404 else 405 protocols = p->next; 406 free(p); 407 } 408 } 409 } 410 411 struct protocol * 412 find_protocol_by_adapter(struct interface_info *info) 413 { 414 struct protocol *p; 415 416 for( p = protocols; p; p = p->next ) { 417 if( p->local == (void *)info ) return p; 418 } 419 420 return NULL; 421 } 422 423 int 424 interface_link_status(char *ifname) 425 { 426 return (1); 427 } 428