ISC DHCP  4.4.2b1
A reference DHCPv4 and DHCPv6 implementation
bootp.c
Go to the documentation of this file.
1 /* bootp.c
2 
3  BOOTP Protocol support. */
4 
5 /*
6  * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1995-2003 by Internet Software Consortium
8  *
9  * This Source Code Form is subject to the terms of the Mozilla Public
10  * License, v. 2.0. If a copy of the MPL was not distributed with this
11  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  * Internet Systems Consortium, Inc.
22  * 950 Charter Street
23  * Redwood City, CA 94063
24  * <info@isc.org>
25  * https://www.isc.org/
26  *
27  */
28 
29 #include "dhcpd.h"
30 #include <errno.h>
31 
32 #if defined (TRACING)
33 # define send_packet trace_packet_send
34 #endif
35 
36 void bootp (packet)
37  struct packet *packet;
38 {
39  int result;
40  struct host_decl *hp = (struct host_decl *)0;
41  struct host_decl *host = (struct host_decl *)0;
42  struct packet outgoing;
43  struct dhcp_packet raw;
44  struct sockaddr_in to;
45  struct in_addr from;
46  struct hardware hto;
47  struct option_state *options = (struct option_state *)0;
48  struct lease *lease = (struct lease *)0;
49  unsigned i;
50  struct data_string d1;
51  struct option_cache *oc;
52  char msgbuf [1024];
53  int ignorep;
54  int peer_has_leases = 0;
55  int norelay = 0;
56 
57  if (packet -> raw -> op != BOOTREQUEST)
58  return;
59 
60  /* %Audit% This is log output. %2004.06.17,Safe%
61  * If we truncate we hope the user can get a hint from the log.
62  */
63  snprintf (msgbuf, sizeof msgbuf, "BOOTREQUEST from %s via %s",
64  print_hw_addr (packet -> raw -> htype,
65  packet -> raw -> hlen,
66  packet -> raw -> chaddr),
67  packet -> raw -> giaddr.s_addr
68  ? inet_ntoa (packet -> raw -> giaddr)
69  : packet -> interface -> name);
70 
71  if ((norelay = locate_network (packet)) == 0) {
72  log_info ("%s: network unknown", msgbuf);
73  return;
74  }
75 
77  0, 0, (struct lease *)0, MDL);
78 
79  if (lease && lease->host)
80  host_reference(&hp, lease->host, MDL);
81 
82  if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
83  struct host_decl *h;
84 
85  /* We didn't find an applicable fixed-address host
86  declaration. Just in case we may be able to dynamically
87  assign an address, see if there's a host declaration
88  that doesn't have an ip address associated with it. */
89 
90  if (!hp)
92  packet->raw->chaddr,
93  packet->raw->hlen, MDL);
94 
95  for (h = hp; h; h = h -> n_ipaddr) {
96  if (!h -> fixed_addr) {
97  host_reference(&host, h, MDL);
98  break;
99  }
100  }
101 
102  if (hp)
103  host_dereference(&hp, MDL);
104 
105  if (host) {
106  host_reference(&hp, host, MDL);
107  host_dereference(&host, MDL);
108  }
109 
110  /* Allocate a lease if we have not yet found one. */
111  if (!lease)
114  &peer_has_leases);
115 
116  if (lease == NULL) {
117  log_info("%s: BOOTP from dynamic client and no "
118  "dynamic leases", msgbuf);
119  goto out;
120  }
121 
122 #if defined(FAILOVER_PROTOCOL)
123  if ((lease->pool != NULL) &&
124  (lease->pool->failover_peer != NULL)) {
125  dhcp_failover_state_t *peer;
126 
127  peer = lease->pool->failover_peer;
128 
129  /* If we are in a failover state that bars us from
130  * answering, do not do so.
131  * If we are in a cooperative state, load balance
132  * (all) responses.
133  */
134  if ((peer->service_state == not_responding) ||
135  (peer->service_state == service_startup)) {
136  log_info("%s: not responding%s",
137  msgbuf, peer->nrr);
138  goto out;
139  } else if((peer->service_state == cooperating) &&
140  !load_balance_mine(packet, peer)) {
141  log_info("%s: load balance to peer %s",
142  msgbuf, peer->name);
143  goto out;
144  }
145  }
146 #endif
147 
148  ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
149  goto out;
150  }
151 
152  /* Run the executable statements to compute the client and server
153  options. */
154  option_state_allocate (&options, MDL);
155 
156  /* Execute the subnet statements. */
158  packet->options, options,
160  NULL, NULL);
161 
162  /* Execute statements from class scopes. */
163  for (i = packet -> class_count; i > 0; i--) {
165  packet->options, options,
166  &lease->scope,
167  packet->classes[i - 1]->group,
168  lease->subnet->group, NULL);
169  }
170 
171  /* Execute the host statements. */
172  if (hp != NULL) {
174  packet->options, options,
175  &lease->scope, hp->group,
176  lease->subnet->group, NULL);
177  }
178 
179  /* Drop the request if it's not allowed for this client. */
180  if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
182  NULL,
183  packet->options, options,
184  &lease->scope, oc, MDL)) {
185  if (!ignorep)
186  log_info ("%s: bootp disallowed", msgbuf);
187  goto out;
188  }
189 
190  if ((oc = lookup_option(&server_universe,
191  options, SV_ALLOW_BOOTING)) &&
193  NULL,
194  packet->options, options,
195  &lease->scope, oc, MDL)) {
196  if (!ignorep)
197  log_info ("%s: booting disallowed", msgbuf);
198  goto out;
199  }
200 
201  /* Set up the outgoing packet... */
202  memset (&outgoing, 0, sizeof outgoing);
203  memset (&raw, 0, sizeof raw);
204  outgoing.raw = &raw;
205 
206  /* If we didn't get a known vendor magic number on the way in,
207  just copy the input options to the output. */
209  if (!packet->options_valid &&
210  !(evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
211  packet->options, options,
212  &lease->scope,
214  options, i), MDL))) {
216  memcpy(outgoing.raw->options, packet->raw->options,
218  }
219 
220  outgoing.packet_length =
222  ? BOOTP_MIN_LEN
224  } else {
225 
226  /* Use the subnet mask from the subnet declaration if no other
227  mask has been provided. */
228  oc = (struct option_cache *)0;
229  i = DHO_SUBNET_MASK;
230  if (!lookup_option (&dhcp_universe, options, i)) {
231  if (option_cache_allocate (&oc, MDL)) {
232  if (make_const_data
233  (&oc -> expression,
234  lease -> subnet -> netmask.iabuf,
235  lease -> subnet -> netmask.len,
236  0, 0, MDL)) {
237  option_code_hash_lookup(&oc->option,
239  &i, 0, MDL);
241  options, oc);
242  }
244  }
245  }
246 
247  /* If use-host-decl-names is enabled and there is a hostname
248  * defined in the host delcartion, send it back in hostname
249  * option */
250  use_host_decl_name(packet, lease, options);
251 
252  /* Pack the options into the buffer. Unlike DHCP, we
253  can't pack options into the filename and server
254  name buffers. */
255 
256  outgoing.packet_length =
257  cons_options (packet, outgoing.raw, lease,
258  (struct client_state *)0, 0,
259  packet -> options, options,
260  &lease -> scope,
261  0, 0, 1, (struct data_string *)0,
262  (const char *)0);
263  if (outgoing.packet_length < BOOTP_MIN_LEN)
264  outgoing.packet_length = BOOTP_MIN_LEN;
265  }
266 
267  /* Take the fields that we care about... */
268  raw.op = BOOTREPLY;
269  raw.htype = packet -> raw -> htype;
270  raw.hlen = packet -> raw -> hlen;
271  memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
272  raw.hops = packet -> raw -> hops;
273  raw.xid = packet -> raw -> xid;
274  raw.secs = packet -> raw -> secs;
275  raw.flags = packet -> raw -> flags;
276  raw.ciaddr = packet -> raw -> ciaddr;
277 
278  /* yiaddr is an ipv4 address, it must be 4 octets. */
279  memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
280 
281  /* If we're always supposed to broadcast to this client, set
282  the broadcast bit in the bootp flags field. */
283  if ((oc = lookup_option (&server_universe,
284  options, SV_ALWAYS_BROADCAST)) &&
286  (struct client_state *)0,
287  packet -> options, options,
288  &lease -> scope, oc, MDL))
289  raw.flags |= htons (BOOTP_BROADCAST);
290 
291  /* Figure out the address of the next server. */
292  memset (&d1, 0, sizeof d1);
293  oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
294  if (oc &&
296  (struct client_state *)0,
297  packet -> options, options,
298  &lease -> scope, oc, MDL)) {
299  /* If there was more than one answer, take the first. */
300  if (d1.len >= 4 && d1.data)
301  memcpy (&raw.siaddr, d1.data, 4);
302  data_string_forget (&d1, MDL);
303  } else {
304  if ((lease->subnet->shared_network->interface != NULL) &&
306  raw.siaddr =
308  else if (packet->interface->address_count)
309  raw.siaddr = packet->interface->addresses[0];
310  }
311 
312  raw.giaddr = packet -> raw -> giaddr;
313 
314  /* Figure out the filename. */
315  oc = lookup_option (&server_universe, options, SV_FILENAME);
316  if (oc &&
318  (struct client_state *)0,
319  packet -> options, options,
320  &lease -> scope, oc, MDL)) {
321  memcpy (raw.file, d1.data,
322  d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
323  if (sizeof raw.file > d1.len)
324  memset (&raw.file [d1.len],
325  0, (sizeof raw.file) - d1.len);
326  data_string_forget (&d1, MDL);
327  } else
328  memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
329 
330  /* Choose a server name as above. */
331  oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
332  if (oc &&
334  (struct client_state *)0,
335  packet -> options, options,
336  &lease -> scope, oc, MDL)) {
337  memcpy (raw.sname, d1.data,
338  d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
339  if (sizeof raw.sname > d1.len)
340  memset (&raw.sname [d1.len],
341  0, (sizeof raw.sname) - d1.len);
342  data_string_forget (&d1, MDL);
343  }
344 
345  /* Execute the commit statements, if there are any. */
346  execute_statements (NULL, packet, lease, NULL, packet->options,
347  options, &lease->scope, lease->on_star.on_commit,
348  NULL);
349 
350  /* We're done with the option state. */
351  option_state_dereference (&options, MDL);
352 
353 #if defined(DHCPv6) && defined(DHCP4o6)
354  if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
355  /* Report what we're doing... */
356  log_info("%s", msgbuf);
357  log_info("DHCP4o6 BOOTREPLY for %s to %s (%s) via %s",
358  piaddr(lease->ip_addr),
359  ((hp != NULL) && (hp->name != NULL)) ?
360  hp -> name : "unknown",
362  packet->raw->hlen,
363  packet->raw->chaddr),
365 
366  /* fill dhcp4o6_response */
368  packet->dhcp4o6_response->buffer = NULL;
370  outgoing.packet_length, MDL)) {
371  log_fatal("No memory to store DHCP4o6 reply.");
372  }
376  outgoing.raw, outgoing.packet_length);
377  goto out;
378  }
379 #endif
380 
381  /* Set up the hardware destination address... */
382  hto.hbuf [0] = packet -> raw -> htype;
383  hto.hlen = packet -> raw -> hlen + 1;
384  memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
385 
387  from = packet->interface->addresses[0];
388  } else {
389  log_error("%s: Interface %s appears to have no IPv4 "
390  "addresses, and so dhcpd cannot select a source "
391  "address.", msgbuf, packet->interface->name);
392  goto out;
393  }
394 
395  /* Report what we're doing... */
396  log_info("%s", msgbuf);
397  log_info("BOOTREPLY for %s to %s (%s) via %s",
398  piaddr(lease->ip_addr),
399  ((hp != NULL) && (hp->name != NULL)) ? hp -> name : "unknown",
401  packet->raw->hlen,
402  packet->raw->chaddr),
403  packet->raw->giaddr.s_addr
404  ? inet_ntoa (packet->raw->giaddr)
405  : packet->interface->name);
406 
407  /* Set up the parts of the address that are in common. */
408  to.sin_family = AF_INET;
409 #ifdef HAVE_SA_LEN
410  to.sin_len = sizeof to;
411 #endif
412  memset (to.sin_zero, 0, sizeof to.sin_zero);
413 
414  /* If this was gatewayed, send it back to the gateway... */
415  if (raw.giaddr.s_addr) {
416  to.sin_addr = raw.giaddr;
417  to.sin_port = local_port;
418 
419  if (fallback_interface) {
420  result = send_packet (fallback_interface, NULL, &raw,
421  outgoing.packet_length, from,
422  &to, &hto);
423  if (result < 0) {
424  log_error ("%s:%d: Failed to send %d byte long "
425  "packet over %s interface.", MDL,
426  outgoing.packet_length,
428  }
429 
430  goto out;
431  }
432  } else if (norelay == 2) {
433  to.sin_addr = raw.ciaddr;
434  to.sin_port = remote_port;
435  if (fallback_interface) {
436  result = send_packet (fallback_interface, NULL, &raw,
437  outgoing.packet_length, from,
438  &to, &hto);
439  goto out;
440  }
441 
442  /* If it comes from a client that already knows its address
443  and is not requesting a broadcast response, and we can
444  unicast to a client without using the ARP protocol, sent it
445  directly to that client. */
446  } else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
447  can_unicast_without_arp (packet -> interface)) {
448  to.sin_addr = raw.yiaddr;
449  to.sin_port = remote_port;
450 
451  /* Otherwise, broadcast it on the local network. */
452  } else {
453  to.sin_addr = limited_broadcast;
454  to.sin_port = remote_port; /* XXX */
455  }
456 
457  errno = 0;
458  result = send_packet(packet->interface, packet, &raw,
459  outgoing.packet_length, from, &to, &hto);
460  if (result < 0) {
461  log_error ("%s:%d: Failed to send %d byte long packet over %s"
462  " interface.", MDL, outgoing.packet_length,
463  packet->interface->name);
464  }
465 
466  out:
467 
468  if (options)
469  option_state_dereference (&options, MDL);
470  if (lease)
471  lease_dereference (&lease, MDL);
472  if (hp)
473  host_dereference (&hp, MDL);
474  if (host)
475  host_dereference (&host, MDL);
476 }
#define BOOTREPLY
Definition: dhcp.h:69
#define DHCP_FIXED_NON_UDP
Definition: dhcp.h:36
char file[DHCP_FILE_LEN]
Definition: dhcp.h:61
int find_lease(struct lease **, struct packet *, struct shared_network *, int *, int *, struct lease *, const char *, int)
Definition: dhcp.c:4213
char sname[DHCP_SNAME_LEN]
Definition: dhcp.h:60
u_int32_t flags
Definition: dhcpd.h:393
#define SV_ALLOW_BOOTING
Definition: dhcpd.h:719
struct on_star on_star
Definition: dhcpd.h:583
Definition: dhcpd.h:560
unsigned len
Definition: tree.h:79
const char * piaddr(const struct iaddr addr)
Definition: inet.c:579
u_int8_t hlen
Definition: dhcpd.h:492
char name[IFNAMSIZ]
Definition: dhcpd.h:1403
u_int16_t secs
Definition: dhcp.h:53
Definition: dhcpd.h:1071
struct universe server_universe
Definition: stables.c:176
int execute_statements(struct binding_value **result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *out_options, struct binding_scope **scope, struct executable_statement *statements, struct on_star *on_star)
Definition: execute.c:35
#define MDL
Definition: omapip.h:567
unsigned char iabuf[16]
Definition: inet.h:33
u_int8_t hlen
Definition: dhcp.h:50
struct in_addr * addresses
Definition: dhcpd.h:1383
void save_option(struct universe *universe, struct option_state *options, struct option_cache *oc)
Definition: options.c:2818
struct universe dhcp_universe
int dhcpv4_over_dhcpv6
Definition: discover.c:48
void data_string_forget(struct data_string *data, const char *file, int line)
Definition: alloc.c:1339
struct option_cache * fixed_addr
Definition: dhcpd.h:982
#define DHO_SUBNET_MASK
Definition: dhcp.h:92
#define BOOTP_BROADCAST
Definition: dhcp.h:72
int log_error(const char *,...) __attribute__((__format__(__printf__
struct in_addr siaddr
Definition: dhcp.h:57
#define SV_SERVER_NAME
Definition: dhcpd.h:726
int allocate_lease(struct lease **, struct packet *, struct pool *, int *)
Definition: dhcp.c:5019
dhcp_failover_state_t * failover_peer
Definition: dhcpd.h:1047
int find_hosts_by_haddr(struct host_decl **, int, const unsigned char *, unsigned, const char *, int)
Definition: mdb.c:632
#define SV_FILENAME
Definition: dhcpd.h:725
u_int16_t flags
Definition: dhcp.h:54
struct option_state * options
Definition: dhcpd.h:449
#define BOOTP_MIN_LEN
Definition: dhcp.h:39
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
Definition: options.c:2503
#define SV_ALLOW_BOOTP
Definition: dhcpd.h:718
int locate_network(struct packet *)
Definition: dhcp.c:5363
void log_fatal(const char *,...) __attribute__((__format__(__printf__
int option_cache_allocate(struct option_cache **cptr, const char *file, int line)
Definition: alloc.c:630
struct dhcp_packet * raw
Definition: dhcpd.h:406
void execute_statements_in_scope(struct binding_value **result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *out_options, struct binding_scope **scope, struct group *group, struct group *limiting_group, struct on_star *on_star)
Definition: execute.c:570
u_int8_t htype
Definition: dhcp.h:49
struct interface_info * fallback_interface
Definition: discover.c:42
int option_state_allocate(struct option_state **ptr, const char *file, int line)
Definition: alloc.c:846
int evaluate_option_cache(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc, const char *file, int line)
Definition: tree.c:2699
unsigned char chaddr[16]
Definition: dhcp.h:59
#define SV_NEXT_SERVER
Definition: dhcpd.h:727
u_int32_t xid
Definition: dhcp.h:52
#define SV_ALWAYS_BROADCAST
Definition: dhcpd.h:732
int options_valid
Definition: dhcpd.h:430
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition: alloc.c:679
struct class * classes[PACKET_MAX_CLASSES]
Definition: dhcpd.h:455
struct interface_info * interface
Definition: dhcpd.h:433
u_int16_t local_port
Definition: dhclient.c:96
Definition: dhcpd.h:405
struct pool * pool
Definition: dhcpd.h:578
char * name
Definition: dhcpd.h:974
#define SV_ALWAYS_REPLY_RFC1048
Definition: dhcpd.h:730
struct in_addr yiaddr
Definition: dhcp.h:56
ssize_t send_packet(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
u_int8_t flags
Definition: dhcpd.h:591
struct in_addr giaddr
Definition: dhclient.c:77
struct host_decl * n_ipaddr
Definition: dhcpd.h:972
#define BOOTREQUEST
Definition: dhcp.h:68
int load_balance_mine(struct packet *, dhcp_failover_state_t *)
struct option * option
Definition: dhcpd.h:389
struct in_addr limited_broadcast
Definition: discover.c:54
int int log_info(const char *,...) __attribute__((__format__(__printf__
struct subnet * subnet
Definition: dhcpd.h:577
struct shared_network * shared_network
Definition: dhcpd.h:1075
void bootp(struct packet *packet)
Definition: bootp.c:36
struct group * group
Definition: dhcpd.h:1081
void use_host_decl_name(struct packet *, struct lease *, struct option_state *)
Adds hostname option when use-host-decl-names is enabled.
Definition: dhcp.c:5732
struct iaddr ip_addr
Definition: dhcpd.h:569
struct in_addr giaddr
Definition: dhcp.h:58
struct data_string * dhcp4o6_response
Definition: dhcpd.h:428
int option_state_dereference(struct option_state **ptr, const char *file, int line)
Definition: alloc.c:911
int evaluate_boolean_option_cache(int *ignorep, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc, const char *file, int line)
Definition: tree.c:2733
int make_const_data(struct expression **expr, const unsigned char *data, unsigned len, int terminated, int allocate, const char *file, int line)
Definition: tree.c:219
struct host_decl * host
Definition: dhcpd.h:576
void ack_lease(struct packet *, struct lease *, unsigned int, TIME, char *, int, struct host_decl *)
Definition: dhcp.c:2201
unsigned char data[1]
Definition: tree.h:62
struct interface_info * interface
Definition: dhcpd.h:1062
#define STATIC_LEASE
Definition: dhcpd.h:592
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:493
int address_count
Definition: dhcpd.h:1386
u_int8_t hops
Definition: dhcp.h:51
int cons_options(struct packet *inpacket, struct dhcp_packet *outpacket, struct lease *lease, struct client_state *client_state, int mms, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, int overload_avail, int terminate, int bootpp, struct data_string *prl, const char *vuname)
Definition: options.c:538
struct iaddr client_addr
Definition: dhcpd.h:432
struct ipv6_pool ** pools
option_code_hash_t * code_hash
Definition: tree.h:337
u_int16_t remote_port
Definition: dhclient.c:97
const char * file
Definition: dhcpd.h:3793
int option_cache_dereference(struct option_cache **ptr, const char *file, int line)
Definition: options.c:2953
int can_unicast_without_arp(struct interface_info *)
struct executable_statement * on_commit
Definition: dhcpd.h:555
const unsigned char * data
Definition: tree.h:78
struct in_addr ciaddr
Definition: dhcp.h:55
struct binding_scope * scope
Definition: dhcpd.h:575
unsigned packet_length
Definition: dhcpd.h:408
char * print_hw_addr(int htype, const int hlen, const unsigned char *data) const
Definition: print.c:171
u_int8_t op
Definition: dhcp.h:48
struct group * group
Definition: dhcpd.h:984
struct buffer * buffer
Definition: tree.h:77
struct group * group
Definition: dhcpd.h:1125
unsigned char options[DHCP_MAX_OPTION_LEN]
Definition: dhcp.h:62