49 |
|
|
50 |
/* Both iovecs below have to have the same structure, since dhcp_send() |
/* Both iovecs below have to have the same structure, since dhcp_send() |
51 |
pokes at the internals */ |
pokes at the internals */ |
52 |
#define DHCP_IOV_LEN 6 |
#define DHCP_IOV_LEN 7 |
53 |
|
|
54 |
static struct iovec dhcp_discover_iov[] = { |
static struct iovec dhcp_discover_iov[DHCP_IOV_LEN] = { |
55 |
/* [0] = ip + udp header */ |
/* [0] = ip + udp header */ |
56 |
/* [1] = bootp header */ |
/* [1] = bootp header */ |
57 |
[2] = {dhcp_discover_hdr, sizeof(dhcp_discover_hdr)}, |
[2] = {dhcp_discover_hdr, sizeof(dhcp_discover_hdr)}, |
58 |
[3] = {dhcp_params, sizeof(dhcp_params)}, |
[3] = {dhcp_params, sizeof(dhcp_params)}, |
59 |
/* [4] = DHCP vendor class */ |
/* [4] = optional vendor class */ |
60 |
[5] = {dhcp_end, sizeof(dhcp_end)} |
/* [5] = optional hostname */ |
61 |
|
/* [6] = {dhcp_end, sizeof(dhcp_end)} */ |
62 |
}; |
}; |
63 |
|
|
64 |
static struct iovec dhcp_request_iov[] = { |
static struct iovec dhcp_request_iov[DHCP_IOV_LEN] = { |
65 |
/* [0] = ip + udp header */ |
/* [0] = ip + udp header */ |
66 |
/* [1] = bootp header */ |
/* [1] = bootp header */ |
67 |
[2] = {dhcp_request_hdr, sizeof(dhcp_request_hdr)}, |
[2] = {dhcp_request_hdr, sizeof(dhcp_request_hdr)}, |
68 |
[3] = {dhcp_params, sizeof(dhcp_params)}, |
[3] = {dhcp_params, sizeof(dhcp_params)}, |
69 |
/* [4] = DHCP vendor class */ |
/* [4] = optional vendor class */ |
70 |
[5] = {dhcp_end, sizeof(dhcp_end)} |
/* [5] = optional hostname */ |
71 |
|
/* [6] = {dhcp_end, sizeof(dhcp_end)} */ |
72 |
}; |
}; |
73 |
|
|
74 |
/* |
/* |
75 |
* Parse a DHCP response packet |
* Parse a DHCP response packet |
76 |
* Returns: |
* Returns: |
77 |
* 0 = Not handled |
* 0 = Unexpected packet, not parsed |
78 |
* 2 = DHCPOFFER (from dhcp_proto.h) |
* 2 = DHCPOFFER (from dhcp_proto.h) |
79 |
* 5 = DHCPACK |
* 5 = DHCPACK |
80 |
* 6 = DHCPNACK |
* 6 = DHCPNACK |
111 |
ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPOFFER : 0; |
ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPOFFER : 0; |
112 |
if (ret == DHCPOFFER && serverid != INADDR_NONE) |
if (ret == DHCPOFFER && serverid != INADDR_NONE) |
113 |
dev->serverid = serverid; |
dev->serverid = serverid; |
114 |
DEBUG(("\n dhcp offer\n")); |
dprintf("\n dhcp offer\n"); |
115 |
break; |
break; |
116 |
|
|
117 |
case DHCPACK: |
case DHCPACK: |
118 |
ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPACK : 0; |
ret = bootp_parse(dev, hdr, exts, extlen) ? DHCPACK : 0; |
119 |
DEBUG(("\n dhcp ack\n")); |
dprintf("\n dhcp ack\n"); |
120 |
break; |
break; |
121 |
|
|
122 |
case DHCPNAK: |
case DHCPNAK: |
123 |
ret = DHCPNAK; |
ret = DHCPNAK; |
124 |
DEBUG(("\n dhcp nak\n")); |
dprintf("\n dhcp nak\n"); |
125 |
break; |
break; |
126 |
} |
} |
127 |
return ret; |
return ret; |
130 |
/* |
/* |
131 |
* Receive and parse a DHCP packet |
* Receive and parse a DHCP packet |
132 |
* Returns: |
* Returns: |
133 |
*-1 = Error in packet_recv |
*-1 = Error in packet_recv, try again later |
134 |
* 0 = Not handled |
* 0 = Unexpected packet, discarded |
135 |
* 2 = DHCPOFFER (from dhcp_proto.h) |
* 2 = DHCPOFFER (from dhcp_proto.h) |
136 |
* 5 = DHCPACK |
* 5 = DHCPACK |
137 |
* 6 = DHCPNACK |
* 6 = DHCPNACK |
148 |
int ret; |
int ret; |
149 |
|
|
150 |
ret = packet_recv(iov, 3); |
ret = packet_recv(iov, 3); |
151 |
if (ret <= 0) |
if (ret == 0) |
152 |
return ret; |
return -1; |
153 |
|
|
154 |
DEBUG(("\n dhcp xid %08x ", dev->bootp.xid)); |
dprintf("\n dhcp xid %08x ", dev->bootp.xid); |
155 |
|
|
156 |
if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY || |
if (ret < sizeof(struct bootp_hdr) || bootp.op != BOOTP_REPLY || |
157 |
/* RFC951 7.5 */ bootp.xid != dev->bootp.xid || |
/* RFC951 7.5 */ bootp.xid != dev->bootp.xid || |
166 |
static int dhcp_send(struct netdev *dev, struct iovec *vec) |
static int dhcp_send(struct netdev *dev, struct iovec *vec) |
167 |
{ |
{ |
168 |
struct bootp_hdr bootp; |
struct bootp_hdr bootp; |
169 |
|
char dhcp_hostname[SYS_NMLN+2]; |
170 |
|
int i = 4; |
171 |
|
|
172 |
memset(&bootp, 0, sizeof(struct bootp_hdr)); |
memset(&bootp, 0, sizeof(struct bootp_hdr)); |
173 |
|
|
175 |
bootp.htype = dev->hwtype; |
bootp.htype = dev->hwtype; |
176 |
bootp.hlen = dev->hwlen; |
bootp.hlen = dev->hwlen; |
177 |
bootp.xid = dev->bootp.xid; |
bootp.xid = dev->bootp.xid; |
178 |
bootp.ciaddr = dev->ip_addr; |
bootp.ciaddr = INADDR_ANY; |
179 |
|
bootp.yiaddr = dev->ip_addr; |
180 |
bootp.giaddr = INADDR_ANY; |
bootp.giaddr = INADDR_ANY; |
181 |
bootp.secs = htons(time(NULL) - dev->open_time); |
bootp.secs = htons(time(NULL) - dev->open_time); |
182 |
memcpy(bootp.chaddr, dev->hwaddr, 16); |
memcpy(bootp.chaddr, dev->hwaddr, 16); |
184 |
vec[1].iov_base = &bootp; |
vec[1].iov_base = &bootp; |
185 |
vec[1].iov_len = sizeof(struct bootp_hdr); |
vec[1].iov_len = sizeof(struct bootp_hdr); |
186 |
|
|
187 |
vec[4].iov_base = vendor_class_identifier; |
dprintf("xid %08x secs %d ", bootp.xid, ntohs(bootp.secs)); |
|
vec[4].iov_len = vendor_class_identifier_len; |
|
188 |
|
|
189 |
DEBUG(("xid %08x secs %d ", bootp.xid, ntohs(bootp.secs))); |
if (vendor_class_identifier_len > 2) { |
190 |
|
vec[i].iov_base = vendor_class_identifier; |
191 |
|
vec[i].iov_len = vendor_class_identifier_len; |
192 |
|
i++; |
193 |
|
|
194 |
|
dprintf("vendor_class_identifier \"%.*s\" ", |
195 |
|
vendor_class_identifier_len-2, |
196 |
|
vendor_class_identifier+2); |
197 |
|
} |
198 |
|
|
199 |
|
if (dev->reqhostname[0] != '\0') { |
200 |
|
int len = strlen(dev->reqhostname); |
201 |
|
dhcp_hostname[0] = 12; |
202 |
|
dhcp_hostname[1] = len; |
203 |
|
memcpy(dhcp_hostname+2, dev->reqhostname, len); |
204 |
|
|
205 |
|
vec[i].iov_base = dhcp_hostname; |
206 |
|
vec[i].iov_len = len+2; |
207 |
|
i++; |
208 |
|
|
209 |
|
printf("hostname %.*s ", len, dhcp_hostname+2); |
210 |
|
} |
211 |
|
|
212 |
|
vec[i].iov_base = dhcp_end; |
213 |
|
vec[i].iov_len = sizeof(dhcp_end); |
214 |
|
|
215 |
return packet_send(dev, vec, DHCP_IOV_LEN); |
return packet_send(dev, vec, i + 1); |
216 |
} |
} |
217 |
|
|
218 |
/* |
/* |
223 |
dev->ip_addr = INADDR_ANY; |
dev->ip_addr = INADDR_ANY; |
224 |
dev->ip_gateway = INADDR_ANY; |
dev->ip_gateway = INADDR_ANY; |
225 |
|
|
226 |
DEBUG(("-> dhcp discover ")); |
dprintf("-> dhcp discover "); |
227 |
|
|
228 |
return dhcp_send(dev, dhcp_discover_iov); |
return dhcp_send(dev, dhcp_discover_iov); |
229 |
} |
} |
244 |
memcpy(&dhcp_request_hdr[SERVER_IP_OFF], &dev->serverid, 4); |
memcpy(&dhcp_request_hdr[SERVER_IP_OFF], &dev->serverid, 4); |
245 |
memcpy(&dhcp_request_hdr[REQ_IP_OFF], &dev->ip_addr, 4); |
memcpy(&dhcp_request_hdr[REQ_IP_OFF], &dev->ip_addr, 4); |
246 |
|
|
247 |
DEBUG(("-> dhcp request ")); |
dprintf("-> dhcp request "); |
248 |
|
|
249 |
return dhcp_send(dev, dhcp_request_iov); |
return dhcp_send(dev, dhcp_request_iov); |
250 |
} |
} |