da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * CDDL HEADER START
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner * The contents of this file are subject to the terms of the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Common Development and Distribution License (the "License").
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * You may not use this file except in compliance with the License.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * or http://www.opensolaris.org/os/licensing.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * See the License for the specific language governing permissions
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * and limitations under the License.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * When distributing Covered Code, include this CDDL HEADER in each
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If applicable, add the following below this CDDL HEADER, with the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * fields enclosed by brackets "[]" replaced with your own identifying
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * information: Portions Copyright [yyyy] [name of copyright owner]
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * CDDL HEADER END
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Use is subject to license terms.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * ADOPTING state of the client state machine. This is used only during
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * diskless boot with IPv4.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/types.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <string.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <unistd.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <stdlib.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <signal.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/socket.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <net/if_arp.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <netinet/in.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/systeminfo.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <netinet/inetutil.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <netinet/dhcp.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <dhcpmsg.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <libdevinfo.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "agent.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "async.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "util.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "packet.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "interface.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "states.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chintypedef struct {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char dk_if_name[IFNAMSIZ];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char dk_ack[1];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin} dhcp_kcache_t;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int get_dhcp_kcache(dhcp_kcache_t **, size_t *);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic boolean_t get_prom_prop(const char *, const char *, uchar_t **,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint_t *);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * dhcp_adopt(): adopts the interface managed by the kernel for diskless boot
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * input: void
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * output: boolean_t: B_TRUE success, B_FALSE on failure
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinboolean_t
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chindhcp_adopt(void)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int retval;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcp_kcache_t *kcache = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size_t kcache_size;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PKT_LIST *plp = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcp_lif_t *lif;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcp_smach_t *dsmp = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint_t client_id_len;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin retval = get_dhcp_kcache(&kcache, &kcache_size);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (retval == 0 || kcache_size < sizeof (dhcp_kcache_t)) {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot fetch kernel cache");
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin goto failure;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin dhcpmsg(MSG_DEBUG, "dhcp_adopt: fetched %s kcache", kcache->dk_if_name);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * convert the kernel's ACK into binary
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin plp = alloc_pkt_entry(strlen(kcache->dk_ack) / 2, B_FALSE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (plp == NULL)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG, "dhcp_adopt: allocated ACK of %d bytes", plp->len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (hexascii_to_octet(kcache->dk_ack, plp->len * 2, plp->pkt,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin &plp->len) != 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot convert kernel ACK");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (dhcp_options_scan(plp, B_TRUE) != 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot parse kernel ACK");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * make an interface to represent the "cached interface" in
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the kernel, hook up the ACK packet we made, and send out
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the extend request (to attempt to renew the lease).
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * we do a send_extend() instead of doing a dhcp_init_reboot()
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * because although dhcp_init_reboot() is more correct from a
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * protocol perspective, it introduces a window where a
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * diskless client has no IP address but may need to page in
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * more of this program. we could mlockall(), but that's
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * going to be a mess, especially with handling malloc() and
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * stack growth, so it's easier to just renew(). the only
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * catch here is that if we are not granted a renewal, we're
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * totally hosed and can only bail out.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((lif = attach_lif(kcache->dk_if_name, B_FALSE, &retval)) == NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_ERROR, "dhcp_adopt: unable to attach %s: %d",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin kcache->dk_if_name, retval);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((dsmp = insert_smach(lif, &retval)) == NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_ERROR, "dhcp_adopt: unable to create state "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "machine for %s: %d", kcache->dk_if_name, retval);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If the agent is adopting a lease, then OBP is initially
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * searched for a client-id.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG, "dhcp_adopt: getting /chosen:clientid property");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin client_id_len = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!get_prom_prop("chosen", "client-id", &dsmp->dsm_cid,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin &client_id_len)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * a failure occurred trying to acquire the client-id
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "dhcp_adopt: cannot allocate client id for %s",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dsmp->dsm_name);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else if (dsmp->dsm_hwtype == ARPHRD_IB && dsmp->dsm_cid == NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * when the interface is infiniband and the agent
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * is adopting the lease there must be an OBP
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * client-id.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG, "dhcp_adopt: no /chosen:clientid id for %s",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dsmp->dsm_name);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dsmp->dsm_cidlen = client_id_len;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (set_lif_dhcp(lif) != DHCP_IPC_SUCCESS)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!set_smach_state(dsmp, ADOPTING))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dsmp->dsm_dflags = DHCP_IF_PRIMARY;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * move to BOUND and use the information in our ACK packet.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * adoption will continue after DAD via dhcp_adopt_complete.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!dhcp_bound(dsmp, plp)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_CRIT, "dhcp_adopt: cannot use cached packet");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto failure;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free(kcache);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (B_TRUE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinfailure:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Note: no need to free lif; dsmp holds reference */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (dsmp != NULL)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin remove_smach(dsmp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free(kcache);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin free_pkt_entry(plp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (B_FALSE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * dhcp_adopt_complete(): completes interface adoption process after kernel
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * duplicate address detection (DAD) is done.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * input: dhcp_smach_t *: the state machine on which a lease is being adopted
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * output: none
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chindhcp_adopt_complete(dhcp_smach_t *dsmp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG, "dhcp_adopt_complete: completing adoption");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (async_start(dsmp, DHCP_EXTEND, B_FALSE) == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_CRIT, "dhcp_adopt_complete: async_start failed");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (dhcp_extending(dsmp) == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_CRIT,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "dhcp_adopt_complete: cannot send renew request");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (grandparent != (pid_t)0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG, "adoption complete, signalling parent (%ld)"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin " to exit.", grandparent);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (void) kill(grandparent, SIGALRM);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * get_dhcp_kcache(): fetches the DHCP ACK and interface name from the kernel
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * input: dhcp_kcache_t **: a dynamically-allocated cache packet
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * size_t *: the length of that packet (on return)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * output: int: nonzero on success, zero on failure
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinget_dhcp_kcache(dhcp_kcache_t **kernel_cachep, size_t *kcache_size)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char dummy;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin long size;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size = sysinfo(SI_DHCP_CACHE, &dummy, sizeof (dummy));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (size == -1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *kcache_size = size;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *kernel_cachep = malloc(*kcache_size);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*kernel_cachep == NULL)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (void) sysinfo(SI_DHCP_CACHE, (caddr_t)*kernel_cachep, size);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * get_prom_prop(): get the value of the named property on the named node in
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * devinfo root.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * input: const char *: The name of the node containing the property.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * const char *: The name of the property.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * uchar_t **: The property value, modified iff B_TRUE is returned.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If no value is found the value is set to NULL.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * uint_t *: The length of the property value
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * output: boolean_t: Returns B_TRUE if successful (no problems),
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * otherwise B_FALSE.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * note: The memory allocated by this function must be freed by
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the caller. This code is derived from
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * usr/src/lib/libwanboot/common/bootinfo_aux.c.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic boolean_t
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinget_prom_prop(const char *nodename, const char *propname, uchar_t **propvaluep,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uint_t *lenp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di_node_t root_node;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di_node_t node;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di_prom_handle_t phdl = DI_PROM_HANDLE_NIL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di_prom_prop_t pp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uchar_t *value = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unsigned int len = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin boolean_t success = B_TRUE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * locate root node
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (phdl = di_prom_init()) == DI_PROM_HANDLE_NIL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG, "get_prom_prop: property root node "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "not found");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto get_prom_prop_cleanup;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * locate nodename within '/'
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (node = di_child_node(root_node);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin node != DI_NODE_NIL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin node = di_sibling_node(node)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (strcmp(di_node_name(node), nodename) == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (node == DI_NODE_NIL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG, "get_prom_prop: node not found");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto get_prom_prop_cleanup;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * scan all properties of /nodename for the 'propname' property
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (pp = di_prom_prop_next(phdl, node, DI_PROM_PROP_NIL);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin pp != DI_PROM_PROP_NIL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp = di_prom_prop_next(phdl, node, pp)) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG, "get_prom_prop: property = %s",
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di_prom_prop_name(pp));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (strcmp(propname, di_prom_prop_name(pp)) == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (pp == DI_PROM_PROP_NIL) {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin dhcpmsg(MSG_DEBUG, "get_prom_prop: property not found");
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin goto get_prom_prop_cleanup;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * get the property; allocate some memory copy it out
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin len = di_prom_prop_data(pp, (uchar_t **)&value);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (value == NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * property data read problems
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin success = B_FALSE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_ERR, "get_prom_prop: cannot read property data");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto get_prom_prop_cleanup;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (propvaluep != NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * allocate somewhere to copy the property value to
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *propvaluep = calloc(len, sizeof (uchar_t));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*propvaluep == NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * allocation problems
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin success = B_FALSE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_ERR, "get_prom_prop: cannot allocate "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "memory for property value");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto get_prom_prop_cleanup;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * copy data out
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (void) memcpy(*propvaluep, value, len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * copy out the length if a suitable pointer has
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * been supplied
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (lenp != NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *lenp = len;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dhcpmsg(MSG_DEBUG, "get_prom_prop: property value "
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin "length = %d", len);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinget_prom_prop_cleanup:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (phdl != DI_PROM_HANDLE_NIL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di_prom_fini(phdl);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (root_node != DI_NODE_NIL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin di_fini(root_node);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return (success);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin