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
132
133
134
135
136
137
138
139
140
141
|
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -54,6 +54,7 @@ const struct dhcp_optflag dhcp_optflags[
{ OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */
#endif
{ OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */
+ { OPTION_6RD , 0xd4 }, /* DHCP_6RD */
{ OPTION_STRING , 0xfc }, /* DHCP_WPAD */
/* Options below have no match in dhcp_option_strings[],
@@ -114,6 +115,7 @@ const char dhcp_option_strings[] ALIGN1
// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES
// is not handled yet by "string->option" conversion code:
"staticroutes" "\0"/* DHCP_STATIC_ROUTES */
+ "ip6rd" "\0" /* DHCP_6RD */
"wpad" "\0" /* DHCP_WPAD */
;
@@ -141,6 +143,7 @@ const uint8_t dhcp_option_lengths[] ALIG
[OPTION_S32] = 4,
/* Just like OPTION_STRING, we use minimum length here */
[OPTION_STATIC_ROUTES] = 5,
+ [OPTION_6RD] = 22,
};
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -45,6 +45,7 @@ static const uint8_t len_of_option_as_st
[OPTION_IP ] = sizeof("255.255.255.255 "),
[OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2,
[OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "),
+ [OPTION_6RD ] = sizeof("32 128 FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF 255.255.255.255 "),
[OPTION_STRING ] = 1,
#if ENABLE_FEATURE_UDHCP_RFC3397
[OPTION_DNS_STRING ] = 1, /* unused */
@@ -68,6 +69,23 @@ static int sprint_nip(char *dest, const
return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
}
+static int sprint_nip6(char *dest, const char *pre, const uint8_t *ip)
+{
+ int len = 0;
+ int off;
+ uint16_t word;
+
+ len += sprintf(dest, "%s", pre);
+
+ for (off = 0; off < 16; off += 2)
+ {
+ move_from_unaligned16(word, &ip[off]);
+ len += sprintf(dest+len, "%s%04X", off ? ":" : "", htons(word));
+ }
+
+ return len;
+}
+
/* really simple implementation, just count the bits */
static int mton(uint32_t mask)
{
@@ -177,6 +195,70 @@ static NOINLINE char *xmalloc_optname_op
return ret;
}
+ case OPTION_6RD: {
+ /* Option binary format:
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | OPTION_6RD | option-length | IPv4MaskLen | 6rdPrefixLen |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * | 6rdPrefix |
+ * | (16 octets) |
+ * | |
+ * | |
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 6rdBRIPv4Address(es) |
+ * . .
+ * . .
+ * . .
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * We convert it to a string "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address"
+ */
+
+ /* Sanity check: ensure that our length is at least 22 bytes, that
+ * IPv4MaskLen is <= 32, 6rdPrefixLen <= 128 and that the sum of
+ * (32 - IPv4MaskLen) + 6rdPrefixLen is less than or equal to 128.
+ * If any of these requirements is not fulfilled, return with empty
+ * value.
+ */
+ if ((len >= 22) && (*option <= 32) && (*(option+1) <= 128) &&
+ (((32 - *option) + *(option+1)) <= 128))
+ {
+ /* IPv4MaskLen */
+ dest += sprintf(dest, "%u ", *option++);
+ len--;
+
+ /* 6rdPrefixLen */
+ dest += sprintf(dest, "%u ", *option++);
+ len--;
+
+ /* 6rdPrefix */
+ dest += sprint_nip6(dest, "", option);
+ option += 16;
+ len -= 16;
+
+ /* 6rdBRIPv4Addresses */
+ while (len >= 4)
+ {
+ dest += sprint_nip(dest, " ", option);
+ option += 4;
+ len -= 4;
+
+ /* the code to determine the option size fails to work with
+ * lengths that are not a multiple of the minimum length,
+ * adding all advertised 6rdBRIPv4Addresses here would
+ * overflow the destination buffer, therefore skip the rest
+ * for now
+ */
+ break;
+ }
+ }
+
+ return ret;
+ }
#if ENABLE_FEATURE_UDHCP_RFC3397
case OPTION_DNS_STRING:
/* unpack option into dest; use ret for prefix (i.e., "optname=") */
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -88,6 +88,7 @@ enum {
OPTION_S32,
OPTION_BIN,
OPTION_STATIC_ROUTES,
+ OPTION_6RD,
#if ENABLE_FEATURE_UDHCP_RFC3397
OPTION_DNS_STRING, /* RFC1035 compressed domain name list */
OPTION_SIP_SERVERS,
|