aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/uml/patches-5.4/102-pseudo-random-mac.patch
blob: 19696365a1d3eed84fb5bf93920c9d9786727957 (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
===============================================================================

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/drivers/Kconfig
+++ b/arch/um/drivers/Kconfig
@@ -146,6 +146,20 @@ config UML_NET
 	  enable at least one of the following transport options to actually
 	  make use of UML networking.
 
+config UML_NET_DETERMINISTIC_MAC
+	bool "Use deterministic MAC addresses for network interfaces"
+	default y
+	depends on UML_NET
+	select CRYPTO_SHA1
+	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);
@@ -286,9 +294,51 @@ static void uml_net_user_timer_expire(st
 #endif
 }
 
+#ifdef CONFIG_UML_NET_DETERMINISTIC_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
+
 void uml_net_setup_etheraddr(struct net_device *dev, char *str)
 {
 	unsigned char *addr = dev->dev_addr;
+	u8 hash[SHA1_DIGEST_SIZE];
 	char *end;
 	int i;
 
@@ -331,9 +381,26 @@ void uml_net_setup_etheraddr(struct net_
 	return;
 
 random:
+#ifndef CONFIG_UML_NET_DETERMINISTIC_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);