⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dhclient.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (!lease->server_name) {
			warning("dhcpoffer: no memory for server name.");
			free_client_lease(lease);
			return (NULL);
		}
		memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
		lease->server_name[DHCP_SNAME_LEN]='\0';
		if (!res_hnok(lease->server_name) ) {
			warning("Bogus server name %s",  lease->server_name );
			free_client_lease(lease);
			return (NULL);
		}

	}

	/* Ditto for the filename. */
	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
	    packet->raw->file[0]) {
		/* Don't count on the NUL terminator. */
		lease->filename = malloc(DHCP_FILE_LEN + 1);
		if (!lease->filename) {
			warning("dhcpoffer: no memory for filename.");
			free_client_lease(lease);
			return (NULL);
		}
		memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
		lease->filename[DHCP_FILE_LEN]='\0';
	}
	return lease;
}

void
dhcpnak(struct packet *packet)
{
	struct interface_info *ip = packet->interface;

	/* If we're not receptive to an offer right now, or if the offer
	   has an unrecognizable transaction id, then just drop it. */
	if (packet->interface->client->xid != packet->raw->xid ||
	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
	    (memcmp(packet->interface->hw_address.haddr,
	    packet->raw->chaddr, packet->raw->hlen)))
		return;

	if (ip->client->state != S_REBOOTING &&
	    ip->client->state != S_REQUESTING &&
	    ip->client->state != S_RENEWING &&
	    ip->client->state != S_REBINDING)
		return;

	note("DHCPNAK from %s", piaddr(packet->client_addr));

	if (!ip->client->active) {
		note("DHCPNAK with no active lease.\n");
		return;
	}

	free_client_lease(ip->client->active);
	ip->client->active = NULL;

	/* Stop sending DHCPREQUEST packets... */
	cancel_timeout(send_request, ip);

	ip->client->state = S_INIT;
	state_init(ip);
}

/* Send out a DHCPDISCOVER packet, and set a timeout to send out another
   one after the right interval has expired.  If we don't get an offer by
   the time we reach the panic interval, call the panic function. */

void
send_discover(void *ipp)
{
	struct interface_info *ip = ipp;
	int interval, increase = 1;

        DH_DbgPrint(MID_TRACE,("Doing discover on interface %p\n",ip));

	/* Figure out how long it's been since we started transmitting. */
	interval = cur_time - ip->client->first_sending;

	/* If we're past the panic timeout, call the script and tell it
	   we haven't found anything for this interface yet. */
	if (interval > ip->client->config->timeout) {
		state_panic(ip);
		return;
	}

	/* If we're selecting media, try the whole list before doing
	   the exponential backoff, but if we've already received an
	   offer, stop looping, because we obviously have it right. */
	if (!ip->client->offered_leases &&
	    ip->client->config->media) {
		int fail = 0;

		if (ip->client->medium) {
			ip->client->medium = ip->client->medium->next;
			increase = 0;
		}
		if (!ip->client->medium) {
			if (fail)
				error("No valid media types for %s!", ip->name);
			ip->client->medium = ip->client->config->media;
			increase = 1;
		}

		note("Trying medium \"%s\" %d", ip->client->medium->string,
		    increase);
                /* XXX Support other media types eventually */
	}

	/*
	 * If we're supposed to increase the interval, do so.  If it's
	 * currently zero (i.e., we haven't sent any packets yet), set
	 * it to one; otherwise, add to it a random number between zero
	 * and two times itself.  On average, this means that it will
	 * double with every transmission.
	 */
	if (increase) {
		if (!ip->client->interval)
			ip->client->interval =
			    ip->client->config->initial_interval;
		else {
			ip->client->interval += (rand() >> 2) %
			    (2 * ip->client->interval);
		}

		/* Don't backoff past cutoff. */
		if (ip->client->interval >
		    ip->client->config->backoff_cutoff)
			ip->client->interval =
				((ip->client->config->backoff_cutoff / 2)
				 + ((rand() >> 2) %
				    ip->client->config->backoff_cutoff));
	} else if (!ip->client->interval)
		ip->client->interval =
			ip->client->config->initial_interval;

	/* If the backoff would take us to the panic timeout, just use that
	   as the interval. */
	if (cur_time + ip->client->interval >
	    ip->client->first_sending + ip->client->config->timeout)
		ip->client->interval =
			(ip->client->first_sending +
			 ip->client->config->timeout) - cur_time + 1;

	/* Record the number of seconds since we started sending. */
	if (interval < 65536)
		ip->client->packet.secs = htons(interval);
	else
		ip->client->packet.secs = htons(65535);
	ip->client->secs = ip->client->packet.secs;

	note("DHCPDISCOVER on %s to %s port %d interval %ld",
	    ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
	    ntohs(sockaddr_broadcast.sin_port), ip->client->interval);

	/* Send out a packet. */
	(void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
	    inaddr_any, &sockaddr_broadcast, NULL);

        DH_DbgPrint(MID_TRACE,("discover timeout: now %x -> then %x\n",
                               cur_time, cur_time + ip->client->interval));

	add_timeout(cur_time + ip->client->interval, send_discover, ip);
}

/*
 * state_panic gets called if we haven't received any offers in a preset
 * amount of time.   When this happens, we try to use existing leases
 * that haven't yet expired, and failing that, we call the client script
 * and hope it can do something.
 */
void
state_panic(void *ipp)
{
	struct interface_info *ip = ipp;
	struct client_lease *loop = ip->client->active;
	struct client_lease *lp;

	note("No DHCPOFFERS received.");

	/* We may not have an active lease, but we may have some
	   predefined leases that we can try. */
	if (!ip->client->active && ip->client->leases)
		goto activate_next;

	/* Run through the list of leases and see if one can be used. */
	while (ip->client->active) {
		if (ip->client->active->expiry > cur_time) {
			note("Trying recorded lease %s",
			    piaddr(ip->client->active->address));
			/* Run the client script with the existing
			   parameters. */
			script_init("TIMEOUT",
			    ip->client->active->medium);
			script_write_params("new_", ip->client->active);
			if (ip->client->alias)
				script_write_params("alias_",
				    ip->client->alias);

			/* If the old lease is still good and doesn't
			   yet need renewal, go into BOUND state and
			   timeout at the renewal time. */
                        if (cur_time <
                            ip->client->active->renewal) {
                            ip->client->state = S_BOUND;
                            note("bound: renewal in %ld seconds.",
                                 ip->client->active->renewal -
                                 cur_time);
                            add_timeout(
                                ip->client->active->renewal,
                                state_bound, ip);
                        } else {
                            ip->client->state = S_BOUND;
                            note("bound: immediate renewal.");
                            state_bound(ip);
                        }
                        reinitialize_interfaces();
                        return;
		}

		/* If there are no other leases, give up. */
		if (!ip->client->leases) {
			ip->client->leases = ip->client->active;
			ip->client->active = NULL;
			break;
		}

activate_next:
		/* Otherwise, put the active lease at the end of the
		   lease list, and try another lease.. */
		for (lp = ip->client->leases; lp->next; lp = lp->next)
			;
		lp->next = ip->client->active;
		if (lp->next)
			lp->next->next = NULL;
		ip->client->active = ip->client->leases;
		ip->client->leases = ip->client->leases->next;

		/* If we already tried this lease, we've exhausted the
		   set of leases, so we might as well give up for
		   now. */
		if (ip->client->active == loop)
			break;
		else if (!loop)
			loop = ip->client->active;
	}

	/* No leases were available, or what was available didn't work, so
	   tell the shell script that we failed to allocate an address,
	   and try again later. */
	note("No working leases in persistent database - sleeping.\n");
	ip->client->state = S_INIT;
	add_timeout(cur_time + ip->client->config->retry_interval, state_init,
	    ip);
        /* XXX Take any failure actions necessary */
}

