Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:GA
dhcp.4389
0016-infiniband-support.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0016-infiniband-support.patch of Package dhcp.4389
References: bnc#870535,bsc#909189,bsc#910984 From 92250da05c2e4e3f1f60d627b52fe3f4f14828d3 Mon Sep 17 00:00:00 2001 From: Marius Tomaschewski <mt@suse.de> Date: Mon, 14 Sep 2015 13:42:34 +0200 Subject: [PATCH] infiniband-support Squashed rework based on the following commits: commit 8f5918fa4319fc8173ca6e75d6e2ab8c379e980d Author: Marius Tomaschewski <mt@suse.de> Date: Mon Sep 14 12:26:12 2015 +0200 dhcp 4.3.3 ip over ib support fixes (bsc#910984) - verify client-identifier in responses as defined by RFC6864 - generate RFC4361 client-identifier for infiniband as required by RFC4390; config file can still override it using send statement. - fixed to set the ib hwaddr and guard copying/compares to chaddr; it is used for client-identifier, improved xid and other things. - fixed lpf send_packet to not break unicast on fallback socket. commit 3173fd96fe8873f7924f8b5c3f2a6a34ebe1c90c Author: root <root@reg-ovm-036-004.lab.mtl.com> Date: Tue Mar 25 23:30:18 2014 +0200 dhcp 4.3.2 improved xid References: bnc#870535 commit 7e27105baa2a86469efa17fe70667baa8bcc627f Author: Jiri Slaby <jslaby@suse.cz> Date: Wed Dec 10 13:48:03 2014 +0100 dhcp-4.2.x-handle-ifa_addr-NULL.909189 Fix to not crash in interface discovery when the interface address is NULL. Bug has been introduced by the infiniband support patch (bsc#870535). References: bsc#909189,bnc#870535 commit 7818a340f84c0fe3c750baa721fb4221e2e2d443 Author: root <root@reg-ovm-036-004.lab.mtl.com> Date: Tue Mar 25 23:15:58 2014 +0200 dhcp 4.3.2 lpf ip over ib support References: bnc#870535 diff --git a/client/dhclient.c b/client/dhclient.c index 0c77ae2..b438629 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -104,6 +104,40 @@ static int check_option_values(struct universe *universe, unsigned int opt, static void dhclient_ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, char* file, int line); +static void form_interface_duid(struct data_string *duid, struct interface_info *ip, const char *file, int line); + +static int check_client_identifier(struct option_state *packet_options, struct option_state *client_options) +{ + struct option_cache *client_oc; + struct option_cache *packet_oc; + + /* RFC6864 check: + * + * When a client receives a DHCP message containing a 'client + * identifier' option, the client MUST compare that client + * identifier to the one it is configured to send. + * If the two client identifiers do not match, the client MUST + * silently discard the message. + */ + + /* no identifier received: not RFC6864 server ... */ + if (!packet_options || !(packet_oc = lookup_option(&dhcp_universe, packet_options, + DHO_DHCP_CLIENT_IDENTIFIER))) + return 1; + + /* client does not remember them in some cases ... */ + if (!client_options || !(client_oc = lookup_option(&dhcp_universe, client_options, + DHO_DHCP_CLIENT_IDENTIFIER))) + return 1; + + /* when we've sent one, the identifiers MUST match */ + if (client_oc->data.len != packet_oc->data.len || + memcmp(client_oc->data.data, packet_oc->data.data, client_oc->data.len)) + return -1; + + return 0; +} + #ifndef UNIT_TEST int main(int argc, char **argv) { @@ -635,6 +669,26 @@ main(int argc, char **argv) { } } + /* We create a backup seed before rediscovering interfaces in order to + have a seed built using all of the available interfaces + It's interesting if required interfaces doesn't let us defined + a really unique seed due to a lack of valid HW addr later + (this is the case with DHCP over IB) + We only use the last device as using a sum could broke the + uniqueness of the seed among multiple nodes + */ + unsigned backup_seed = 0; + for (ip = interfaces; ip; ip = ip -> next) { + int junk; + if ( ip -> hw_address.hlen <= sizeof seed ) + continue; + memcpy (&junk, + &ip -> hw_address.hbuf [ip -> hw_address.hlen - + sizeof seed], sizeof seed); + backup_seed = junk; + } + + /* At this point, all the interfaces that the script thinks are relevant should be running, so now we once again call discover_interfaces(), and this time ask it to actually set @@ -649,19 +703,42 @@ main(int argc, char **argv) { Not much entropy, but we're booting, so we're not likely to find anything better. */ seed = 0; + int seed_flag = 0; for (ip = interfaces; ip; ip = ip->next) { int junk; + if (ip->hw_address.hlen <= sizeof seed) + continue; memcpy(&junk, &ip->hw_address.hbuf[ip->hw_address.hlen - sizeof seed], sizeof seed); seed += junk; + seed_flag = 1; } - srandom(seed + cur_time + (unsigned)getpid()); + if ( seed_flag == 0 ) { + if ( backup_seed != 0 ) { + seed = backup_seed; + log_info ("xid: rand init seed (0x%x) built using all" + " available interfaces",seed); + } + else { + seed = cur_time^((unsigned) gethostid()) ; + log_info ("xid: warning: no netdev with useable HWADDR found" + " for seed's uniqueness enforcement"); + log_info ("xid: rand init seed (0x%x) built using gethostid", + seed); + } + /* we only use seed and no current time as a broadcast reply */ + /* will certainly be used by the hwaddrless interface */ + srandom(seed); + } + else + srandom(seed + cur_time + (unsigned)getpid()); /* * Establish a default DUID. We always do so for v6 and - * do so if desired for v4 via the -D or -i options + * do so if desired for v4 via the -D or -i options or + * when an infiniband interface is involved. */ if ((local_family == AF_INET6) || ((local_family == AF_INET) && (duid_v4 == 1))) { @@ -672,6 +749,20 @@ main(int argc, char **argv) { form_duid(&default_duid, MDL); write_duid(&default_duid); } + } else { + for (ip = interfaces; ip; ip = ip->next) { + if (!ip->client || ip->hw_address.hbuf[0] != HTYPE_INFINIBAND) + continue; + + if (default_duid.len == 0) { + if (default_duid.buffer != NULL) + data_string_forget(&default_duid, MDL); + + form_duid(&default_duid, MDL); + write_duid(&default_duid); + break; + } + } } /* Start a configuration state machine for each interface. */ @@ -1143,15 +1234,22 @@ void dhcpack (packet) if (client -> xid == packet -> raw -> xid) break; } - if (!client || - (packet -> interface -> hw_address.hlen - 1 != - packet -> raw -> hlen) || - (memcmp (&packet -> interface -> hw_address.hbuf [1], - packet -> raw -> chaddr, packet -> raw -> hlen))) { + + if (!client || (packet -> raw -> hlen && + ((packet -> interface -> hw_address.hlen - 1 != + packet -> raw -> hlen) || + (memcmp (&packet -> interface -> hw_address.hbuf [1], + packet -> raw -> chaddr, packet -> raw -> hlen))))) { #if defined (DEBUG) log_debug ("DHCPACK in wrong transaction."); #endif return; + } else + if (check_client_identifier(packet->options, client->sent_options) < 0) { +#if defined (DEBUG) + log_debug ("response client identifier does not match ours"); +#endif + return; } if (client -> state != S_REBOOTING && @@ -1164,7 +1262,7 @@ void dhcpack (packet) return; } - log_info ("DHCPACK from %s", piaddr (packet -> client_addr)); + log_info ("DHCPACK from %s (xid=0x%x)", piaddr (packet -> client_addr), client -> xid); lease = packet_to_lease (packet, client); if (!lease) { @@ -1629,15 +1727,21 @@ void dhcpoffer (packet) /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ if (!client || - client -> state != S_SELECTING || - (packet -> interface -> hw_address.hlen - 1 != - packet -> raw -> hlen) || - (memcmp (&packet -> interface -> hw_address.hbuf [1], - packet -> raw -> chaddr, packet -> raw -> hlen))) { + client -> state != S_SELECTING || (packet -> raw -> hlen && + ((packet -> interface -> hw_address.hlen - 1 != + packet -> raw -> hlen) || + (memcmp (&packet -> interface -> hw_address.hbuf [1], + packet -> raw -> chaddr, packet -> raw -> hlen))))) { #if defined (DEBUG) log_debug ("%s in wrong transaction.", name); #endif return; + } else + if (check_client_identifier(packet->options, client->sent_options) < 0) { +#if defined (DEBUG) + log_debug ("response client identifier does not match ours"); +#endif + return; } sprintf (obuf, "%s from %s", name, piaddr (packet -> client_addr)); @@ -1875,11 +1979,11 @@ void dhcpnak (packet) /* If we're not receptive to an offer right now, or if the offer has an unrecognizable transaction id, then just drop it. */ - if (!client || - (packet -> interface -> hw_address.hlen - 1 != - packet -> raw -> hlen) || - (memcmp (&packet -> interface -> hw_address.hbuf [1], - packet -> raw -> chaddr, packet -> raw -> hlen))) { + if (!client || (packet -> raw -> hlen && + ((packet -> interface -> hw_address.hlen - 1 != + packet -> raw -> hlen) || + (memcmp (&packet -> interface -> hw_address.hbuf [1], + packet -> raw -> chaddr, packet -> raw -> hlen))))) { #if defined (DEBUG) log_debug ("DHCPNAK in wrong transaction."); #endif @@ -1894,9 +1998,15 @@ void dhcpnak (packet) log_debug ("DHCPNAK in wrong state."); #endif return; + } else + if (check_client_identifier(packet->options, client->sent_options) < 0) { +#if defined (DEBUG) + log_debug ("response client identifier does not match ours"); +#endif + return; } - log_info ("DHCPNAK from %s", piaddr (packet -> client_addr)); + log_info ("DHCPNAK from %s (xid=0x%x)", piaddr (packet -> client_addr), client -> xid); if (!client -> active) { #if defined (DEBUG) @@ -2023,10 +2133,10 @@ void send_discover (cpp) client -> packet.secs = htons (65535); client -> secs = client -> packet.secs; - log_info ("DHCPDISCOVER on %s to %s port %d interval %ld", - client -> name ? client -> name : client -> interface -> name, - inet_ntoa (sockaddr_broadcast.sin_addr), - ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval)); + log_info ("DHCPDISCOVER on %s to %s port %d interval %ld (xid=0x%x)", + client -> name ? client -> name : client -> interface -> name, + inet_ntoa (sockaddr_broadcast.sin_addr), + ntohs (sockaddr_broadcast.sin_port), (long)(client -> interval), client -> xid); /* Send out a packet. */ result = send_packet(client->interface, NULL, &client->packet, @@ -2295,10 +2405,10 @@ void send_request (cpp) client -> packet.secs = htons (65535); } - log_info ("DHCPREQUEST on %s to %s port %d", + log_info ("DHCPREQUEST on %s to %s port %d (xid=0x%x)", client -> name ? client -> name : client -> interface -> name, inet_ntoa (destination.sin_addr), - ntohs (destination.sin_port)); + ntohs (destination.sin_port), client -> xid); if (destination.sin_addr.s_addr != INADDR_BROADCAST && fallback_interface) { @@ -2338,10 +2448,10 @@ void send_decline (cpp) int result; - log_info ("DHCPDECLINE on %s to %s port %d", + log_info ("DHCPDECLINE on %s to %s port %d (xid=0x%x)", client->name ? client->name : client->interface->name, inet_ntoa(sockaddr_broadcast.sin_addr), - ntohs(sockaddr_broadcast.sin_port)); + ntohs (sockaddr_broadcast.sin_port), client -> xid); /* Send out a packet. */ result = send_packet(client->interface, NULL, &client->packet, @@ -2384,10 +2494,10 @@ void send_release (cpp) return; } - log_info ("DHCPRELEASE on %s to %s port %d", + log_info ("DHCPRELEASE on %s to %s port %d (xid=0x%x)", client -> name ? client -> name : client -> interface -> name, inet_ntoa (destination.sin_addr), - ntohs (destination.sin_port)); + ntohs (destination.sin_port), client -> xid); if (fallback_interface) { result = send_packet(fallback_interface, NULL, &client->packet, @@ -2507,10 +2617,17 @@ make_client_options(struct client_state *client, struct client_lease *lease, * This can be overridden by including a client id in the configuration * file. */ - if (duid_v4 == 1) { + if (duid_v4 == 1 || client->interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) { struct data_string client_identifier; int hw_idx, hw_len; + if (default_duid.len == 0) { + if (default_duid.buffer != NULL) + data_string_forget(&default_duid, MDL); + + form_interface_duid(&default_duid, client->interface, MDL); + } + memset(&client_identifier, 0, sizeof(client_identifier)); client_identifier.len = 1 + 4 + default_duid.len; if (!buffer_allocate(&client_identifier.buffer, @@ -2600,12 +2717,13 @@ void make_discover (client, lease) client -> packet.op = BOOTREQUEST; client -> packet.htype = client -> interface -> hw_address.hbuf [0]; - client -> packet.hlen = client -> interface -> hw_address.hlen - 1; + if (client -> interface -> hw_address.hlen - 1 <= sizeof(client -> packet.chaddr)) + client -> packet.hlen = client -> interface -> hw_address.hlen - 1; client -> packet.hops = 0; client -> packet.xid = random (); client -> packet.secs = 0; /* filled in by send_discover. */ - if (can_receive_unicast_unconfigured (client -> interface)) + if (can_receive_unicast_unconfigured (client -> interface) && client -> packet.hlen) client -> packet.flags = 0; else client -> packet.flags = htons (BOOTP_BROADCAST); @@ -2617,7 +2735,7 @@ void make_discover (client, lease) memset (&(client -> packet.siaddr), 0, sizeof client -> packet.siaddr); client -> packet.giaddr = giaddr; - if (client -> interface -> hw_address.hlen > 0) + if (client -> interface -> hw_address.hlen > 1 && client -> packet.hlen) memcpy (client -> packet.chaddr, &client -> interface -> hw_address.hbuf [1], (unsigned)(client -> interface -> hw_address.hlen - 1)); @@ -2673,7 +2791,8 @@ void make_request (client, lease) client -> packet.op = BOOTREQUEST; client -> packet.htype = client -> interface -> hw_address.hbuf [0]; - client -> packet.hlen = client -> interface -> hw_address.hlen - 1; + if (client -> interface -> hw_address.hlen - 1 <= sizeof(client -> packet.chaddr)) + client -> packet.hlen = client -> interface -> hw_address.hlen - 1; client -> packet.hops = 0; client -> packet.xid = client -> xid; client -> packet.secs = 0; /* Filled in by send_request. */ @@ -2705,7 +2824,7 @@ void make_request (client, lease) else memset (&client -> packet.giaddr, 0, sizeof client -> packet.giaddr); - if (client -> interface -> hw_address.hlen > 0) + if (client -> interface -> hw_address.hlen > 1 && client -> packet.hlen) memcpy (client -> packet.chaddr, &client -> interface -> hw_address.hbuf [1], (unsigned)(client -> interface -> hw_address.hlen - 1)); @@ -2747,7 +2866,8 @@ void make_decline (client, lease) client -> packet.op = BOOTREQUEST; client -> packet.htype = client -> interface -> hw_address.hbuf [0]; - client -> packet.hlen = client -> interface -> hw_address.hlen - 1; + if (client -> interface -> hw_address.hlen - 1 <= sizeof(client -> packet.chaddr)) + client -> packet.hlen = client -> interface -> hw_address.hlen - 1; client -> packet.hops = 0; client -> packet.xid = client -> xid; client -> packet.secs = 0; /* Filled in by send_request. */ @@ -2764,9 +2884,10 @@ void make_decline (client, lease) memset (&client -> packet.siaddr, 0, sizeof client -> packet.siaddr); client -> packet.giaddr = giaddr; - memcpy (client -> packet.chaddr, - &client -> interface -> hw_address.hbuf [1], - client -> interface -> hw_address.hlen); + if (client -> interface -> hw_address.hlen > 1 && client -> packet.hlen) + memcpy (client -> packet.chaddr, + &client -> interface -> hw_address.hbuf [1], + client -> interface -> hw_address.hlen - 1); #ifdef DEBUG_PACKET dump_raw ((unsigned char *)&client -> packet, client -> packet_length); @@ -2808,7 +2929,8 @@ void make_release (client, lease) client -> packet.op = BOOTREQUEST; client -> packet.htype = client -> interface -> hw_address.hbuf [0]; - client -> packet.hlen = client -> interface -> hw_address.hlen - 1; + if (client -> interface -> hw_address.hlen - 1 <= sizeof(client -> packet.chaddr)) + client -> packet.hlen = client -> interface -> hw_address.hlen - 1; client -> packet.hops = 0; client -> packet.xid = random (); client -> packet.secs = 0; @@ -2820,9 +2942,10 @@ void make_release (client, lease) memset (&client -> packet.siaddr, 0, sizeof client -> packet.siaddr); client -> packet.giaddr = giaddr; - memcpy (client -> packet.chaddr, - &client -> interface -> hw_address.hbuf [1], - client -> interface -> hw_address.hlen); + if (client -> interface -> hw_address.hlen > 1 && client -> packet.hlen) + memcpy (client -> packet.chaddr, + &client -> interface -> hw_address.hbuf [1], + client -> interface -> hw_address.hlen); #ifdef DEBUG_PACKET dump_raw ((unsigned char *)&client -> packet, client -> packet_length); @@ -2975,17 +3098,13 @@ write_options(struct client_state *client, struct option_state *options, * is not how it is intended. Upcoming rearchitecting the client should * address this "one daemon model." */ -void -form_duid(struct data_string *duid, const char *file, int line) +static void +form_interface_duid(struct data_string *duid, struct interface_info *ip, const char *file, int line) { - struct interface_info *ip; int len; char *str; - /* For now, just use the first interface on the list. */ - ip = interfaces; - - if (ip == NULL) + if (ip == NULL || duid == NULL) log_fatal("Impossible condition at %s:%d.", MDL); if ((ip->hw_address.hlen == 0) || @@ -3033,6 +3152,13 @@ form_duid(struct data_string *duid, const char *file, int line) } } +void +form_duid(struct data_string *duid, const char *file, int line) +{ + /* For now, just use the first interface on the list. */ + form_interface_duid(duid, interfaces, file, line); +} + /* Write the default DUID to the lease store. */ static isc_result_t write_duid(struct data_string *duid) @@ -4368,7 +4494,8 @@ client_dns_update(struct client_state *client, dhcp_ddns_cb_t *ddns_cb) NULL, client, client->sent_options, NULL, &global_scope, oc, MDL)) { - if ((std_dhcid == 1) && (duid_v4 == 1) && + if ((std_dhcid == 1) && (duid_v4 == 1 || + client->interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) && (client_identifier.data[0] == 255)) { /* * This appears to be an embedded DUID, diff --git a/common/bpf.c b/common/bpf.c index df9facc..23d416a 100644 --- a/common/bpf.c +++ b/common/bpf.c @@ -117,7 +117,7 @@ int if_register_bpf (info) log_fatal ("Can't attach interface %s to bpf device %s: %m", info -> name, filename); - get_hw_addr(info->name, &info->hw_address); + get_hw_addr(info); return sock; } @@ -199,11 +199,44 @@ struct bpf_insn dhcp_bpf_filter [] = { BPF_STMT(BPF_RET+BPF_K, 0), }; +/* Packet filter program for DHCP over Infiniband. + * It is a generic UDP in IP packet filter (initialized to port 67 in [6].k). + * + * XXX + * Changes to the filter program may require changes to the constant offsets + * used in lpf_gen_filter_setup to patch the port in the BPF program! + * XXX + */ +struct bpf_insn dhcp_ib_bpf_filter [] = { + /* Make sure it's a UDP packet... */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 9), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), + + /* Make sure this isn't a fragment... */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 6), + BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), + + /* Get the IP header length... */ + BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0), + + /* Make sure it's to the right port... */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, 2), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), + + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT(BPF_RET + BPF_K, (u_int)-1), + + /* Otherwise, drop it. */ + BPF_STMT(BPF_RET + BPF_K, 0), +}; + #if defined (DEC_FDDI) struct bpf_insn *bpf_fddi_filter; #endif int dhcp_bpf_filter_len = sizeof dhcp_bpf_filter / sizeof (struct bpf_insn); +int dhcp_ib_bpf_filter_len = sizeof dhcp_ib_bpf_filter / sizeof (struct bpf_insn); + #if defined (HAVE_TR_SUPPORT) struct bpf_insn dhcp_bpf_tr_filter [] = { /* accept all token ring packets due to variable length header */ @@ -550,7 +583,9 @@ void maybe_setup_fallback () #if defined(USE_BPF_RECEIVE) || defined(USE_BPF_HWADDR) void -get_hw_addr(const char *name, struct hardware *hw) { +get_hw_addr(struct interface_info *info) { + const char *name = info->name; + struct hardware *hw = &info->hw_address; struct ifaddrs *ifa; struct ifaddrs *p; struct sockaddr_dl *sa; diff --git a/common/dlpi.c b/common/dlpi.c index 944f21c..5cc2f3b 100644 --- a/common/dlpi.c +++ b/common/dlpi.c @@ -1330,7 +1330,9 @@ void maybe_setup_fallback () #endif /* USE_DLPI_SEND */ void -get_hw_addr(const char *name, struct hardware *hw) { +get_hw_addr(struct interface_info *info) { + const char *name = info->name; + struct hardware *hw = &info->hw_address; int sock, unit; long buf[DLPI_MAXDLBUF]; union DL_primitives *dlp; diff --git a/common/lpf.c b/common/lpf.c index 8582f31..745d3c0 100644 --- a/common/lpf.c +++ b/common/lpf.c @@ -47,12 +47,22 @@ #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> +#include <ifaddrs.h> #endif #if defined (USE_LPF_SEND) || defined (USE_LPF_RECEIVE) /* Reinitializes the specified interface after an address change. This is not required for packet-filter APIs. */ +/* Default broadcast address for IPoIB */ +static unsigned char default_ib_bcast_addr[20] = { + 0x00, 0xff, 0xff, 0xff, + 0xff, 0x12, 0x40, 0x1b, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff +}; + #ifdef USE_LPF_SEND void if_reinitialize_send (info) struct interface_info *info; @@ -80,10 +90,25 @@ int if_register_lpf (info) struct sockaddr common; } sa; struct ifreq ifr; + int type; + int protocol; /* Make an LPF socket. */ - if ((sock = socket(PF_PACKET, SOCK_RAW, - htons((short)ETH_P_ALL))) < 0) { + get_hw_addr(info); + + if (info->hw_address.hbuf[0] == HTYPE_INFINIBAND) { + /* + * Infiniband provides a 4-octet encapsulation + * header [08 00 00 00] only, so just omit it. + */ + type = SOCK_DGRAM; + protocol = ETHERTYPE_IP; + } else { + type = SOCK_RAW; + protocol = ETH_P_ALL; + } + + if ((sock = socket(PF_PACKET, type, htons((short)protocol))) < 0) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT || errno == EINVAL) { @@ -107,6 +132,7 @@ int if_register_lpf (info) memset (&sa, 0, sizeof sa); sa.ll.sll_family = AF_PACKET; sa.ll.sll_ifindex = ifr.ifr_ifindex; + sa.ll.sll_protocol = htons(protocol); if (bind (sock, &sa.common, sizeof sa)) { if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || @@ -122,8 +148,6 @@ int if_register_lpf (info) } - get_hw_addr(info->name, &info->hw_address); - return sock; } #endif /* USE_LPF_SEND || USE_LPF_RECEIVE */ @@ -178,6 +202,8 @@ void if_deregister_send (info) in bpf includes... */ extern struct sock_filter dhcp_bpf_filter []; extern int dhcp_bpf_filter_len; +extern struct sock_filter dhcp_ib_bpf_filter []; +extern int dhcp_ib_bpf_filter_len; #if defined (HAVE_TR_SUPPORT) extern struct sock_filter dhcp_bpf_tr_filter []; @@ -185,6 +211,8 @@ extern int dhcp_bpf_tr_filter_len; static void lpf_tr_filter_setup (struct interface_info *); #endif +static void lpf_ib_filter_setup (struct interface_info *); + static void lpf_gen_filter_setup (struct interface_info *); void if_register_receive (info) @@ -206,12 +234,14 @@ void if_register_receive (info) } #endif - #if defined (HAVE_TR_SUPPORT) if (info -> hw_address.hbuf [0] == HTYPE_IEEE802) lpf_tr_filter_setup (info); else #endif + if (info -> hw_address.hbuf [0] == HTYPE_INFINIBAND) + lpf_ib_filter_setup (info); + else lpf_gen_filter_setup (info); if (!quiet_interface_discovery) @@ -276,6 +306,38 @@ static void lpf_gen_filter_setup (info) } } +static void lpf_ib_filter_setup (info) + struct interface_info *info; +{ + struct sock_fprog p; + + memset(&p, 0, sizeof(p)); + + /* Set up the bpf filter program structure */ + p.len = dhcp_ib_bpf_filter_len; + p.filter = dhcp_ib_bpf_filter; + + /* Patch the server port into the LPF program... + XXX changes to filter program may require changes + to the insn number(s) used below! XXX */ + dhcp_ib_bpf_filter [6].k = ntohs ((short)local_port); + + if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p, + sizeof p) < 0) { + if (errno == ENOPROTOOPT || errno == EPROTONOSUPPORT || + errno == ESOCKTNOSUPPORT || errno == EPFNOSUPPORT || + errno == EAFNOSUPPORT) { + log_error ("socket: %m - make sure"); + log_error ("CONFIG_PACKET (Packet socket) %s", + "and CONFIG_FILTER"); + log_error ("(Socket Filtering) are enabled %s", + "in your kernel"); + log_fatal ("configuration!"); + } + log_fatal ("Can't install packet filter program: %m"); + } +} + #if defined (HAVE_TR_SUPPORT) static void lpf_tr_filter_setup (info) struct interface_info *info; @@ -315,6 +377,54 @@ static void lpf_tr_filter_setup (info) #endif /* USE_LPF_RECEIVE */ #ifdef USE_LPF_SEND +ssize_t send_packet_ib(interface, packet, raw, len, from, to, hto) + struct interface_info *interface; + struct packet *packet; + struct dhcp_packet *raw; + size_t len; + struct in_addr from; + struct sockaddr_in *to; + struct hardware *hto; +{ + unsigned ibufp = 0; + double ih [1536 / sizeof (double)]; + unsigned char *buf = (unsigned char *)ih; + ssize_t result; + + union sockunion { + struct sockaddr sa; + struct sockaddr_ll sll; + struct sockaddr_storage ss; + } su; + + assemble_udp_ip_header (interface, buf, &ibufp, from.s_addr, + to->sin_addr.s_addr, to->sin_port, + (unsigned char *)raw, len); + memcpy (buf + ibufp, raw, len); + + memset(&su, 0, sizeof(su)); + su.sll.sll_family = AF_PACKET; + su.sll.sll_protocol = htons(ETHERTYPE_IP); + + if (!(su.sll.sll_ifindex = if_nametoindex(interface->name))) { + errno = ENOENT; + log_error ("send_packet_ib: %m - failed to get if index"); + return -1; + } + + su.sll.sll_hatype = htons(HTYPE_INFINIBAND); + su.sll.sll_halen = sizeof(interface->bcast_addr); + memcpy(&su.sll.sll_addr, interface->bcast_addr, 20); + + result = sendto(interface->wfdesc, buf, ibufp + len, 0, + &su.sa, sizeof(su)); + + if (result < 0) + log_error ("send_packet_ib: %m"); + + return result; +} + ssize_t send_packet (interface, packet, raw, len, from, to, hto) struct interface_info *interface; struct packet *packet; @@ -335,6 +445,10 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) return send_fallback (interface, packet, raw, len, from, to, hto); + if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) + return send_packet_ib(interface, packet, raw, + len, from, to, hto); + if (hto == NULL && interface->anycast_mac_addr.hlen) hto = &interface->anycast_mac_addr; @@ -439,7 +553,15 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) bufix = 0; /* Decode the physical header... */ - offset = decode_hw_header (interface, ibuf, bufix, hfrom); + if (interface->hw_address.hbuf[0] == HTYPE_INFINIBAND) { + /* ETHERTYPE_IP packet, no HW header to decode */ + if (hfrom) { + memset(hfrom, 0, sizeof(*hfrom)); + hfrom->hbuf[0] = HTYPE_INFINIBAND; + } + } else { + offset = decode_hw_header (interface, ibuf, bufix, hfrom); + } /* If a physical layer checksum failed (dunno of any physical layer that supports this, but WTH), skip this @@ -507,33 +629,44 @@ void maybe_setup_fallback () #if defined (USE_LPF_RECEIVE) || defined (USE_LPF_HWADDR) void -get_hw_addr(const char *name, struct hardware *hw) { - int sock; - struct ifreq tmp; - struct sockaddr *sa; +get_hw_addr(struct interface_info *info) +{ + const char *name = info->name; + struct hardware *hw = &info->hw_address; + struct ifaddrs *ifaddrs; + struct ifaddrs *ifa; + struct sockaddr_ll *sll = NULL; - if (strlen(name) >= sizeof(tmp.ifr_name)) { - log_fatal("Device name too long: \"%s\"", name); - } + if (getifaddrs(&ifaddrs) == -1) + log_fatal("Failed to get interfaces"); + + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + + if (!ifa->ifa_addr) + continue; + + if (ifa->ifa_addr->sa_family != AF_PACKET) + continue; - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - log_fatal("Can't create socket for \"%s\": %m", name); + if (ifa->ifa_flags & IFF_LOOPBACK) + continue; + + if (strcmp(ifa->ifa_name, name) == 0) { + sll = (struct sockaddr_ll *)(void *)ifa->ifa_addr; + break; + } } - memset(&tmp, 0, sizeof(tmp)); - strcpy(tmp.ifr_name, name); - if (ioctl(sock, SIOCGIFHWADDR, &tmp) < 0) { - log_fatal("Error getting hardware address for \"%s\": %m", - name); + if (sll == NULL || sll->sll_halen >= sizeof(hw->hbuf)) { + freeifaddrs(ifaddrs); + log_fatal("Failed to get HW address for %s\n", name); } - sa = &tmp.ifr_hwaddr; - switch (sa->sa_family) { + switch (sll->sll_hatype) { case ARPHRD_ETHER: hw->hlen = 7; hw->hbuf[0] = HTYPE_ETHER; - memcpy(&hw->hbuf[1], sa->sa_data, 6); + memcpy(&hw->hbuf[1], sll->sll_addr, 6); break; case ARPHRD_IEEE802: #ifdef ARPHRD_IEEE802_TR @@ -541,18 +674,37 @@ get_hw_addr(const char *name, struct hardware *hw) { #endif /* ARPHRD_IEEE802_TR */ hw->hlen = 7; hw->hbuf[0] = HTYPE_IEEE802; - memcpy(&hw->hbuf[1], sa->sa_data, 6); + memcpy(&hw->hbuf[1], sll->sll_addr, 6); break; case ARPHRD_FDDI: hw->hlen = 7; hw->hbuf[0] = HTYPE_FDDI; - memcpy(&hw->hbuf[1], sa->sa_data, 6); + memcpy(&hw->hbuf[1], sll->sll_addr, 6); + break; + case ARPHRD_INFINIBAND: + /* For Infiniband, save the broadcast address and store + * the port GUID into the hardware address. + */ + if (ifa->ifa_flags & IFF_BROADCAST) { + struct sockaddr_ll *bll; + + bll = (struct sockaddr_ll *)ifa->ifa_broadaddr; + memcpy(&info->bcast_addr, bll->sll_addr, sll->sll_halen); + } else { + memcpy(&info->bcast_addr, default_ib_bcast_addr, + sizeof(default_ib_bcast_addr)); + } + + hw->hlen = sll->sll_halen + 1; + hw->hbuf[0] = HTYPE_INFINIBAND; + memcpy(&hw->hbuf[1], sll->sll_addr, sll->sll_halen); break; default: + freeifaddrs(ifaddrs); log_fatal("Unsupported device type %ld for \"%s\"", - (long int)sa->sa_family, name); + (long int)sll->sll_family, name); } - close(sock); + freeifaddrs(ifaddrs); } #endif diff --git a/common/print.c b/common/print.c index dfe0593..aa7b8e2 100644 --- a/common/print.c +++ b/common/print.c @@ -162,11 +162,11 @@ char *print_hw_addr (htype, hlen, data) const int hlen; const unsigned char *data; { - static char habuf [49]; + static char habuf [64]; char *s; int i; - if (hlen <= 0) + if (hlen <= 0 || hlen >= sizeof(habuf)) habuf [0] = 0; else { s = habuf; diff --git a/common/socket.c b/common/socket.c index e8851b4..2c6fb1c 100644 --- a/common/socket.c +++ b/common/socket.c @@ -328,7 +328,7 @@ void if_register_send (info) info->wfdesc = if_register_socket(info, AF_INET, 0, NULL); /* If this is a normal IPv4 address, get the hardware address. */ if (strcmp(info->name, "fallback") != 0) - get_hw_addr(info->name, &info->hw_address); + get_hw_addr(info); #if defined (USE_SOCKET_FALLBACK) /* Fallback only registers for send, but may need to receive as well. */ @@ -391,7 +391,7 @@ void if_register_receive (info) #endif /* IP_PKTINFO... */ /* If this is a normal IPv4 address, get the hardware address. */ if (strcmp(info->name, "fallback") != 0) - get_hw_addr(info->name, &info->hw_address); + get_hw_addr(info); if (!quiet_interface_discovery) log_info ("Listening on Socket/%s%s%s", @@ -505,7 +505,7 @@ if_register6(struct interface_info *info, int do_multicast) { if (req_multi) if_register_multicast(info); - get_hw_addr(info->name, &info->hw_address); + get_hw_addr(info); if (!quiet_interface_discovery) { if (info->shared_network != NULL) { @@ -561,7 +561,7 @@ if_register_linklocal6(struct interface_info *info) { info->rfdesc = sock; info->wfdesc = sock; - get_hw_addr(info->name, &info->hw_address); + get_hw_addr(info); if (!quiet_interface_discovery) { if (info->shared_network != NULL) { @@ -1145,7 +1145,9 @@ void maybe_setup_fallback () #if defined(sun) && defined(USE_V4_PKTINFO) /* This code assumes the existence of SIOCGLIFHWADDR */ void -get_hw_addr(const char *name, struct hardware *hw) { +get_hw_addr(struct interface_info *info) { + const char *name = info->name; + struct hardware *hw = &info->hw_address; struct sockaddr_dl *dladdrp; int sock, i; struct lifreq lifr; diff --git a/includes/dhcpd.h b/includes/dhcpd.h index f0f4b20..0a04f04 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -1321,6 +1321,7 @@ struct interface_info { struct shared_network *shared_network; /* Networks connected to this interface. */ struct hardware hw_address; /* Its physical address. */ + u_int8_t bcast_addr[HARDWARE_ADDR_LEN]; /* broadcast hw address */ struct in_addr *addresses; /* Addresses associated with this * interface. */ @@ -2542,7 +2543,7 @@ void print_dns_status (int, struct dhcp_ddns_cb *, isc_result_t); #endif const char *print_time(TIME); -void get_hw_addr(const char *name, struct hardware *hw); +void get_hw_addr(struct interface_info *info); /* socket.c */ #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \ diff --git a/server/dhcp.c b/server/dhcp.c index 1f007e2..0f53ac2 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -1806,11 +1806,12 @@ void echo_client_id(packet, lease, in_options, out_options) /* Check if echo-client-id is enabled */ oc = lookup_option(&server_universe, in_options, SV_ECHO_CLIENT_ID); - if (oc && evaluate_boolean_option_cache(&ignorep, packet, lease, + if ((packet->raw && packet->raw->hlen == 0) || + (oc && evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, packet->options, in_options, (lease ? &lease->scope : NULL), - oc, MDL)) { + oc, MDL))) { struct data_string client_id; unsigned int opcode = DHO_DHCP_CLIENT_IDENTIFIER; @@ -3592,9 +3593,11 @@ void dhcp_reply (lease) } else bufs |= 2; /* XXX */ - memcpy (raw.chaddr, - &lease -> hardware_addr.hbuf [1], sizeof raw.chaddr); - raw.hlen = lease -> hardware_addr.hlen - 1; + if (lease -> hardware_addr.hlen - 1 <= sizeof(raw.chaddr)) + raw.hlen = lease -> hardware_addr.hlen - 1; + if (lease -> hardware_addr.hlen > 1 && raw.hlen) + memcpy (raw.chaddr, + &lease -> hardware_addr.hbuf [1], raw.hlen); raw.htype = lease -> hardware_addr.hbuf [0]; /* See if this is a Microsoft client that NUL-terminates its diff --git a/server/dhcpleasequery.c b/server/dhcpleasequery.c index 0766b84..c9a1e8b 100644 --- a/server/dhcpleasequery.c +++ b/server/dhcpleasequery.c @@ -295,7 +295,7 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) { assoc_ips, nassoc_ips); - } else { + } else if (packet->raw->hlen) { if (packet->raw->hlen+1 > sizeof(h.hbuf)) { log_info("%s: hardware length too long, " @@ -405,11 +405,13 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) { * Set the hardware address fields. */ - packet->raw->hlen = lease->hardware_addr.hlen - 1; packet->raw->htype = lease->hardware_addr.hbuf[0]; - memcpy(packet->raw->chaddr, - &lease->hardware_addr.hbuf[1], - sizeof(packet->raw->chaddr)); + if (lease->hardware_addr.hlen - 1 <= sizeof(packet->raw->chaddr)) + packet->raw->hlen = lease->hardware_addr.hlen - 1; + if (lease->hardware_addr.hlen > 1 && packet->raw->hlen) + memcpy(packet->raw->chaddr, + &lease->hardware_addr.hbuf[1], + packet->raw->hlen); /* * Set client identifier option. diff --git a/server/mdb.c b/server/mdb.c index 9a7da80..539a233 100644 --- a/server/mdb.c +++ b/server/mdb.c @@ -619,6 +619,9 @@ int find_hosts_by_haddr (struct host_decl **hp, int htype, return ret; #endif + if (!hlen || hlen > HARDWARE_ADDR_LEN) + return 0; + h.hlen = hlen + 1; h.hbuf [0] = htype; memcpy (&h.hbuf [1], haddr, hlen); -- 2.1.4
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor