socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
}
#endif
+#ifdef __FreeBSD__
+ } else if (inst->broadcast &&
+#ifdef HAVE_LIBPCAP
+ !inst->use_pcap &&
+#endif
+ (inst->interface || if_name[0])) {
+ uint8_t macaddr[6];
+ uint8_t ipaddr[4];
+
+ memcpy(&ipaddr, &packet->yiaddr, 4);
+ memcpy(&macaddr, &packet->chaddr, 6);
+
+ /*
+ * FreeBSD version of above using netlink API
+ */
+ if (fr_bsd_arp_entry_add(socket.inet.ifindex, ipaddr, macaddr) == 0) {
+ DEBUG("Reply will be unicast to YADDR, done ARP table updates.");
+ memcpy(&socket.inet.dst_ipaddr.addr.v4.s_addr, &packet->yiaddr, 4);
+ } else {
+ DEBUG("Failed adding ARP table entry. Reply will be broadcast.");
+ socket.inet.dst_ipaddr.addr.v4.s_addr = INADDR_BROADCAST;
+ }
+#endif
#ifdef HAVE_LIBPCAP
} else if (inst->use_pcap && inst->broadcast && (inst->interface || if_name[0])) {
proto_dhcpv4_pcap_t *pcap;
inst->port = ntohl(s->s_port);
}
-#ifdef SIOCSARP
+#if defined(SIOCSARP) || defined(__FreeBSD__)
/*
* If we're listening for broadcast requests, we MUST
*/
#include <net/if_arp.h>
+#ifdef __FreeBSD__
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <netlink/netlink.h>
+#include <netlink/netlink_route.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_route.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#endif
+
static uint32_t instance_count = 0;
fr_dict_t const *dict_arp;
}
#endif
+#ifdef __FreeBSD__
+/** Use FreeBSD netlink API to add ARP entries
+ */
+int fr_bsd_arp_entry_add(uint32_t ifindex, uint8_t ipaddr[static 4], uint8_t macaddr[static 6])
+{
+ struct sockaddr_in sin;
+ struct sockaddr_dl sdl;
+ struct snl_state state;
+ struct snl_writer nw;
+ struct nlmsghdr *msghdr;
+ struct ndmsg *msg;
+ struct snl_errmsg_data errmsg = {};
+
+ if (ifindex == 0) {
+ fr_strerror_const("Missing interface index");
+ return -1;
+ }
+
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr.s_addr, ipaddr, 4);
+
+ sdl = (struct sockaddr_dl){
+ .sdl_len = sizeof(sdl),
+ .sdl_family = AF_LINK,
+ .sdl_alen = ETHER_ADDR_LEN
+ };
+ memcpy(LLADDR(&sdl), macaddr, ETHER_ADDR_LEN);
+
+ if (!snl_init(&state, NETLINK_ROUTE)) {
+ if (modfind("netlink") == -1 && errno == ENOENT) {
+ if (kldload("netlink") == -1) {
+ fr_strerror_const("netlink is not loaded and load attempt failed");
+ return -1;
+ }
+ } else {
+ open_error:
+ fr_strerror_const("Unable to open netlink socket");
+ }
+ if (!snl_init(&state, NETLINK_ROUTE)) goto open_error;
+ }
+
+ snl_init_writer(&state, &nw);
+ msghdr = snl_create_msg_request(&nw, RTM_NEWNEIGH);
+ msghdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
+
+ msg = snl_reserve_msg_object(&nw, struct ndmsg);
+ if (!msg) {
+ fr_strerror_const("Failed reserving message");
+ error:
+ snl_free(&state);
+ return -1;
+ }
+ msg->ndm_family = AF_INET;
+ msg->ndm_ifindex = ifindex;
+ msg->ndm_state = NUD_PERMANENT;
+ msg->ndm_flags = NTF_STICKY;
+
+ snl_add_msg_attr_ip(&nw, NDA_DST, (struct sockaddr *)&sin);
+ snl_add_msg_attr(&nw, NDA_LLADDR, sdl.sdl_alen, LLADDR(&sdl));
+
+ if (!(msghdr = snl_finalize_msg(&nw)) || !snl_send_message(&state, msghdr)) {
+ fr_strerror_const("Failed sending netlink message.");
+ goto error;
+ }
+
+ snl_read_reply_code(&state, msghdr->nlmsg_seq, &errmsg);
+ if (errmsg.error != 0) {
+ fr_strerror_printf("Failed adding ARP table entry: %s (%s)", strerror(errmsg.error), errmsg.error_str);
+ goto error;
+ }
+
+ snl_free(&state);
+
+ return 0;
+}
+#endif
/** Encode VPS into a raw ARP packet.
*