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 //#include <sys/ioctl.h> 45 46 //#include <net/if_media.h> 47 //#include <ifaddrs.h> 48 //#include <poll.h> 49 50 extern SOCKET DhcpSocket; 51 HANDLE AdapterStateChangedEvent = NULL; 52 struct protocol *protocols = NULL; 53 struct timeout *timeouts = NULL; 54 static struct timeout *free_timeouts = NULL; 55 void (*bootp_packet_handler)(struct interface_info *, 56 struct dhcp_packet *, int, unsigned int, 57 struct iaddr, struct hardware *); 58 59 /* 60 * Wait for packets to come in using poll(). When a packet comes in, 61 * call receive_packet to receive the packet and possibly strip hardware 62 * addressing information from it, and then call through the 63 * bootp_packet_handler hook to try to do something with it. 64 */ 65 void 66 dispatch(HANDLE hStopEvent) 67 { 68 int count, to_msec; 69 struct protocol *l; 70 time_t howlong, cur_time; 71 HANDLE Events[3]; 72 int EventCount = 2; 73 74 Events[0] = StartAdapterDiscovery(); 75 if (!Events[0]) 76 return; 77 78 AdapterStateChangedEvent = Events[0]; 79 80 Events[1] = hStopEvent; 81 Events[2] = WSA_INVALID_EVENT; 82 83 ApiLock(); 84 85 do { 86 /* 87 * Call any expired timeouts, and then if there's still 88 * a timeout registered, time out the select call then. 89 */ 90 time(&cur_time); 91 92 if (timeouts) 93 { 94 struct timeout *t; 95 96 if (timeouts->when <= cur_time) { 97 t = timeouts; 98 timeouts = timeouts->next; 99 (*(t->func))(t->what); 100 t->next = free_timeouts; 101 free_timeouts = t; 102 continue; 103 } 104 105 /* 106 * Figure timeout in milliseconds, and check for 107 * potential overflow, so we can cram into an 108 * int for poll, while not polling with a 109 * negative timeout and blocking indefinitely. 110 */ 111 howlong = timeouts->when - cur_time; 112 if (howlong > INT_MAX / 1000) 113 howlong = INT_MAX / 1000; 114 to_msec = howlong * 1000; 115 } 116 else 117 { 118 to_msec = INFINITE; 119 } 120 121 if (Events[2] == WSA_INVALID_EVENT && DhcpSocket != INVALID_SOCKET) 122 { 123 Events[2] = WSACreateEvent(); 124 if (Events[2] != WSA_INVALID_EVENT) 125 { 126 count = WSAEventSelect(DhcpSocket, Events[2], FD_READ | FD_CLOSE); 127 if (count != NO_ERROR) 128 { 129 WSACloseEvent(Events[2]); 130 Events[2] = WSA_INVALID_EVENT; 131 } 132 else 133 { 134 EventCount = 3; 135 } 136 } 137 } 138 else if (Events[2] != WSA_INVALID_EVENT && DhcpSocket == INVALID_SOCKET) 139 { 140 WSACloseEvent(Events[2]); 141 Events[2] = WSA_INVALID_EVENT; 142 143 EventCount = 2; 144 } 145 146 ApiUnlock(); 147 count = WaitForMultipleObjects(EventCount, 148 Events, 149 FALSE, 150 to_msec); 151 ApiLock(); 152 if (count == WAIT_OBJECT_0) 153 { 154 /* Adapter state change */ 155 continue; 156 } 157 else if (count == WAIT_OBJECT_0 + 1) 158 { 159 /* Stop event signalled */ 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 AdapterStateChangedEvent = NULL; 187 CloseHandle(Events[0]); 188 CloseHandle(Events[1]); 189 WSACloseEvent(Events[2]); 190 191 ApiUnlock(); 192 } 193 194 void 195 got_one(struct protocol *l) 196 { 197 struct sockaddr_in from; 198 struct hardware hfrom; 199 struct iaddr ifrom; 200 ssize_t result; 201 union { 202 /* 203 * Packet input buffer. Must be as large as largest 204 * possible MTU. 205 */ 206 unsigned char packbuf[4095]; 207 struct dhcp_packet packet; 208 } u; 209 struct interface_info *ip = l->local; 210 PDHCP_ADAPTER adapter; 211 212 if ((result = receive_packet(ip, u.packbuf, sizeof(u), &from, 213 &hfrom)) == -1) { 214 warning("receive_packet failed on %s: %d", ip->name, 215 WSAGetLastError()); 216 ip->errors++; 217 if (ip->errors > 20) { 218 /* our interface has gone away. */ 219 warning("Interface %s no longer appears valid.", 220 ip->name); 221 ip->dead = 1; 222 closesocket(l->fd); 223 remove_protocol(l); 224 adapter = AdapterFindInfo(ip); 225 if (adapter) { 226 RemoveEntryList(&adapter->ListEntry); 227 free(adapter); 228 } 229 } 230 return; 231 } 232 if (result == 0) 233 return; 234 235 if (bootp_packet_handler) { 236 ifrom.len = 4; 237 memcpy(ifrom.iabuf, &from.sin_addr, ifrom.len); 238 239 240 adapter = AdapterFindByHardwareAddress(u.packet.chaddr, 241 u.packet.hlen); 242 243 if (!adapter) { 244 warning("Discarding packet with a non-matching target physical address\n"); 245 return; 246 } 247 248 (*bootp_packet_handler)(&adapter->DhclientInfo, &u.packet, result, 249 from.sin_port, ifrom, &hfrom); 250 } 251 } 252 253 void 254 add_timeout(time_t when, void (*where)(void *), void *what) 255 { 256 struct timeout *t, *q; 257 258 DH_DbgPrint(MID_TRACE,("Adding timeout %x %p %x\n", when, where, what)); 259 /* See if this timeout supersedes an existing timeout. */ 260 t = NULL; 261 for (q = timeouts; q; q = q->next) { 262 if (q->func == where && q->what == what) { 263 if (t) 264 t->next = q->next; 265 else 266 timeouts = q->next; 267 break; 268 } 269 t = q; 270 } 271 272 /* If we didn't supersede a timeout, allocate a timeout 273 structure now. */ 274 if (!q) { 275 if (free_timeouts) { 276 q = free_timeouts; 277 free_timeouts = q->next; 278 q->func = where; 279 q->what = what; 280 } else { 281 q = malloc(sizeof(struct timeout)); 282 if (!q) { 283 error("Can't allocate timeout structure!"); 284 return; 285 } 286 q->func = where; 287 q->what = what; 288 } 289 } 290 291 q->when = when; 292 293 /* Now sort this timeout into the timeout list. */ 294 295 /* Beginning of list? */ 296 if (!timeouts || timeouts->when > q->when) { 297 q->next = timeouts; 298 timeouts = q; 299 return; 300 } 301 302 /* Middle of list? */ 303 for (t = timeouts; t->next; t = t->next) { 304 if (t->next->when > q->when) { 305 q->next = t->next; 306 t->next = q; 307 return; 308 } 309 } 310 311 /* End of list. */ 312 t->next = q; 313 q->next = NULL; 314 } 315 316 void 317 cancel_timeout(void (*where)(void *), void *what) 318 { 319 struct timeout *t, *q; 320 321 /* Look for this timeout on the list, and unlink it if we find it. */ 322 t = NULL; 323 for (q = timeouts; q; q = q->next) { 324 if (q->func == where && q->what == what) { 325 if (t) 326 t->next = q->next; 327 else 328 timeouts = q->next; 329 break; 330 } 331 t = q; 332 } 333 334 /* If we found the timeout, put it on the free list. */ 335 if (q) { 336 q->next = free_timeouts; 337 free_timeouts = q; 338 } 339 } 340 341 /* Add a protocol to the list of protocols... */ 342 void 343 add_protocol(char *name, int fd, void (*handler)(struct protocol *), 344 void *local) 345 { 346 struct protocol *p; 347 348 p = malloc(sizeof(*p)); 349 if (!p) 350 error("can't allocate protocol struct for %s", name); 351 352 p->fd = fd; 353 p->handler = handler; 354 p->local = local; 355 p->next = protocols; 356 protocols = p; 357 } 358 359 void 360 remove_protocol(struct protocol *proto) 361 { 362 struct protocol *p, *next, *prev; 363 struct interface_info *ip = proto->local; 364 struct timeout *t, *q, *u; 365 366 t = NULL; 367 q = timeouts; 368 while (q != NULL) 369 { 370 /* Remove all timeouts for this protocol */ 371 if (q->what == ip) 372 { 373 /* Unlink the timeout from previous */ 374 if (t) 375 t->next = q->next; 376 else 377 timeouts = q->next; 378 379 /* Advance to the next timeout */ 380 u = q->next; 381 382 /* Add it to the free list */ 383 q->next = free_timeouts; 384 free_timeouts = q; 385 } 386 else 387 { 388 /* Advance to the next timeout */ 389 u = q->next; 390 391 /* Update the previous pointer */ 392 t = q; 393 } 394 395 /* Advance */ 396 q = u; 397 } 398 399 prev = NULL; 400 for (p = protocols; p; p = next) { 401 next = p->next; 402 if (p == proto) { 403 if (prev) 404 prev->next = p->next; 405 else 406 protocols = p->next; 407 free(p); 408 } 409 } 410 } 411 412 struct protocol * 413 find_protocol_by_adapter(struct interface_info *info) 414 { 415 struct protocol *p; 416 417 for( p = protocols; p; p = p->next ) { 418 if( p->local == (void *)info ) return p; 419 } 420 421 return NULL; 422 } 423 424 int 425 interface_link_status(char *ifname) 426 { 427 return (1); 428 } 429