void
send_request(void *ipp)
{
	struct interface_info *ip = ipp;
	struct sockaddr_in destination;
	struct in_addr from;
	int interval;

	/* Figure out how long it's been since we started transmitting. */
	interval = cur_time - ip->client->first_sending;

	/* If we're in the INIT-REBOOT or REQUESTING state and we're
	   past the reboot timeout, go to INIT and see if we can
	   DISCOVER an address... */
	/* XXX In the INIT-REBOOT state, if we don't get an ACK, it
	   means either that we're on a network with no DHCP server,
	   or that our server is down.  In the latter case, assuming
	   that there is a backup DHCP server, DHCPDISCOVER will get
	   us a new address, but we could also have successfully
	   reused our old address.  In the former case, we're hosed
	   anyway.  This is not a win-prone situation. */
	if ((ip->client->state == S_REBOOTING ||
	    ip->client->state == S_REQUESTING) &&
	    interval > ip->client->config->reboot_timeout) {
		ip->client->state = S_INIT;
		cancel_timeout(send_request, ip);
		state_init(ip);
		return;
	}

	/* If we're in the reboot state, make sure the media is set up
	   correctly. */
	if (ip->client->state == S_REBOOTING &&
	    !ip->client->medium &&
	    ip->client->active->medium ) {
		script_init("MEDIUM", ip->client->active->medium);

		/* If the medium we chose won't fly, go to INIT state. */
                /* XXX Nothing for now */

		/* Record the medium. */
		ip->client->medium = ip->client->active->medium;
	}

	/* If the lease has expired, relinquish the address and go back
	   to the INIT state. */
	if (ip->client->state != S_REQUESTING &&
	    cur_time > ip->client->active->expiry) {
            PDHCP_ADAPTER Adapter = AdapterFindInfo( ip );
            /* Run the client script with the new parameters. */
            /* No script actions necessary in the expiry case */
            /* Now do a preinit on the interface so that we can
               discover a new address. */

            if( Adapter )
                DeleteIPAddress( Adapter->NteContext );

            ip->client->state = S_INIT;
            state_init(ip);
            return;
	}

	/* Do the exponential backoff... */
	if (!ip->client->interval)
		ip->client->interval = ip->client->config->initial_interval;
	else
		ip->client->interval += ((rand() >> 2) %
		    (2 * ip->client->interval));

	/* Don't backoff past cutoff. */
	if (ip->client->interval >
	    ip->client->config->backoff_cutoff)
		ip->client->interval =
		    ((ip->client->config->backoff_cutoff / 2) +
		    ((rand() >> 2) % ip->client->interval));

	/* If the backoff would take us to the expiry time, just set the
	   timeout to the expiry time. */
	if (ip->client->state != S_REQUESTING &&
	    cur_time + ip->client->interval >
	    ip->client->active->expiry)
		ip->client->interval =
		    ip->client->active->expiry - cur_time + 1;

	/* If the lease T2 time has elapsed, or if we're not yet bound,
	   broadcast the DHCPREQUEST rather than unicasting. */
	memset(&destination, 0, sizeof(destination));
	if (ip->client->state == S_REQUESTING ||
	    ip->client->state == S_REBOOTING ||
	    cur_time > ip->client->active->rebind)
		destination.sin_addr.s_addr = INADDR_BROADCAST;
	else
		memcpy(&destination.sin_addr.s_addr,
		    ip->client->destination.iabuf,
		    sizeof(destination.sin_addr.s_addr));
	destination.sin_port = htons(REMOTE_PORT);
	destination.sin_family = AF_INET;
//	destination.sin_len = sizeof(destination);

	if (ip->client->state != S_REQUESTING)
		memcpy(&from, ip->client->active->address.iabuf,
		    sizeof(from));
	else
		from.s_addr = INADDR_ANY;

	/* Record the number of seconds since we started sending. */
	if (ip->client->state == S_REQUESTING)
		ip->client->packet.secs = ip->client->secs;
	else {
		if (interval < 65536)
			ip->client->packet.secs = htons(interval);
		else
			ip->client->packet.secs = htons(65535);
	}

	note("DHCPREQUEST on %s to %s port %d", ip->name,
	    inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));

	/* Send out a packet. */
	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
	    from, &destination, NULL);

	add_timeout(cur_time + ip->client->interval, send_request, ip);
}

void
send_decline(void *ipp)
{
	struct interface_info *ip = ipp;

	note("DHCPDECLINE on %s to %s port %d", ip->name,
	    inet_ntoa(sockaddr_broadcast.sin_addr),
	    ntohs(sockaddr_broadcast.sin_port));

	/* Send out a packet. */
	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
	    inaddr_any, &sockaddr_broadcast, NULL);
}

void
make_discover(struct interface_info *ip, struct client_lease *lease)
{
	unsigned char discover = DHCPDISCOVER;
	struct tree_cache *options[256];
	struct tree_cache option_elements[256];
	int i;
	ULONG foo = (ULONG) GetTickCount();

	memset(option_elements, 0, sizeof(option_elements));
	memset(options, 0, sizeof(options));
	memset(&ip->client->packet, 0, sizeof(ip->client->packet));

	/* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
	i = DHO_DHCP_MESSAGE_TYPE;
	options[i] = &option_elements[i];
	options[i]->value = &discover;
	options[i]->len = sizeof(discover);
	options[i]->buf_size = sizeof(discover);
	options[i]->timeout = 0xFFFFFFFF;

	/* Request the options we want */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -