aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/options.c')
-rw-r--r--networking/udhcp/options.c96
1 files changed, 49 insertions, 47 deletions
diff --git a/networking/udhcp/options.c b/networking/udhcp/options.c
index 581a7b671..143a1fd1c 100644
--- a/networking/udhcp/options.c
+++ b/networking/udhcp/options.c
@@ -119,58 +119,61 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = {
119}; 119};
120 120
121 121
122/* get an option with bounds checking (warning, not aligned). */ 122/* get an option with bounds checking (warning, result is not aligned). */
123uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code) 123uint8_t* FAST_FUNC get_option(struct dhcpMessage *packet, int code)
124{ 124{
125 int i, length;
126 uint8_t *optionptr; 125 uint8_t *optionptr;
127 int over = 0; 126 int len;
128 int curr = OPTION_FIELD; 127 int rem;
129 128 int overload = 0;
129 enum {
130 FILE_FIELD101 = FILE_FIELD * 0x101,
131 SNAME_FIELD101 = SNAME_FIELD * 0x101,
132 };
133
134 /* option bytes: [code][len][data1][data2]..[dataLEN] */
130 optionptr = packet->options; 135 optionptr = packet->options;
131 i = 0; 136 rem = sizeof(packet->options);
132 length = sizeof(packet->options);
133 while (1) { 137 while (1) {
134 if (i >= length) { 138 if (rem <= 0) {
135 bb_error_msg("bogus packet, option fields too long"); 139 bb_error_msg("bogus packet, malformed option field");
136 return NULL; 140 return NULL;
137 } 141 }
138 if (optionptr[i + OPT_CODE] == code) { 142 if (optionptr[OPT_CODE] == DHCP_PADDING) {
139 if (i + 1 + optionptr[i + OPT_LEN] >= length) { 143 rem--;
140 bb_error_msg("bogus packet, option fields too long"); 144 optionptr++;
141 return NULL; 145 continue;
142 }
143 return optionptr + i + 2;
144 } 146 }
145 switch (optionptr[i + OPT_CODE]) { 147 if (optionptr[OPT_CODE] == DHCP_END) {
146 case DHCP_PADDING: 148 if ((overload & FILE_FIELD101) == FILE_FIELD) {
147 i++; 149 /* can use packet->file, and didn't look at it yet */
148 break; 150 overload |= FILE_FIELD101; /* "we looked at it" */
149 case DHCP_OPTION_OVER:
150 if (i + 1 + optionptr[i + OPT_LEN] >= length) {
151 bb_error_msg("bogus packet, option fields too long");
152 return NULL;
153 }
154 over = optionptr[i + 3];
155 i += optionptr[OPT_LEN] + 2;
156 break;
157 case DHCP_END:
158 if (curr == OPTION_FIELD && (over & FILE_FIELD)) {
159 optionptr = packet->file; 151 optionptr = packet->file;
160 i = 0; 152 rem = sizeof(packet->file);
161 length = sizeof(packet->file); 153 continue;
162 curr = FILE_FIELD; 154 }
163 } else if (curr == FILE_FIELD && (over & SNAME_FIELD)) { 155 if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
156 /* can use packet->sname, and didn't look at it yet */
157 overload |= SNAME_FIELD101; /* "we looked at it" */
164 optionptr = packet->sname; 158 optionptr = packet->sname;
165 i = 0; 159 rem = sizeof(packet->sname);
166 length = sizeof(packet->sname); 160 continue;
167 curr = SNAME_FIELD; 161 }
168 } else 162 return NULL;
169 return NULL; 163 }
170 break; 164 len = 2 + optionptr[OPT_LEN];
171 default: 165 rem -= len;
172 i += optionptr[OPT_LEN + i] + 2; 166 if (rem < 0)
167 continue; /* complain and return NULL */
168
169 if (optionptr[OPT_CODE] == code)
170 return optionptr + OPT_DATA;
171
172 if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
173 overload |= optionptr[OPT_DATA];
174 /* fall through */
173 } 175 }
176 optionptr += len;
174 } 177 }
175 return NULL; 178 return NULL;
176} 179}
@@ -182,17 +185,16 @@ int FAST_FUNC end_option(uint8_t *optionptr)
182 int i = 0; 185 int i = 0;
183 186
184 while (optionptr[i] != DHCP_END) { 187 while (optionptr[i] != DHCP_END) {
185 if (optionptr[i] == DHCP_PADDING) 188 if (optionptr[i] != DHCP_PADDING)
186 i++; 189 i += optionptr[i + OPT_LEN] + 1;
187 else 190 i++;
188 i += optionptr[i + OPT_LEN] + 2;
189 } 191 }
190 return i; 192 return i;
191} 193}
192 194
193 195
194/* add an option string to the options (an option string contains an option code, 196/* add an option string to the options */
195 * length, then data) */ 197/* option bytes: [code][len][data1][data2]..[dataLEN] */
196int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string) 198int FAST_FUNC add_option_string(uint8_t *optionptr, uint8_t *string)
197{ 199{
198 int end = end_option(optionptr); 200 int end = end_option(optionptr);