#!/opt/psh/bin/psh

#
# Copyright (c) 1998 Sun Microsystems, Inc.
# 
# This software is provided by Sun ``AS IS'' and any express or implied
# warranties, including, but not limited to, the implied warranties of
# merchantability and fitness for a particular purpose are disclaimed.
# In no event shall Sun Microsystems be liable for any direct, indirect,
# incidental, special, exemplary, or consequential damages.
# 
# This software is not a product, and is provided for evaluation purposes
# only.
# 
# This software may not be resold without the express permission of
# Sun Microsystems.
# 
#ident	"@(#)get+release2	1.1	98/02/24 SMI"
#

set bootpc	68
set bootps	67
set srv_timeout 15000;		# msec
set slp_timeout 10;		# sec
set xid		42;

proc dhcp_client_add { cl_ethaddr srv_ipaddr } {

	global argv0 bootpc bootps srv_timeout srv_id cl_ipaddr xid

	# make all the packets we'll need up front
	foreach i { disc offer req decl ack } {
		pinit bootpc $i - - $i
	}

	# open the socket, set options so we can broadcast 
	popen socket ep inet dgram udp
	foreach i { dontroute broadcast reuseaddr } {
		ep.setsockopt SOL_SOCKET $i 1
	}

	# initialize discover packet
	eval pset disc bootpc chaddr	$cl_ethaddr
	pset disc bootpc xid		$xid
	pset disc bootpc flags		0x8000

	puts "$argv0: sending DISCOVER packet to $srv_ipaddr, port $bootps"

	ep.bind 0.0.0.0/$bootpc
	ep.sendto disc 0 $srv_ipaddr/$bootps
	if { [ep.recvfrom offer 0 $srv_timeout] == "timeout" } {
		puts "$argv0: no response to DISCOVER packet"
		return;
	}

	set srv_id  [pget offer bootpc opt "server id"]

	puts "$argv0: received OFFER packet from $srv_id"
	
	# got offer, let's fill in request

	pset req bootpc xid			[pget offer bootpc xid]
	pset req bootpc flags			0x8000
	eval pset req bootpc chaddr		$cl_ethaddr
	pset req bootpc opt "requested ip"	[pget offer bootpc yiaddr]
	pset req bootpc opt "server id"		$srv_id
	pset req bootpc opt "ip address lease"	[pget offer bootpc opt \
	    "ip address lease"]

	puts "$argv0: sending REQUEST packet to $srv_ipaddr, port $bootps"

	ep.sendto req 0 $srv_ipaddr/$bootps
	if { [ep.recvfrom ack 0 $srv_timeout] == "timeout" } {
		puts "$argv0: no response to REQUEST packet"
		return
	}

	if { [pget ack bootpc option "dhcp message type" ] == "nak" } {
		puts "$argv0: received NAK packet from dhcp server"
		return
	}

	set cl_ipaddr [pget ack bootpc yiaddr]
	puts "$argv0: **** successfully obtained dhcp address ****"
	puts [plist ack]

	# free all the packets
	foreach i { disc offer req decl ack } {
		pfree $i
	}
}

proc dhcp_client_del { cl_ethaddr cl_ipaddr } {

	global argv0 bootpc bootps srv_timeout srv_id

	foreach i { rel } {
		pinit bootpc $i - - $i
	}

#
#	RFC 2131 says the XID in RELEASE packets is selected by the client
#	This should work, even though it doesn't correspond to the one from
#	the DISCOVER...ACK exchange
	pset rel bootpc xid			0xbaadcafe
	pset rel bootpc ciaddr			$cl_ipaddr
	eval pset rel bootpc chaddr		$cl_ethaddr
	pset rel bootpc option "server id"	$srv_id

	puts "$argv0: sending RELEASE packet to $srv_id, port $bootps"
	ep.sendto rel 0 $srv_id/$bootps

	# free all the packets
	foreach i { rel } {
		pfree $i
	}
}

#
# if no one passed us an ether addr, try to find one
#

if { [expr $argc < 2] } {
	puts "$argv0: no client ethernet address given, trying to find one..."

	regsub -all ":" [lindex [exec ifconfig -a | grep BROADCAST] 0] "" i
	regsub -all ":|^" [lindex [exec ifconfig $i ether | tail +2] 1] " 0x" \
	    cl_ethaddr
	set srv_ipaddr "255.255.255.255"
} else {
	regsub -all ":|^" [lindex $argv 0]" " 0x" cl_ethaddr 
	set srv_ipaddr [lindex $argv 1]
}

puts "$argv0: using (ethernet addr `$cl_ethaddr')"
dhcp_client_add "$cl_ethaddr" "$srv_ipaddr"

puts "\n$argv0: holding `$cl_ipaddr' for $slp_timeout seconds\n"
psleep $slp_timeout

dhcp_client_del "$cl_ethaddr" "$cl_ipaddr"
