1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <linux/if.h>
4 #include <linux/if_arp.h>
5
6 #include "arphrd-util.h"
7 #include "device-util.h"
8 #include "log-link.h"
9 #include "memory-util.h"
10 #include "netif-util.h"
11 #include "siphash24.h"
12 #include "sparse-endian.h"
13 #include "strv.h"
14
netif_has_carrier(uint8_t operstate,unsigned flags)15 bool netif_has_carrier(uint8_t operstate, unsigned flags) {
16 /* see Documentation/networking/operstates.txt in the kernel sources */
17
18 if (operstate == IF_OPER_UP)
19 return true;
20
21 if (operstate != IF_OPER_UNKNOWN)
22 return false;
23
24 /* operstate may not be implemented, so fall back to flags */
25 return FLAGS_SET(flags, IFF_LOWER_UP | IFF_RUNNING) &&
26 !FLAGS_SET(flags, IFF_DORMANT);
27 }
28
net_get_type_string(sd_device * device,uint16_t iftype,char ** ret)29 int net_get_type_string(sd_device *device, uint16_t iftype, char **ret) {
30 const char *t;
31 char *p;
32
33 if (device &&
34 sd_device_get_devtype(device, &t) >= 0 &&
35 !isempty(t)) {
36 p = strdup(t);
37 if (!p)
38 return -ENOMEM;
39
40 *ret = p;
41 return 0;
42 }
43
44 t = arphrd_to_name(iftype);
45 if (!t)
46 return -ENOENT;
47
48 p = strdup(t);
49 if (!p)
50 return -ENOMEM;
51
52 *ret = ascii_strlower(p);
53 return 0;
54 }
55
net_get_persistent_name(sd_device * device)56 const char *net_get_persistent_name(sd_device *device) {
57 assert(device);
58
59 /* fetch some persistent data unique (on this machine) to this device */
60 FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
61 const char *name;
62
63 if (sd_device_get_property_value(device, field, &name) >= 0)
64 return name;
65 }
66
67 return NULL;
68 }
69
70 /* Used when generating hardware address by udev, and IPv4LL seed by networkd. */
71 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
72
net_get_unique_predictable_data(sd_device * device,bool use_sysname,uint64_t * ret)73 int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *ret) {
74 const char *name;
75
76 assert(device);
77 assert(ret);
78
79 /* net_get_persistent_name() will return one of the device names based on stable information about
80 * the device. If this is not available, we fall back to using the actual device name. */
81 name = net_get_persistent_name(device);
82 if (!name && use_sysname)
83 (void) sd_device_get_sysname(device, &name);
84 if (!name)
85 return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA),
86 "No stable identifying information found");
87
88 log_device_debug(device, "Using \"%s\" as stable identifying information", name);
89
90 return net_get_unique_predictable_data_from_name(name, &HASH_KEY, ret);
91 }
92
net_get_unique_predictable_data_from_name(const char * name,const sd_id128_t * key,uint64_t * ret)93 int net_get_unique_predictable_data_from_name(
94 const char *name,
95 const sd_id128_t *key,
96 uint64_t *ret) {
97
98 size_t l, sz;
99 uint8_t *v;
100 int r;
101
102 assert(name);
103 assert(key);
104 assert(ret);
105
106 l = strlen(name);
107 sz = sizeof(sd_id128_t) + l;
108 v = newa(uint8_t, sz);
109
110 /* Fetch some persistent data unique to this machine */
111 r = sd_id128_get_machine((sd_id128_t*) v);
112 if (r < 0)
113 return r;
114
115 memcpy(v + sizeof(sd_id128_t), name, l);
116
117 /* Let's hash the machine ID plus the device name. We use
118 * a fixed, but originally randomly created hash key here. */
119 *ret = htole64(siphash24(v, sz, key->bytes));
120 return 0;
121 }
122
123 typedef struct Link {
124 const char *ifname;
125 } Link;
126
net_verify_hardware_address(const char * ifname,bool is_static,uint16_t iftype,const struct hw_addr_data * ib_hw_addr,struct hw_addr_data * new_hw_addr)127 int net_verify_hardware_address(
128 const char *ifname,
129 bool is_static,
130 uint16_t iftype,
131 const struct hw_addr_data *ib_hw_addr, /* current or parent HW address */
132 struct hw_addr_data *new_hw_addr) {
133
134 Link link = { .ifname = ifname };
135
136 assert(new_hw_addr);
137
138 if (new_hw_addr->length == 0)
139 return 0;
140
141 if (new_hw_addr->length != arphrd_to_hw_addr_len(iftype)) {
142 if (is_static)
143 log_link_warning(&link,
144 "Specified MAC address with invalid length (%zu, expected %zu), refusing.",
145 new_hw_addr->length, arphrd_to_hw_addr_len(iftype));
146 return -EINVAL;
147 }
148
149 switch (iftype) {
150 case ARPHRD_ETHER:
151 /* see eth_random_addr() in the kernel */
152
153 if (ether_addr_is_null(&new_hw_addr->ether)) {
154 if (is_static)
155 log_link_warning(&link, "Specified MAC address is null, refusing.");
156 return -EINVAL;
157 }
158
159 if (ether_addr_is_broadcast(&new_hw_addr->ether)) {
160 if (is_static)
161 log_link_warning(&link, "Specified MAC address is broadcast, refusing.");
162 return -EINVAL;
163 }
164
165 if (ether_addr_is_multicast(&new_hw_addr->ether)) {
166 if (is_static)
167 log_link_warning(&link, "Specified MAC address has the multicast bit set, clearing the bit.");
168
169 new_hw_addr->bytes[0] &= 0xfe;
170 }
171
172 if (!is_static && !ether_addr_is_local(&new_hw_addr->ether))
173 /* Adjust local assignment bit when the MAC address is generated randomly. */
174 new_hw_addr->bytes[0] |= 0x02;
175
176 break;
177
178 case ARPHRD_INFINIBAND:
179 /* see ipoib_check_lladdr() in the kernel */
180
181 assert(ib_hw_addr);
182 assert(ib_hw_addr->length == INFINIBAND_ALEN);
183
184 if (is_static &&
185 (!memeqzero(new_hw_addr->bytes, INFINIBAND_ALEN - 8) ||
186 memcmp(new_hw_addr->bytes, ib_hw_addr->bytes, INFINIBAND_ALEN - 8) != 0))
187 log_link_warning(&link, "Only the last 8 bytes of the InifniBand MAC address can be changed, ignoring the first 12 bytes.");
188
189 if (memeqzero(new_hw_addr->bytes + INFINIBAND_ALEN - 8, 8)) {
190 if (is_static)
191 log_link_warning(&link, "The last 8 bytes of the InfiniBand MAC address cannot be null, refusing.");
192 return -EINVAL;
193 }
194
195 memcpy(new_hw_addr->bytes, ib_hw_addr->bytes, INFINIBAND_ALEN - 8);
196 break;
197
198 default:
199 if (is_static)
200 log_link_warning(&link, "Unsupported interface type %s%u to set MAC address, refusing.",
201 strna(arphrd_to_name(iftype)), iftype);
202 return -EINVAL;
203 }
204
205 return 0;
206 }
207