|
@@ -32,6 +32,30 @@
|
32
|
32
|
*
|
33
|
33
|
*/
|
34
|
34
|
|
|
35
|
+/**
|
|
36
|
+ * Calculate used length of an IPv4 field within a DHCP packet
|
|
37
|
+ *
|
|
38
|
+ * @v data Field data
|
|
39
|
+ * @v len Length of field
|
|
40
|
+ * @ret used Used length of field
|
|
41
|
+ */
|
|
42
|
+static size_t used_len_ipv4 ( const void *data, size_t len __unused ) {
|
|
43
|
+ const struct in_addr *in = data;
|
|
44
|
+
|
|
45
|
+ return ( in->s_addr ? sizeof ( *in ) : 0 );
|
|
46
|
+}
|
|
47
|
+
|
|
48
|
+/**
|
|
49
|
+ * Calculate used length of a string field within a DHCP packet
|
|
50
|
+ *
|
|
51
|
+ * @v data Field data
|
|
52
|
+ * @v len Length of field
|
|
53
|
+ * @ret used Used length of field
|
|
54
|
+ */
|
|
55
|
+static size_t used_len_string ( const void *data, size_t len ) {
|
|
56
|
+ return strnlen ( data, len );
|
|
57
|
+}
|
|
58
|
+
|
35
|
59
|
/** A dedicated field within a DHCP packet */
|
36
|
60
|
struct dhcp_packet_field {
|
37
|
61
|
/** Settings tag number */
|
|
@@ -40,25 +64,34 @@ struct dhcp_packet_field {
|
40
|
64
|
uint16_t offset;
|
41
|
65
|
/** Length of field */
|
42
|
66
|
uint16_t len;
|
|
67
|
+ /** Calculate used length of field
|
|
68
|
+ *
|
|
69
|
+ * @v data Field data
|
|
70
|
+ * @v len Length of field
|
|
71
|
+ * @ret used Used length of field
|
|
72
|
+ */
|
|
73
|
+ size_t ( * used_len ) ( const void *data, size_t len );
|
43
|
74
|
};
|
44
|
75
|
|
45
|
76
|
/** Declare a dedicated field within a DHCP packet
|
46
|
77
|
*
|
47
|
78
|
* @v _tag Settings tag number
|
48
|
79
|
* @v _field Field name
|
|
80
|
+ * @v _used_len Function to calculate used length of field
|
49
|
81
|
*/
|
50
|
|
-#define DHCP_PACKET_FIELD( _tag, _field ) { \
|
|
82
|
+#define DHCP_PACKET_FIELD( _tag, _field, _used_len ) { \
|
51
|
83
|
.tag = (_tag), \
|
52
|
84
|
.offset = offsetof ( struct dhcphdr, _field ), \
|
53
|
85
|
.len = sizeof ( ( ( struct dhcphdr * ) 0 )->_field ), \
|
|
86
|
+ .used_len = _used_len, \
|
54
|
87
|
}
|
55
|
88
|
|
56
|
89
|
/** Dedicated fields within a DHCP packet */
|
57
|
90
|
static struct dhcp_packet_field dhcp_packet_fields[] = {
|
58
|
|
- DHCP_PACKET_FIELD ( DHCP_EB_YIADDR, yiaddr ),
|
59
|
|
- DHCP_PACKET_FIELD ( DHCP_EB_SIADDR, siaddr ),
|
60
|
|
- DHCP_PACKET_FIELD ( DHCP_TFTP_SERVER_NAME, sname ),
|
61
|
|
- DHCP_PACKET_FIELD ( DHCP_BOOTFILE_NAME, file ),
|
|
91
|
+ DHCP_PACKET_FIELD ( DHCP_EB_YIADDR, yiaddr, used_len_ipv4 ),
|
|
92
|
+ DHCP_PACKET_FIELD ( DHCP_EB_SIADDR, siaddr, used_len_ipv4 ),
|
|
93
|
+ DHCP_PACKET_FIELD ( DHCP_TFTP_SERVER_NAME, sname, used_len_string ),
|
|
94
|
+ DHCP_PACKET_FIELD ( DHCP_BOOTFILE_NAME, file, used_len_string ),
|
62
|
95
|
};
|
63
|
96
|
|
64
|
97
|
/**
|
|
@@ -138,14 +171,19 @@ int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
|
138
|
171
|
int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
|
139
|
172
|
void *data, size_t len ) {
|
140
|
173
|
struct dhcp_packet_field *field;
|
|
174
|
+ void *field_data;
|
|
175
|
+ size_t field_len;
|
141
|
176
|
|
142
|
177
|
/* If this is a special field, return it */
|
143
|
178
|
if ( ( field = find_dhcp_packet_field ( tag ) ) != NULL ) {
|
144
|
|
- if ( len > field->len )
|
145
|
|
- len = field->len;
|
146
|
|
- memcpy ( data,
|
147
|
|
- dhcp_packet_field ( dhcppkt->dhcphdr, field ), len );
|
148
|
|
- return field->len;
|
|
179
|
+ field_data = dhcp_packet_field ( dhcppkt->dhcphdr, field );
|
|
180
|
+ field_len = field->used_len ( field_data, field->len );
|
|
181
|
+ if ( ! field_len )
|
|
182
|
+ return -ENOENT;
|
|
183
|
+ if ( len > field_len )
|
|
184
|
+ len = field_len;
|
|
185
|
+ memcpy ( data, field_data, len );
|
|
186
|
+ return field_len;
|
149
|
187
|
}
|
150
|
188
|
|
151
|
189
|
/* Otherwise, use the generic options block */
|