Adding upstream version 4.00~pre53+dfsg.
[syslinux-debian/hramrach.git] / core / fs / pxe / dhcp_option.c
blobee1a37850ee66593b008e5dbf60a709eda119fc9
1 #include <stdio.h>
2 #include <string.h>
3 #include <core.h>
4 #include <sys/cpu.h>
5 #include "pxe.h"
7 char LocalDomain[256];
9 int over_load;
10 uint8_t uuid_type;
11 char uuid[17];
13 static void parse_dhcp_options(void *, int, uint8_t);
15 static void subnet_mask(void *data, int opt_len)
17 if (opt_len != 4)
18 return;
19 IPInfo.netmask = *(uint32_t *)data;
22 static void router(void *data, int opt_len)
24 if (opt_len != 4)
25 return;
26 IPInfo.gateway = *(uint32_t *)data;
29 static void dns_servers(void *data, int opt_len)
31 int num = opt_len >> 2;
32 int i;
34 if (num > DNS_MAX_SERVERS)
35 num = DNS_MAX_SERVERS;
37 for (i = 0; i < num; i++) {
38 dns_server[i] = *(uint32_t *)data;
39 data += 4;
42 #if 0
44 * if you find you got no corret DNS server, you can add
45 * it here manually. BUT be carefull the DNS_MAX_SERVERS
47 if (i < DNS_MAX_SERVERS ) {
48 dns_server[i++] = your_master_dns_server;
49 dns_server[i++] = your_second_dns_server;
51 #endif
54 static void local_domain(void *data, int opt_len)
56 char *p = (char *)data + opt_len;
57 char *ld = LocalDomain;
58 char end = *p;
60 *p = '\0'; /* Zero-terminate option */
61 dns_mangle(&ld, data);
62 *p = end; /* Restore ending byte */
65 static void vendor_encaps(void *data, int opt_len)
67 /* Only recongnize PXELINUX options */
68 parse_dhcp_options(data, opt_len, 208);
71 static void option_overload(void *data, int opt_len)
73 if (opt_len != 1)
74 return;
75 over_load = *(uint8_t *)data;
79 static void server(void *data, int opt_len)
81 uint32_t ip;
83 if (opt_len != 4)
84 return;
86 if (IPInfo.serverip)
87 return;
89 ip = *(uint32_t *)data;
90 if (ip_ok(ip))
91 IPInfo.serverip = ip;
94 static void client_identifier(void *data, int opt_len)
96 if (opt_len > MAC_MAX || opt_len < 2 ||
97 MAC_len != (opt_len >> 8) ||
98 *(uint8_t *)data != MAC_type)
99 return;
101 opt_len --;
102 MAC_len = opt_len & 0xff;
103 memcpy(MAC, data+1, opt_len);
104 MAC[opt_len] = 0;
107 static void bootfile_name(void *data, int opt_len)
109 strncpy(boot_file, data, opt_len);
110 boot_file[opt_len] = 0;
113 static void uuid_client_identifier(void *data, int opt_len)
115 int type = *(uint8_t *)data;
116 if (opt_len != 17 || type != 0 || have_uuid)
117 return;
119 have_uuid = true;
120 uuid_type = type;
121 memcpy(uuid, data+1, 16);
122 uuid[16] = 0;
125 static void pxelinux_configfile(void *data, int opt_len)
127 DHCPMagic |= 2;
128 strncpy(ConfigName, data, opt_len);
129 ConfigName[opt_len] = 0;
132 static void pxelinux_pathprefix(void *data, int opt_len)
134 DHCPMagic |= 4;
135 strncpy(path_prefix, data, opt_len);
136 path_prefix[opt_len] = 0;
139 static void pxelinux_reboottime(void *data, int opt_len)
141 if ((opt_len && 0xff) != 4)
142 return ;
144 RebootTime = ntohl(*(uint32_t *)data);
145 DHCPMagic |= 8; /* Got reboot time */
149 struct dhcp_options {
150 int opt_num;
151 void (*fun) (void *, int);
154 static struct dhcp_options dhcp_opts[] = {
155 {1, subnet_mask},
156 {3, router},
157 {6, dns_servers},
158 {15, local_domain},
159 {43, vendor_encaps},
160 {52, option_overload},
161 {54, server},
162 {61, client_identifier},
163 {67, bootfile_name},
164 {97, uuid_client_identifier},
165 {209, pxelinux_configfile},
166 {210, pxelinux_pathprefix},
167 {211, pxelinux_reboottime}
171 * Parse a sequence of DHCP options, pointed to by _option_;
172 * -- some DHCP servers leave option fields unterminated
173 * in violation of the spec.
175 * filter contains the minimum value for the option to recognize
176 * -- this is used to restrict parsing to PXELINUX-specific options only.
178 static void parse_dhcp_options(void *option, int size, uint8_t opt_filter)
180 uint8_t opt_num;
181 uint8_t opt_len;
182 int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]);
183 int i = 0;
184 char *p = option;
185 struct dhcp_options *opt;
187 while (size--) {
188 opt_num = *p++;
190 if (!size)
191 break;
192 if (opt_num == 0)
193 continue;
194 if (opt_num == 0xff)
195 break;
197 /* Anything else will have a lenght filed */
198 opt_len = *p++; /* c <- option lenght */
199 size = size - opt_len - 1;
200 if (size < 0)
201 break;
202 if (opt_num < opt_filter) { /* Is the option value valid */
203 option += opt_len; /* Try next */
204 continue;
207 opt = dhcp_opts;
208 for (i = 0; i < opt_entries; i++) {
209 if (opt_num == opt->opt_num) {
210 opt->fun(p, opt_len);
211 break;
213 opt ++;
216 /* parse next */
217 p += opt_len;
222 * parse_dhcp
224 * Parse a DHCP packet. This includes dealing with "overloaded"
225 * option fields (see RFC 2132, section 9.3)
227 * This should fill in the following global variables, if the
228 * information is present:
230 * MyIP - client IP address
231 * server_ip - boot server IP address
232 * net_mask - network mask
233 * gate_way - default gateway router IP
234 * boot_file - boot file name
235 * DNSServers - DNS server IPs
236 * LocalDomain - Local domain name
237 * MAC_len, MAC - Client identifier, if MAC_len == 0
239 * This assumes the DHCP packet is in "trackbuf".
242 void parse_dhcp(int pkt_len)
244 struct bootp_t *dhcp = (struct bootp_t *)trackbuf;
245 int opt_len;
247 IPInfo.ipv4 = 4; /* This is IPv4 only for now... */
249 over_load = 0;
250 if (ip_ok(dhcp->yip))
251 IPInfo.myip = dhcp->yip;
253 if (ip_ok(dhcp->sip))
254 IPInfo.serverip = dhcp->sip;
256 opt_len = (char *)dhcp + pkt_len - (char *)&dhcp->options;
257 if (opt_len && (dhcp->option_magic == BOOTP_OPTION_MAGIC))
258 parse_dhcp_options(&dhcp->options, opt_len, 0);
260 if (over_load & 1)
261 parse_dhcp_options(&dhcp->bootfile, 128, 0);
262 else if (dhcp->bootfile[0])
263 strcpy(boot_file, dhcp->bootfile);
265 if (over_load & 2)
266 parse_dhcp_options(dhcp->sname, 64, 0);