• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdio.h>
2 #include <string.h>
3 #include <core.h>
4 #include <sys/cpu.h>
5 #include <lwip/opt.h>		/* DNS_MAX_SERVERS */
6 #include <dprintf.h>
7 #include "pxe.h"
8 
9 char LocalDomain[256];
10 
11 int over_load;
12 uint8_t uuid_type;
13 uint8_t uuid[16];
14 
subnet_mask(const void * data,int opt_len)15 static void subnet_mask(const void *data, int opt_len)
16 {
17     if (opt_len != 4)
18 	return;
19     IPInfo.netmask = *(const uint32_t *)data;
20 }
21 
router(const void * data,int opt_len)22 static void router(const void *data, int opt_len)
23 {
24     if (opt_len != 4)
25 	return;
26     IPInfo.gateway = *(const uint32_t *)data;
27 }
28 
dns_servers(const void * data,int opt_len)29 static void dns_servers(const void *data, int opt_len)
30 {
31     const uint32_t *dp = data;
32     int num = 0;
33 
34     while (num < DNS_MAX_SERVERS) {
35 	uint32_t ip;
36 
37 	if (opt_len < 4)
38 	    break;
39 
40 	opt_len -= 4;
41 	ip = *dp++;
42 	if (ip_ok(ip))
43 	    dns_server[num++] = ip;
44     }
45     while (num < DNS_MAX_SERVERS)
46 	dns_server[num++] = 0;
47 }
48 
local_domain(const void * data,int opt_len)49 static void local_domain(const void *data, int opt_len)
50 {
51     memcpy(LocalDomain, data, opt_len);
52     LocalDomain[opt_len] = 0;
53 }
54 
vendor_encaps(const void * data,int opt_len)55 static void vendor_encaps(const void *data, int opt_len)
56 {
57     /* Only recognize PXELINUX options */
58     parse_dhcp_options(data, opt_len, 208);
59 }
60 
option_overload(const void * data,int opt_len)61 static void option_overload(const void *data, int opt_len)
62 {
63     if (opt_len != 1)
64 	return;
65     over_load = *(uint8_t *)data;
66 }
67 
server(const void * data,int opt_len)68 static void server(const void *data, int opt_len)
69 {
70     uint32_t ip;
71 
72     if (opt_len != 4)
73 	return;
74 
75     if (IPInfo.serverip)
76         return;
77 
78     ip = *(uint32_t *)data;
79     if (ip_ok(ip))
80         IPInfo.serverip = ip;
81 }
82 
client_identifier(const void * data,int opt_len)83 static void client_identifier(const void *data, int opt_len)
84 {
85     if (opt_len > MAC_MAX || opt_len < 2 ||
86         MAC_len != (opt_len >> 8) ||
87         *(uint8_t *)data != MAC_type)
88         return;
89 
90     opt_len --;
91     MAC_len = opt_len & 0xff;
92     memcpy(MAC, data+1, opt_len);
93     MAC[opt_len] = 0;
94 }
95 
bootfile_name(const void * data,int opt_len)96 static void bootfile_name(const void *data, int opt_len)
97 {
98     memcpy(boot_file, data, opt_len);
99     boot_file[opt_len] = 0;
100 }
101 
uuid_client_identifier(const void * data,int opt_len)102 static void uuid_client_identifier(const void *data, int opt_len)
103 {
104     int type = *(const uint8_t *)data;
105     if (opt_len != 17 || type != 0 || have_uuid)
106         return;
107 
108     have_uuid = true;
109     uuid_type = type;
110     memcpy(uuid, data+1, 16);
111 }
112 
pxelinux_configfile(const void * data,int opt_len)113 static void pxelinux_configfile(const void *data, int opt_len)
114 {
115     DHCPMagic |= 2;
116     memcpy(ConfigName, data, opt_len);
117     ConfigName[opt_len] = 0;
118 }
119 
pxelinux_pathprefix(const void * data,int opt_len)120 static void pxelinux_pathprefix(const void *data, int opt_len)
121 {
122     DHCPMagic |= 4;
123     memcpy(path_prefix, data, opt_len);
124     path_prefix[opt_len] = 0;
125 }
126 
pxelinux_reboottime(const void * data,int opt_len)127 static void pxelinux_reboottime(const void *data, int opt_len)
128 {
129     if (opt_len != 4)
130         return;
131 
132     RebootTime = ntohl(*(const uint32_t *)data);
133     DHCPMagic |= 8;     /* Got reboot time */
134 }
135 
136 
137 struct dhcp_options {
138     int opt_num;
139     void (*fun)(const void *, int);
140 };
141 
142 static const struct dhcp_options dhcp_opts[] = {
143     {1,   subnet_mask},
144     {3,   router},
145     {6,   dns_servers},
146     {15,  local_domain},
147     {43,  vendor_encaps},
148     {52,  option_overload},
149     {54,  server},
150     {61,  client_identifier},
151     {67,  bootfile_name},
152     {97,  uuid_client_identifier},
153     {209, pxelinux_configfile},
154     {210, pxelinux_pathprefix},
155     {211, pxelinux_reboottime}
156 };
157 
158 /*
159  * Parse a sequence of DHCP options, pointed to by _option_;
160  * -- some DHCP servers leave option fields unterminated
161  * in violation of the spec.
162  *
163  * filter  contains the minimum value for the option to recognize
164  * -- this is used to restrict parsing to PXELINUX-specific options only.
165  */
parse_dhcp_options(const void * option,int size,uint8_t opt_filter)166 void parse_dhcp_options(const void *option, int size, uint8_t opt_filter)
167 {
168     int opt_num;
169     int opt_len;
170     const int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]);
171     int i = 0;
172     const uint8_t *p = option;
173     const struct dhcp_options *opt;
174 
175     /* The only 1-byte options are 00 and FF, neither of which matter */
176     while (size >= 2) {
177         opt_num = *p++;
178 	size--;
179 
180         if (opt_num == 0)
181             continue;
182         if (opt_num == 0xff)
183             break;
184 
185         /* Anything else will have a length field */
186         opt_len = *p++; /* c  <- option lenght */
187         size -= opt_len + 1;
188         if (size < 0)
189             break;
190 
191 	dprintf("DHCP: option %d, len %d\n", opt_num, opt_len);
192 
193 	if (opt_num >= opt_filter) {
194 	    opt = dhcp_opts;
195 	    for (i = 0; i < opt_entries; i++) {
196 		if (opt_num == opt->opt_num) {
197 		    opt->fun(p, opt_len);
198 		    break;
199 		}
200 		opt++;
201 	    }
202 	}
203 
204         /* parse next */
205         p += opt_len;
206     }
207 }
208 
209 /*
210  * parse_dhcp
211  *
212  * Parse a DHCP packet.  This includes dealing with "overloaded"
213  * option fields (see RFC 2132, section 9.3)
214  *
215  * This should fill in the following global variables, if the
216  * information is present:
217  *
218  * MyIP		- client IP address
219  * server_ip	- boot server IP address
220  * net_mask	- network mask
221  * gate_way	- default gateway router IP
222  * boot_file	- boot file name
223  * DNSServers	- DNS server IPs
224  * LocalDomain	- Local domain name
225  * MAC_len, MAC	- Client identifier, if MAC_len == 0
226  *
227  */
parse_dhcp(const void * pkt,size_t pkt_len)228 void parse_dhcp(const void *pkt, size_t pkt_len)
229 {
230     const struct bootp_t *dhcp = (const struct bootp_t *)pkt;
231     int opt_len;
232 
233     IPInfo.ipver = 4;		/* This is IPv4 only for now... */
234 
235     over_load = 0;
236     if (ip_ok(dhcp->yip))
237         IPInfo.myip = dhcp->yip;
238 
239     if (ip_ok(dhcp->sip))
240         IPInfo.serverip = dhcp->sip;
241 
242     opt_len = (char *)dhcp + pkt_len - (char *)&dhcp->options;
243     if (opt_len && (dhcp->option_magic == BOOTP_OPTION_MAGIC))
244         parse_dhcp_options(&dhcp->options, opt_len, 0);
245 
246     if (over_load & 1)
247         parse_dhcp_options(&dhcp->bootfile, 128, 0);
248     else if (dhcp->bootfile[0])
249 	strcpy(boot_file, dhcp->bootfile);
250 
251     if (over_load & 2)
252         parse_dhcp_options(dhcp->sname, 64, 0);
253 }
254