00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "dhcpd.h"
00038 #include <errno.h>
00039 #include <sys/ioctl.h>
00040 #include <sys/uio.h>
00041 #include <sys/uio.h>
00042
00043 #if defined(sun) && defined(USE_V4_PKTINFO)
00044 #include <sys/sysmacros.h>
00045 #include <net/if.h>
00046 #include <sys/sockio.h>
00047 #include <net/if_dl.h>
00048 #include <sys/dlpi.h>
00049 #endif
00050
00051 #ifdef USE_SOCKET_FALLBACK
00052 # if !defined (USE_SOCKET_SEND)
00053 # define if_register_send if_register_fallback
00054 # define send_packet send_fallback
00055 # define if_reinitialize_send if_reinitialize_fallback
00056 # endif
00057 #endif
00058
00059 #if defined(DHCPv6)
00060
00061
00062
00063
00064 static int no_global_v6_socket = 0;
00065 static unsigned int global_v6_socket_references = 0;
00066 static int global_v6_socket = -1;
00067
00068 static void if_register_multicast(struct interface_info *info);
00069 #endif
00070
00071
00072
00073
00074
00075
00076 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
00077 static unsigned int global_v4_socket_references = 0;
00078 static int global_v4_socket = -1;
00079 #endif
00080
00081
00082
00083
00084
00085
00086 #if !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK)
00087 static int once = 0;
00088 #endif
00089
00090
00091
00092
00093 #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
00094 void if_reinitialize_send (info)
00095 struct interface_info *info;
00096 {
00097 #if 0
00098 #ifndef USE_SOCKET_RECEIVE
00099 once = 0;
00100 close (info -> wfdesc);
00101 #endif
00102 if_register_send (info);
00103 #endif
00104 }
00105 #endif
00106
00107 #ifdef USE_SOCKET_RECEIVE
00108 void if_reinitialize_receive (info)
00109 struct interface_info *info;
00110 {
00111 #if 0
00112 once = 0;
00113 close (info -> rfdesc);
00114 if_register_receive (info);
00115 #endif
00116 }
00117 #endif
00118
00119 #if defined (USE_SOCKET_SEND) || \
00120 defined (USE_SOCKET_RECEIVE) || \
00121 defined (USE_SOCKET_FALLBACK)
00122
00123 int
00124 if_register_socket(struct interface_info *info, int family,
00125 int *do_multicast, struct in6_addr *linklocal6)
00126 {
00127 struct sockaddr_storage name;
00128 int name_len;
00129 int sock;
00130 int flag;
00131 int domain;
00132 #ifdef DHCPv6
00133 struct sockaddr_in6 *addr6;
00134 #endif
00135 struct sockaddr_in *addr;
00136
00137
00138
00139 #if !defined(SO_BINDTODEVICE) && !defined(USE_FALLBACK)
00140
00141 if (once) {
00142 log_fatal ("The standard socket API can only support %s",
00143 "hosts with a single network interface.");
00144 }
00145 once = 1;
00146 #endif
00147
00148
00149
00150
00151
00152 memset(&name, 0, sizeof(name));
00153 switch (family) {
00154 #ifdef DHCPv6
00155 case AF_INET6:
00156 addr6 = (struct sockaddr_in6 *)&name;
00157 addr6->sin6_family = AF_INET6;
00158 addr6->sin6_port = local_port;
00159 if (linklocal6) {
00160 memcpy(&addr6->sin6_addr,
00161 linklocal6,
00162 sizeof(addr6->sin6_addr));
00163 addr6->sin6_scope_id = if_nametoindex(info->name);
00164 }
00165 #ifdef HAVE_SA_LEN
00166 addr6->sin6_len = sizeof(*addr6);
00167 #endif
00168 name_len = sizeof(*addr6);
00169 domain = PF_INET6;
00170 if ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM) {
00171 *do_multicast = 0;
00172 }
00173 break;
00174 #endif
00175
00176 case AF_INET:
00177 default:
00178 addr = (struct sockaddr_in *)&name;
00179 addr->sin_family = AF_INET;
00180 addr->sin_port = local_port;
00181 memcpy(&addr->sin_addr,
00182 &local_address,
00183 sizeof(addr->sin_addr));
00184 #ifdef HAVE_SA_LEN
00185 addr->sin_len = sizeof(*addr);
00186 #endif
00187 name_len = sizeof(*addr);
00188 domain = PF_INET;
00189 break;
00190 }
00191
00192
00193 sock = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
00194 if (sock < 0) {
00195 log_fatal("Can't create dhcp socket: %m");
00196 }
00197
00198
00199
00200 flag = 1;
00201 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
00202 (char *)&flag, sizeof(flag)) < 0) {
00203 log_fatal("Can't set SO_REUSEADDR option on dhcp socket: %m");
00204 }
00205
00206
00207
00208
00209 if (info->ifp &&
00210 (setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
00211 (char *)&flag, sizeof(flag)) < 0)) {
00212 log_fatal("Can't set SO_BROADCAST option on dhcp socket: %m");
00213 }
00214
00215 #if defined(DHCPv6) && defined(SO_REUSEPORT)
00216
00217
00218
00219
00220
00221
00222
00223 if ((local_family == AF_INET6) && *do_multicast) {
00224 flag = 1;
00225 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
00226 (char *)&flag, sizeof(flag)) < 0) {
00227 log_fatal("Can't set SO_REUSEPORT option on dhcp "
00228 "socket: %m");
00229 }
00230 }
00231 #endif
00232
00233
00234 if (bind(sock, (struct sockaddr *)&name, name_len) < 0) {
00235 log_error("Can't bind to dhcp address: %m");
00236 log_error("Please make sure there is no other dhcp server");
00237 log_error("running and that there's no entry for dhcp or");
00238 log_error("bootp in /etc/inetd.conf. Also make sure you");
00239 log_error("are not running HP JetAdmin software, which");
00240 log_fatal("includes a bootp server.");
00241 }
00242
00243 #if defined(SO_BINDTODEVICE)
00244
00245 if ((local_family != AF_INET6) && (info->ifp != NULL) &&
00246 setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE,
00247 (char *)(info -> ifp), sizeof(*(info -> ifp))) < 0) {
00248 log_fatal("setsockopt: SO_BINDTODEVICE: %m");
00249 }
00250 #endif
00251
00252
00253
00254
00255
00256
00257
00258
00259 #if defined(SCO) && defined(IP_BROADCAST_IF)
00260 if (info->address_count &&
00261 setsockopt(sock, IPPROTO_IP, IP_BROADCAST_IF, &info->addresses[0],
00262 sizeof(info->addresses[0])) < 0)
00263 log_fatal("Can't set IP_BROADCAST_IF on dhcp socket: %m");
00264 #endif
00265
00266 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
00267
00268
00269
00270
00271 if (family == AF_INET) {
00272 int on = 1;
00273 if (setsockopt(sock, IPPROTO_IP, IP_RECVPKTINFO,
00274 &on, sizeof(on)) != 0) {
00275 log_fatal("setsockopt: IPV_RECVPKTINFO: %m");
00276 }
00277 }
00278 #endif
00279
00280 #ifdef DHCPv6
00281
00282
00283
00284
00285
00286 if (family == AF_INET6) {
00287 int on = 1;
00288 #ifdef IPV6_RECVPKTINFO
00289
00290 if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
00291 &on, sizeof(on)) != 0) {
00292 log_fatal("setsockopt: IPV6_RECVPKTINFO: %m");
00293 }
00294 #else
00295
00296 if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
00297 &on, sizeof(on)) != 0) {
00298 log_fatal("setsockopt: IPV6_PKTINFO: %m");
00299 }
00300 #endif
00301 }
00302
00303 if ((family == AF_INET6) &&
00304 ((info->flags & INTERFACE_UPSTREAM) != 0)) {
00305 int hop_limit = 32;
00306 if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
00307 &hop_limit, sizeof(int)) < 0) {
00308 log_fatal("setsockopt: IPV6_MULTICAST_HOPS: %m");
00309 }
00310 }
00311 #endif
00312
00313 return sock;
00314 }
00315 #endif
00316
00317 #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
00318 void if_register_send (info)
00319 struct interface_info *info;
00320 {
00321 #ifndef USE_SOCKET_RECEIVE
00322 info->wfdesc = if_register_socket(info, AF_INET, 0, NULL);
00323
00324 if (strcmp(info->name, "fallback") != 0)
00325 get_hw_addr(info);
00326 #if defined (USE_SOCKET_FALLBACK)
00327
00328
00329 info->rfdesc = info->wfdesc;
00330 #endif
00331 #else
00332 info->wfdesc = info->rfdesc;
00333 #endif
00334 if (!quiet_interface_discovery)
00335 log_info ("Sending on Socket/%s%s%s",
00336 info->name,
00337 (info->shared_network ? "/" : ""),
00338 (info->shared_network ?
00339 info->shared_network->name : ""));
00340 }
00341
00342 #if defined (USE_SOCKET_SEND)
00343 void if_deregister_send (info)
00344 struct interface_info *info;
00345 {
00346 #ifndef USE_SOCKET_RECEIVE
00347 close (info -> wfdesc);
00348 #endif
00349 info -> wfdesc = -1;
00350
00351 if (!quiet_interface_discovery)
00352 log_info ("Disabling output on Socket/%s%s%s",
00353 info -> name,
00354 (info -> shared_network ? "/" : ""),
00355 (info -> shared_network ?
00356 info -> shared_network -> name : ""));
00357 }
00358 #endif
00359 #endif
00360
00361 #ifdef USE_SOCKET_RECEIVE
00362 void if_register_receive (info)
00363 struct interface_info *info;
00364 {
00365
00366 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
00367 if (global_v4_socket_references == 0) {
00368 global_v4_socket = if_register_socket(info, AF_INET, 0, NULL);
00369 if (global_v4_socket < 0) {
00370
00371
00372
00373
00374 log_fatal("Failed to create AF_INET socket %s:%d",
00375 MDL);
00376 }
00377 }
00378
00379 info->rfdesc = global_v4_socket;
00380 global_v4_socket_references++;
00381 #else
00382
00383
00384 info->rfdesc = if_register_socket(info, AF_INET, 0, NULL);
00385 #endif
00386
00387 if (strcmp(info->name, "fallback") != 0)
00388 get_hw_addr(info);
00389
00390 if (!quiet_interface_discovery)
00391 log_info ("Listening on Socket/%s%s%s",
00392 info->name,
00393 (info->shared_network ? "/" : ""),
00394 (info->shared_network ?
00395 info->shared_network->name : ""));
00396 }
00397
00398 void if_deregister_receive (info)
00399 struct interface_info *info;
00400 {
00401 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
00402
00403 if ((info->rfdesc == global_v4_socket) &&
00404 (info->wfdesc == global_v4_socket) &&
00405 (global_v4_socket_references > 0)) {
00406 global_v4_socket_references--;
00407 info->rfdesc = -1;
00408 } else {
00409 log_fatal("Impossible condition at %s:%d", MDL);
00410 }
00411
00412 if (global_v4_socket_references == 0) {
00413 close(global_v4_socket);
00414 global_v4_socket = -1;
00415 }
00416 #else
00417 close(info->rfdesc);
00418 info->rfdesc = -1;
00419 #endif
00420 if (!quiet_interface_discovery)
00421 log_info ("Disabling input on Socket/%s%s%s",
00422 info -> name,
00423 (info -> shared_network ? "/" : ""),
00424 (info -> shared_network ?
00425 info -> shared_network -> name : ""));
00426 }
00427 #endif
00428
00429
00430 #ifdef DHCPv6
00431
00432
00433
00434
00435 static void
00436 if_register_multicast(struct interface_info *info) {
00437 int sock = info->rfdesc;
00438 struct ipv6_mreq mreq;
00439
00440 if (inet_pton(AF_INET6, All_DHCP_Relay_Agents_and_Servers,
00441 &mreq.ipv6mr_multiaddr) <= 0) {
00442 log_fatal("inet_pton: unable to convert '%s'",
00443 All_DHCP_Relay_Agents_and_Servers);
00444 }
00445 mreq.ipv6mr_interface = if_nametoindex(info->name);
00446 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
00447 &mreq, sizeof(mreq)) < 0) {
00448 log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458 if ((info->flags & INTERFACE_STREAMS) == 0) {
00459 if (inet_pton(AF_INET6, All_DHCP_Servers,
00460 &mreq.ipv6mr_multiaddr) <= 0) {
00461 log_fatal("inet_pton: unable to convert '%s'",
00462 All_DHCP_Servers);
00463 }
00464 mreq.ipv6mr_interface = if_nametoindex(info->name);
00465 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
00466 &mreq, sizeof(mreq)) < 0) {
00467 log_fatal("setsockopt: IPV6_JOIN_GROUP: %m");
00468 }
00469 }
00470 }
00471
00472 void
00473 if_register6(struct interface_info *info, int do_multicast) {
00474
00475 int req_multi = do_multicast;
00476
00477 if (no_global_v6_socket) {
00478 log_fatal("Impossible condition at %s:%d", MDL);
00479 }
00480
00481 if (global_v6_socket_references == 0) {
00482 global_v6_socket = if_register_socket(info, AF_INET6,
00483 &req_multi, NULL);
00484 if (global_v6_socket < 0) {
00485
00486
00487
00488
00489 log_fatal("Impossible condition at %s:%d", MDL);
00490 } else {
00491 log_info("Bound to *:%d", ntohs(local_port));
00492 }
00493 }
00494
00495 info->rfdesc = global_v6_socket;
00496 info->wfdesc = global_v6_socket;
00497 global_v6_socket_references++;
00498
00499 if (req_multi)
00500 if_register_multicast(info);
00501
00502 get_hw_addr(info);
00503
00504 if (!quiet_interface_discovery) {
00505 if (info->shared_network != NULL) {
00506 log_info("Listening on Socket/%d/%s/%s",
00507 global_v6_socket, info->name,
00508 info->shared_network->name);
00509 log_info("Sending on Socket/%d/%s/%s",
00510 global_v6_socket, info->name,
00511 info->shared_network->name);
00512 } else {
00513 log_info("Listening on Socket/%s", info->name);
00514 log_info("Sending on Socket/%s", info->name);
00515 }
00516 }
00517 }
00518
00519
00520
00521
00522
00523
00524
00525 void
00526 if_register_linklocal6(struct interface_info *info) {
00527 int sock;
00528 int count;
00529 struct in6_addr *addr6 = NULL;
00530 int req_multi = 0;
00531
00532 if (global_v6_socket >= 0) {
00533 log_fatal("Impossible condition at %s:%d", MDL);
00534 }
00535
00536 no_global_v6_socket = 1;
00537
00538
00539 for (count = 0; count < info->v6address_count; count++) {
00540 addr6 = &info->v6addresses[count];
00541 if (IN6_IS_ADDR_LINKLOCAL(addr6))
00542 break;
00543 }
00544
00545 if (!addr6) {
00546 log_fatal("no link-local IPv6 address for %s", info->name);
00547 }
00548
00549 sock = if_register_socket(info, AF_INET6, &req_multi, addr6);
00550
00551 if (sock < 0) {
00552 log_fatal("if_register_socket for %s fails", info->name);
00553 }
00554
00555 info->rfdesc = sock;
00556 info->wfdesc = sock;
00557
00558 get_hw_addr(info);
00559
00560 if (!quiet_interface_discovery) {
00561 if (info->shared_network != NULL) {
00562 log_info("Listening on Socket/%d/%s/%s",
00563 global_v6_socket, info->name,
00564 info->shared_network->name);
00565 log_info("Sending on Socket/%d/%s/%s",
00566 global_v6_socket, info->name,
00567 info->shared_network->name);
00568 } else {
00569 log_info("Listening on Socket/%s", info->name);
00570 log_info("Sending on Socket/%s", info->name);
00571 }
00572 }
00573 }
00574
00575 void
00576 if_deregister6(struct interface_info *info) {
00577
00578 if (no_global_v6_socket) {
00579 close(info->rfdesc);
00580 info->rfdesc = -1;
00581 info->wfdesc = -1;
00582 } else if ((info->rfdesc == global_v6_socket) &&
00583 (info->wfdesc == global_v6_socket) &&
00584 (global_v6_socket_references > 0)) {
00585
00586 global_v6_socket_references--;
00587 info->rfdesc = -1;
00588 info->wfdesc = -1;
00589 } else {
00590 log_fatal("Impossible condition at %s:%d", MDL);
00591 }
00592
00593 if (!quiet_interface_discovery) {
00594 if (info->shared_network != NULL) {
00595 log_info("Disabling input on Socket/%s/%s", info->name,
00596 info->shared_network->name);
00597 log_info("Disabling output on Socket/%s/%s", info->name,
00598 info->shared_network->name);
00599 } else {
00600 log_info("Disabling input on Socket/%s", info->name);
00601 log_info("Disabling output on Socket/%s", info->name);
00602 }
00603 }
00604
00605 if (!no_global_v6_socket &&
00606 (global_v6_socket_references == 0)) {
00607 close(global_v6_socket);
00608 global_v6_socket = -1;
00609
00610 log_info("Unbound from *:%d", ntohs(local_port));
00611 }
00612 }
00613 #endif
00614
00615 #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_FALLBACK)
00616 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
00617 struct interface_info *interface;
00618 struct packet *packet;
00619 struct dhcp_packet *raw;
00620 size_t len;
00621 struct in_addr from;
00622 struct sockaddr_in *to;
00623 struct hardware *hto;
00624 {
00625 int result;
00626 #ifdef IGNORE_HOSTUNREACH
00627 int retry = 0;
00628 do {
00629 #endif
00630 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
00631 struct in_pktinfo pktinfo;
00632
00633 if (interface->ifp != NULL) {
00634 memset(&pktinfo, 0, sizeof (pktinfo));
00635 pktinfo.ipi_ifindex = interface->ifp->ifr_index;
00636 if (setsockopt(interface->wfdesc, IPPROTO_IP,
00637 IP_PKTINFO, (char *)&pktinfo,
00638 sizeof(pktinfo)) < 0)
00639 log_fatal("setsockopt: IP_PKTINFO: %m");
00640 }
00641 #endif
00642 result = sendto (interface -> wfdesc, (char *)raw, len, 0,
00643 (struct sockaddr *)to, sizeof *to);
00644 #ifdef IGNORE_HOSTUNREACH
00645 } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) &&
00646 result < 0 &&
00647 (errno == EHOSTUNREACH ||
00648 errno == ECONNREFUSED) &&
00649 retry++ < 10);
00650 #endif
00651 if (result < 0) {
00652 log_error ("send_packet: %m");
00653 if (errno == ENETUNREACH)
00654 log_error ("send_packet: please consult README file%s",
00655 " regarding broadcast address.");
00656 }
00657 return result;
00658 }
00659
00660 #endif
00661
00662 #ifdef DHCPv6
00663
00664
00665
00666
00667
00668 #ifndef CMSG_LEN
00669 static size_t CMSG_LEN(size_t len) {
00670 size_t hdrlen;
00671
00672
00673
00674
00675 hdrlen = (size_t)CMSG_DATA(((struct cmsghdr *)NULL));
00676 return hdrlen + len;
00677 }
00678 #endif
00679
00680 #ifndef CMSG_SPACE
00681 static size_t CMSG_SPACE(size_t len) {
00682 struct msghdr msg;
00683 struct cmsghdr *cmsgp;
00684
00685
00686
00687
00688
00689 union {
00690 struct cmsghdr cmsg_sizer;
00691 u_int8_t pktinfo_sizer[sizeof(struct cmsghdr) + 1024];
00692 } dummybuf;
00693
00694 memset(&msg, 0, sizeof(msg));
00695 msg.msg_control = &dummybuf;
00696 msg.msg_controllen = sizeof(dummybuf);
00697
00698 cmsgp = (struct cmsghdr *)&dummybuf;
00699 cmsgp->cmsg_len = CMSG_LEN(len);
00700
00701 cmsgp = CMSG_NXTHDR(&msg, cmsgp);
00702 if (cmsgp != NULL) {
00703 return (char *)cmsgp - (char *)msg.msg_control;
00704 } else {
00705 return 0;
00706 }
00707 }
00708 #endif
00709
00710 #endif
00711
00712 #if defined(DHCPv6) || \
00713 (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
00714 defined(USE_V4_PKTINFO))
00715
00716
00717
00718
00719
00720
00721
00722 static void *control_buf = NULL;
00723 static size_t control_buf_len = 0;
00724
00725 static void
00726 allocate_cmsg_cbuf(void) {
00727 control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
00728 control_buf = dmalloc(control_buf_len, MDL);
00729 return;
00730 }
00731 #endif
00732
00733 #ifdef DHCPv6
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753 ssize_t send_packet6(struct interface_info *interface,
00754 const unsigned char *raw, size_t len,
00755 struct sockaddr_in6 *to) {
00756 struct msghdr m;
00757 struct iovec v;
00758 struct sockaddr_in6 dst;
00759 int result;
00760 struct in6_pktinfo *pktinfo;
00761 struct cmsghdr *cmsg;
00762 unsigned int ifindex;
00763
00764
00765
00766
00767
00768
00769 if (control_buf == NULL) {
00770 allocate_cmsg_cbuf();
00771 if (control_buf == NULL) {
00772 log_error("send_packet6: unable to allocate cmsg header");
00773 return(ENOMEM);
00774 }
00775 }
00776 memset(control_buf, 0, control_buf_len);
00777
00778
00779
00780
00781 memset(&m, 0, sizeof(m));
00782
00783
00784
00785
00786
00787 memcpy(&dst, to, sizeof(dst));
00788 m.msg_name = &dst;
00789 m.msg_namelen = sizeof(dst);
00790 ifindex = if_nametoindex(interface->name);
00791 if (no_global_v6_socket)
00792 dst.sin6_scope_id = ifindex;
00793
00794
00795
00796
00797
00798
00799 v.iov_base = (char *)raw;
00800 v.iov_len = len;
00801 m.msg_iov = &v;
00802 m.msg_iovlen = 1;
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812 m.msg_control = control_buf;
00813 m.msg_controllen = control_buf_len;
00814 cmsg = CMSG_FIRSTHDR(&m);
00815 INSIST(cmsg != NULL);
00816 cmsg->cmsg_level = IPPROTO_IPV6;
00817 cmsg->cmsg_type = IPV6_PKTINFO;
00818 cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
00819 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
00820 memset(pktinfo, 0, sizeof(*pktinfo));
00821 pktinfo->ipi6_ifindex = ifindex;
00822 m.msg_controllen = cmsg->cmsg_len;
00823
00824 result = sendmsg(interface->wfdesc, &m, 0);
00825 if (result < 0) {
00826 log_error("send_packet6: %m");
00827 }
00828 return result;
00829 }
00830 #endif
00831
00832 #ifdef USE_SOCKET_RECEIVE
00833 ssize_t receive_packet (interface, buf, len, from, hfrom)
00834 struct interface_info *interface;
00835 unsigned char *buf;
00836 size_t len;
00837 struct sockaddr_in *from;
00838 struct hardware *hfrom;
00839 {
00840 #if !(defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO))
00841 SOCKLEN_T flen = sizeof *from;
00842 #endif
00843 int result;
00844
00845
00846
00847
00848
00849
00850 memset(hfrom, 0, sizeof(*hfrom));
00851
00852 #ifdef IGNORE_HOSTUNREACH
00853 int retry = 0;
00854 do {
00855 #endif
00856
00857 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
00858 struct msghdr m;
00859 struct iovec v;
00860 struct cmsghdr *cmsg;
00861 struct in_pktinfo *pktinfo;
00862 unsigned int ifindex;
00863
00864
00865
00866
00867
00868 if (control_buf == NULL) {
00869 allocate_cmsg_cbuf();
00870 if (control_buf == NULL) {
00871 log_error("receive_packet: unable to allocate cmsg "
00872 "header");
00873 return(ENOMEM);
00874 }
00875 }
00876 memset(control_buf, 0, control_buf_len);
00877
00878
00879
00880
00881 memset(&m, 0, sizeof(m));
00882
00883
00884
00885
00886 m.msg_name = from;
00887 m.msg_namelen = sizeof(*from);
00888
00889
00890
00891
00892
00893
00894 v.iov_base = buf;
00895 v.iov_len = len;
00896 m.msg_iov = &v;
00897 m.msg_iovlen = 1;
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907 m.msg_control = control_buf;
00908 m.msg_controllen = control_buf_len;
00909
00910 result = recvmsg(interface->rfdesc, &m, 0);
00911
00912 if (result >= 0) {
00913
00914
00915
00916
00917
00918 cmsg = CMSG_FIRSTHDR(&m);
00919 while (cmsg != NULL) {
00920 if ((cmsg->cmsg_level == IPPROTO_IP) &&
00921 (cmsg->cmsg_type == IP_PKTINFO)) {
00922 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
00923 ifindex = pktinfo->ipi_ifindex;
00924
00925
00926
00927
00928
00929
00930 memcpy(hfrom->hbuf, &ifindex, sizeof(ifindex));
00931 return (result);
00932 }
00933 cmsg = CMSG_NXTHDR(&m, cmsg);
00934 }
00935
00936
00937
00938
00939
00940 result = -1;
00941 errno = EIO;
00942 }
00943 #else
00944 result = recvfrom(interface -> rfdesc, (char *)buf, len, 0,
00945 (struct sockaddr *)from, &flen);
00946 #endif
00947 #ifdef IGNORE_HOSTUNREACH
00948 } while (result < 0 &&
00949 (errno == EHOSTUNREACH ||
00950 errno == ECONNREFUSED) &&
00951 retry++ < 10);
00952 #endif
00953 return (result);
00954 }
00955
00956 #endif
00957
00958 #ifdef DHCPv6
00959 ssize_t
00960 receive_packet6(struct interface_info *interface,
00961 unsigned char *buf, size_t len,
00962 struct sockaddr_in6 *from, struct in6_addr *to_addr,
00963 unsigned int *if_idx)
00964 {
00965 struct msghdr m;
00966 struct iovec v;
00967 int result;
00968 struct cmsghdr *cmsg;
00969 struct in6_pktinfo *pktinfo;
00970
00971
00972
00973
00974
00975 if (control_buf == NULL) {
00976 allocate_cmsg_cbuf();
00977 if (control_buf == NULL) {
00978 log_error("receive_packet6: unable to allocate cmsg "
00979 "header");
00980 return(ENOMEM);
00981 }
00982 }
00983 memset(control_buf, 0, control_buf_len);
00984
00985
00986
00987
00988 memset(&m, 0, sizeof(m));
00989
00990
00991
00992
00993 m.msg_name = from;
00994 m.msg_namelen = sizeof(*from);
00995
00996
00997
00998
00999
01000
01001 v.iov_base = buf;
01002 v.iov_len = len;
01003 m.msg_iov = &v;
01004 m.msg_iovlen = 1;
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014 m.msg_control = control_buf;
01015 m.msg_controllen = control_buf_len;
01016
01017 result = recvmsg(interface->rfdesc, &m, 0);
01018
01019 if (result >= 0) {
01020
01021
01022
01023
01024
01025 cmsg = CMSG_FIRSTHDR(&m);
01026 while (cmsg != NULL) {
01027 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
01028 (cmsg->cmsg_type == IPV6_PKTINFO)) {
01029 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
01030 *to_addr = pktinfo->ipi6_addr;
01031 *if_idx = pktinfo->ipi6_ifindex;
01032
01033 return (result);
01034 }
01035 cmsg = CMSG_NXTHDR(&m, cmsg);
01036 }
01037
01038
01039
01040
01041
01042 result = -1;
01043 errno = EIO;
01044 }
01045
01046 return (result);
01047 }
01048 #endif
01049
01050 #if defined (USE_SOCKET_FALLBACK)
01051
01052
01053 isc_result_t fallback_discard (object)
01054 omapi_object_t *object;
01055 {
01056 char buf [1540];
01057 struct sockaddr_in from;
01058 SOCKLEN_T flen = sizeof from;
01059 int status;
01060 struct interface_info *interface;
01061
01062 if (object -> type != dhcp_type_interface)
01063 return DHCP_R_INVALIDARG;
01064 interface = (struct interface_info *)object;
01065
01066 status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0,
01067 (struct sockaddr *)&from, &flen);
01068 #if defined (DEBUG)
01069
01070 if (status < 0) {
01071 log_error ("fallback_discard: %m");
01072 return ISC_R_UNEXPECTED;
01073 }
01074 #else
01075
01076 IGNORE_UNUSED(status);
01077 #endif
01078 return ISC_R_SUCCESS;
01079 }
01080 #endif
01081
01082 #if defined (USE_SOCKET_SEND)
01083 int can_unicast_without_arp (ip)
01084 struct interface_info *ip;
01085 {
01086 return 0;
01087 }
01088
01089 int can_receive_unicast_unconfigured (ip)
01090 struct interface_info *ip;
01091 {
01092 #if defined (SOCKET_CAN_RECEIVE_UNICAST_UNCONFIGURED)
01093 return 1;
01094 #else
01095 return 0;
01096 #endif
01097 }
01098
01099 int supports_multiple_interfaces (ip)
01100 struct interface_info *ip;
01101 {
01102 #if defined(SO_BINDTODEVICE) || \
01103 (defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && \
01104 defined(USE_V4_PKTINFO))
01105 return(1);
01106 #else
01107 return(0);
01108 #endif
01109 }
01110
01111
01112
01113
01114 void maybe_setup_fallback ()
01115 {
01116 #if defined (USE_SOCKET_FALLBACK)
01117 isc_result_t status;
01118 struct interface_info *fbi = (struct interface_info *)0;
01119 if (setup_fallback (&fbi, MDL)) {
01120 fbi -> wfdesc = if_register_socket (fbi, AF_INET, 0, NULL);
01121 fbi -> rfdesc = fbi -> wfdesc;
01122 log_info ("Sending on Socket/%s%s%s",
01123 fbi -> name,
01124 (fbi -> shared_network ? "/" : ""),
01125 (fbi -> shared_network ?
01126 fbi -> shared_network -> name : ""));
01127
01128 status = omapi_register_io_object ((omapi_object_t *)fbi,
01129 if_readsocket, 0,
01130 fallback_discard, 0, 0);
01131 if (status != ISC_R_SUCCESS)
01132 log_fatal ("Can't register I/O handle for %s: %s",
01133 fbi -> name, isc_result_totext (status));
01134 interface_dereference (&fbi, MDL);
01135 }
01136 #endif
01137 }
01138
01139
01140 #if defined(sun) && defined(USE_V4_PKTINFO)
01141
01142 void
01143 get_hw_addr(const char *name, struct hardware *hw) {
01144 struct sockaddr_dl *dladdrp;
01145 int sock, i;
01146 struct lifreq lifr;
01147
01148 memset(&lifr, 0, sizeof (lifr));
01149 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
01150
01151
01152
01153
01154 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
01155 ioctl(sock, SIOCGLIFFLAGS, &lifr) < 0) {
01156 if (sock != -1)
01157 (void) close(sock);
01158
01159 #ifdef DHCPv6
01160
01161
01162
01163 if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) >= 0 &&
01164 ioctl(sock, SIOCGLIFFLAGS, &lifr) >= 0) {
01165 goto flag_check;
01166 }
01167 if (sock != -1)
01168 (void) close(sock);
01169 #endif
01170 log_fatal("Couldn't get interface flags for %s: %m", name);
01171
01172 }
01173
01174 flag_check:
01175 if (lifr.lifr_flags & (IFF_VIRTUAL|IFF_IPMP)) {
01176 hw->hlen = sizeof (hw->hbuf);
01177 srandom((long)gethrtime());
01178
01179 hw->hbuf[0] = HTYPE_IPMP;
01180 for (i = 1; i < hw->hlen; ++i) {
01181 hw->hbuf[i] = random() % 256;
01182 }
01183
01184 if (sock != -1)
01185 (void) close(sock);
01186 return;
01187 }
01188
01189 if (ioctl(sock, SIOCGLIFHWADDR, &lifr) < 0)
01190 log_fatal("Couldn't get interface hardware address for %s: %m",
01191 name);
01192 dladdrp = (struct sockaddr_dl *)&lifr.lifr_addr;
01193 hw->hlen = dladdrp->sdl_alen+1;
01194 switch (dladdrp->sdl_type) {
01195 case DL_CSMACD:
01196 case DL_ETHER:
01197 hw->hbuf[0] = HTYPE_ETHER;
01198 break;
01199 case DL_TPR:
01200 hw->hbuf[0] = HTYPE_IEEE802;
01201 break;
01202 case DL_FDDI:
01203 hw->hbuf[0] = HTYPE_FDDI;
01204 break;
01205 case DL_IB:
01206 hw->hbuf[0] = HTYPE_INFINIBAND;
01207 break;
01208 default:
01209 log_fatal("%s: unsupported DLPI MAC type %lu", name,
01210 (unsigned long)dladdrp->sdl_type);
01211 }
01212
01213 memcpy(hw->hbuf+1, LLADDR(dladdrp), hw->hlen-1);
01214
01215 if (sock != -1)
01216 (void) close(sock);
01217 }
01218 #endif
01219
01220 #endif