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