#!/opt/psh/bin/psh

#
# Copyright (c) 1997-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	"@(#)provoke_nak	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 nak } {
		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 "server id"		$srv_id
	pset req bootpc opt "ip address lease"	[pget offer bootpc opt \
	    "ip address lease"]

	# set `requested ip address' to a manifestly bad address
	# in order to provoke a NAK
	pset req bootpc opt "requested ip"	"224.0.0.1"
	pset req bootpc giaddr			"0.0.0.0"
	puts "$argv0: sending REQUEST packet to [lindex $srv_id 0], port $bootps"

	ep.sendto req 0 [lindex $srv_id 0]/$bootps

	while { 1 } {
		if { [ep.recvfrom nak 0 $srv_timeout] == "timeout" } {
			puts "$argv0: no response to REQUEST packet"
			return
		}
		if { [pget nak bootpc option "dhcp message type" ] != "0x6 (nak)" } {
			# discard other, later offers
			if { [pget nak bootpc option "dhcp message type" ] == "0x2 (offer)"} {
				set srv_id  [pget offer bootpc opt "server id"]
				puts "$argv0: offer from $srv_id discarded"
				continue
			} else {
				puts "$argv0: received non-NAK packet from dhcp server"
				puts [pget nak bootpc option "dhcp message type" ]
				puts [plist nak]
				return
			}
		}

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

#
# 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"
	set srv_ipaddr "129.146.86.180"
} 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"
