aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/uml/patches-4.14/102-pseudo-random-mac.patch
blob: 3d3bc63431cc557368970775aba62e31f3c3feeb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
===============================================================================

This patch makes MAC addresses of network interfaces predictable. In
particular, it adds a small routine that computes MAC addresses of based on
a SHA1 hash of the virtual machine name and interface ID.

TECHNICAL INFORMATION:

Applies to vanilla kernel 3.9.4.

===============================================================================
--- a/arch/um/Kconfig.net
+++ b/arch/um/Kconfig.net
@@ -22,6 +22,19 @@ config UML_NET
         enable at least one of the following transport options to actually
         make use of UML networking.
 
+config UML_NET_RANDOM_MAC
+	bool "Use random MAC addresses for network interfaces"
+	default n
+	depends on UML_NET
+	help
+        Virtual network devices inside a User-Mode Linux instance must be
+        assigned a MAC (Ethernet) address. If none is specified on the UML
+        command line, one must be automatically computed. If this option is
+        enabled, a randomly generated address is used. Otherwise, if this
+        option is disabled, the address is generated from a SHA1 hash of
+        the umid of the UML instance and the interface name. The latter choice
+        is useful to make MAC addresses predictable.
+
 config UML_NET_ETHERTAP
 	bool "Ethertap transport"
 	depends on UML_NET
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -25,6 +25,14 @@
 #include <net_kern.h>
 #include <net_user.h>
 
+#include <crypto/sha.h>
+#include <crypto/hash.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/scatterlist.h>
+#include "os.h"
+
 #define DRIVER_NAME "uml-netdev"
 
 static DEFINE_SPINLOCK(opened_lock);
@@ -288,11 +296,53 @@ static void uml_net_user_timer_expire(un
 #endif
 }
 
+#ifndef CONFIG_UML_NET_RANDOM_MAC
+
+/* Compute a SHA1 hash of the UML instance's id and
+ *  * an interface name. */
+static int compute_hash(const char *umid, const char *ifname, char *hash)
+{
+	struct ahash_request *desc;
+	struct crypto_ahash *tfm;
+	struct scatterlist sg;
+	char vmif[1024];
+	int ret;
+
+	strcpy (vmif, umid);
+	strcat (vmif, ifname);
+
+	tfm = crypto_alloc_ahash("sha1", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm))
+		return -ENOMEM;
+
+	desc = ahash_request_alloc(tfm, GFP_KERNEL);
+	if (!desc) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	crypto_ahash_clear_flags(tfm, ~0);
+
+	sg_init_table(&sg, 1);
+	sg_set_buf(&sg, vmif, strlen(vmif));
+
+	ahash_request_set_crypt(desc, &sg, hash, strlen(vmif));
+
+	ret = crypto_ahash_digest(desc);
+out:
+	crypto_free_ahash(tfm);
+
+	return ret;
+}
+
+#endif
+
 static void setup_etheraddr(struct net_device *dev, char *str)
 {
 	unsigned char *addr = dev->dev_addr;
 	char *end;
 	int i;
+	u8 hash[SHA1_DIGEST_SIZE];
 
 	if (str == NULL)
 		goto random;
@@ -333,9 +383,26 @@ static void setup_etheraddr(struct net_d
 	return;
 
 random:
+#ifdef CONFIG_UML_NET_RANDOM_MAC
 	printk(KERN_INFO
 	       "Choosing a random ethernet address for device %s\n", dev->name);
 	eth_hw_addr_random(dev);
+#else
+	printk(KERN_INFO
+	       "Computing a digest to use as ethernet address for device %s\n", dev->name);
+	if (compute_hash(get_umid(), dev->name, hash) < 0) {
+		printk(KERN_WARNING
+		       "Could not compute digest to use as ethernet address for device %s. "
+		       "Using random address instead.\n", dev->name);
+		random_ether_addr(addr);
+	}
+	else {
+		for (i=0; i < 6; i++)
+			addr[i] = (hash[i] + hash[i+6]) % 0x100;
+	}
+	addr [0] &= 0xfe; /* clear multicast bit */
+	addr [0] |= 0x02; /* set local assignment bit (IEEE802) */
+#endif
 }
 
 static DEFINE_SPINLOCK(devices_lock);