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