diff options
author | Kevin Steves <stevesk@cvs.openbsd.org> | 2006-11-27 19:32:18 +0000 |
---|---|---|
committer | Kevin Steves <stevesk@cvs.openbsd.org> | 2006-11-27 19:32:18 +0000 |
commit | 5c41c9b5ccfd22ef3c2ba35b5a3b9dac9c0e1410 (patch) | |
tree | 60cdc2595ab49347c3c50f0b0573a2a2333a3fd3 /sbin/dhclient/bpf.c | |
parent | 3ae6368ff3ac2e2ee5e436bfe8b87bbbc3b4ca2a (diff) |
Recognize when we are sending to a unicast destination IP address and
instead of using BPF, which currently will always set the destination
MAC to broadcast, send using a SOCK_RAW socket and sendmsg() so the
frame has a unicast destination MAC.
Fixes an issue when using a bootp forwarder where unicast DHCPREQUESTs
are dropped at the router/gateway until we reach T2/REBINDING and
change the destination IP to broadcast.
ok henning@ (but doesn't like using a raw socket for this)
Diffstat (limited to 'sbin/dhclient/bpf.c')
-rw-r--r-- | sbin/dhclient/bpf.c | 39 |
1 files changed, 32 insertions, 7 deletions
diff --git a/sbin/dhclient/bpf.c b/sbin/dhclient/bpf.c index 4d4681bd94b..eb4c8b5e667 100644 --- a/sbin/dhclient/bpf.c +++ b/sbin/dhclient/bpf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bpf.c,v 1.15 2005/11/26 17:35:35 reyk Exp $ */ +/* $OpenBSD: bpf.c,v 1.16 2006/11/27 19:32:17 stevesk Exp $ */ /* BPF socket interface code, originally contributed by Archie Cobbs. */ @@ -87,11 +87,23 @@ if_register_bpf(struct interface_info *info) void if_register_send(struct interface_info *info) { + int sock, on = 1; + /* * If we're using the bpf API for sending and receiving, we * don't need to register this interface twice. */ info->wfdesc = info->rfdesc; + + /* + * Use raw socket for unicast send. + */ + if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1) + error("socket(SOCK_RAW): %m"); + if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, + sizeof(on)) == -1) + error("setsockopt(IP_HDRINCL): %m"); + info->ufdesc = sock; } /* @@ -242,23 +254,36 @@ send_packet(struct interface_info *interface, struct dhcp_packet *raw, size_t len, struct in_addr from, struct sockaddr_in *to, struct hardware *hto) { +#define IOVCNT 2 unsigned char buf[256]; - struct iovec iov[2]; + struct iovec iov[IOVCNT]; + struct msghdr msg; int result, bufp = 0; - /* Assemble the headers... */ - assemble_hw_header(interface, buf, &bufp, hto); + if (to->sin_addr.s_addr == INADDR_BROADCAST) { + assemble_hw_header(interface, buf, &bufp, hto); + } + assemble_udp_ip_header(buf, &bufp, from.s_addr, to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len); - /* Fire it off */ iov[0].iov_base = (char *)buf; iov[0].iov_len = bufp; iov[1].iov_base = (char *)raw; iov[1].iov_len = len; - result = writev(interface->wfdesc, iov, 2); - if (result < 0) + if (to->sin_addr.s_addr == INADDR_BROADCAST) { + result = writev(interface->wfdesc, iov, IOVCNT); + } else { + memset(&msg, 0, sizeof(msg)); + msg.msg_name = (struct sockaddr *)to; + msg.msg_namelen = sizeof(*to); + msg.msg_iov = iov; + msg.msg_iovlen = IOVCNT; + result = sendmsg(interface->ufdesc, &msg, 0); + } + + if (result == -1) warning("send_packet: %m"); return (result); } |