1 /*
2  * pxe-pdhcp
3  *
4  * Copyright (c) 2007 FURUHASHI Sadayuki <fr _at_ syuki.skr.jp>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include <sys/types.h>
26 #include <arpa/inet.h>
27 #include <string.h>
28 #include "pdhcp.h"
29 #include "dhcp.h"
30 
31 
check_dhcp_packet(struct dhcp_packet * p)32 int check_dhcp_packet(struct dhcp_packet *p)
33 {
34 	u_char *op;
35 
36 	/* check magic cookie */
37 	if (memcmp(p->options, DHCP_OPTIONS_COOKIE, DHCP_OPTIONS_COOKIE_LEN))
38 		return -1;
39 
40 	/* */
41 	if (p->op != BOOTREQUEST)
42 		return -1;
43 
44 	/* check packet length */
45 	op = p->options + DHCP_OPTIONS_COOKIE_LEN;
46 	while (*op != DHO_END) {
47 		if (op - p->options >= DHCP_OPTION_LEN)
48 			return -1;
49 		else if (*op == DHO_PAD)
50 			++op;
51 		else
52 			op += op[1] + 2;
53 	}
54 	return 0;
55 }
56 
get_dhcp_option(struct dhcp_packet * p,u_char type,u_char ** opt,u_char * optlen)57 int get_dhcp_option(struct dhcp_packet *p, u_char type, u_char **opt, u_char *optlen)
58 {
59 	u_char *opos = p->options + DHCP_OPTIONS_COOKIE_LEN;
60 	while (*opos != DHO_END) {
61 		if (*opos == type) {
62 			*opt = &opos[2];
63 			*optlen = opos[1];
64 			return 0;
65 		}
66 		if (*opos == DHO_PAD)
67 			opos++;
68 		else
69 			opos += opos[1] + 2;
70 	}
71 	return -1;
72 }
73 
get_dhcp_message_type(struct dhcp_packet * p)74 int get_dhcp_message_type(struct dhcp_packet *p)
75 {
76 	u_char *opt, optlen;
77 	if (get_dhcp_option(p, DHO_DHCP_MESSAGE_TYPE, &opt, &optlen) == -1) {
78 		return -1;
79 	}
80 	return *opt;
81 }
82 
get_dhcp_packet_len(struct dhcp_packet * p)83 int get_dhcp_packet_len(struct dhcp_packet *p)
84 {
85 	u_char *op = p->options;
86 	op += DHCP_OPTIONS_COOKIE_LEN;
87 	while (*op != DHO_END) {
88 		if (*op == DHO_PAD)
89 			op++;
90 		else
91 			op += op[1] + 2;
92 	}
93 	return (op - (u_char*)p) + 1;
94 }
95 
add_dhcp_option(struct dhcp_packet * p,u_char type,u_char * opt,u_char optlen)96 int add_dhcp_option(struct dhcp_packet *p, u_char type,
97 		u_char *opt, u_char optlen)
98 {
99 	u_char *op;
100 
101 	int len = get_dhcp_packet_len(p);
102 	if (len == -1) return -1;
103 
104 	/* check if there is enough space left */
105 	if (len + optlen + 3 > sizeof(struct dhcp_packet))
106 		return -1;
107 
108 	/* add new option */
109 	op = (u_char*)p + len - 1;
110 	op[0] = type;
111 	op[1] = optlen;
112 	memcpy(&op[2], opt, optlen);
113 
114 	/* and end marker */
115 	op[2+optlen] = DHO_END;
116 
117 	return 0;
118 }
119 
120