M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
dhcpclient.c \
dhcpmsg.c \
dhcp_utils.c \
ifc_utils.c \
packet.c
LOCAL_SHARED_LIBRARIES := \
libcutils
# need "-lrt" on Linux simulator to pick up clock_gettime
ifeq ($(TARGET_SIMULATOR),true)
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -lrt -lpthread
endif
endif
LOCAL_MODULE:= libnetutils
include $(BUILD_SHARED_LIBRARY)
+190
View File
@@ -0,0 +1,190 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
+289
View File
@@ -0,0 +1,289 @@
/*
* Copyright 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Utilities for managing the dhcpcd DHCP client daemon */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cutils/properties.h>
static const char DAEMON_NAME[] = "dhcpcd";
static const char DAEMON_PROP_NAME[] = "init.svc.dhcpcd";
static const char HOSTNAME_PROP_NAME[] = "net.hostname";
static const char DHCP_PROP_NAME_PREFIX[] = "dhcp";
static const char DAEMON_NAME_RENEW[] = "iprenew";
static const int NAP_TIME = 1; /* wait for 1 second at a time */
/* when polling for property values */
static char errmsg[100];
/*
* Wait for a system property to be assigned a specified value.
* If desired_value is NULL, then just wait for the property to
* be created with any value. maxwait is the maximum amount of
* time in seconds to wait before giving up.
*/
static int wait_for_property(const char *name, const char *desired_value, int maxwait)
{
char value[PROPERTY_VALUE_MAX] = {'\0'};
int maxnaps = maxwait / NAP_TIME;
if (maxnaps < 1) {
maxnaps = 1;
}
while (maxnaps-- > 0) {
usleep(1000000);
if (property_get(name, value, NULL)) {
if (desired_value == NULL ||
strcmp(value, desired_value) == 0) {
return 0;
}
}
}
return -1; /* failure */
}
static void fill_ip_info(const char *interface,
in_addr_t *ipaddr,
in_addr_t *gateway,
in_addr_t *mask,
in_addr_t *dns1,
in_addr_t *dns2,
in_addr_t *server,
uint32_t *lease)
{
char prop_name[PROPERTY_KEY_MAX];
char prop_value[PROPERTY_VALUE_MAX];
struct in_addr addr;
in_addr_t iaddr;
snprintf(prop_name, sizeof(prop_name), "%s.%s.ipaddress", DHCP_PROP_NAME_PREFIX, interface);
if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
*ipaddr = addr.s_addr;
} else {
*ipaddr = 0;
}
snprintf(prop_name, sizeof(prop_name), "%s.%s.gateway", DHCP_PROP_NAME_PREFIX, interface);
if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
*gateway = addr.s_addr;
} else {
*gateway = 0;
}
snprintf(prop_name, sizeof(prop_name), "%s.%s.mask", DHCP_PROP_NAME_PREFIX, interface);
if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
*mask = addr.s_addr;
} else {
*mask = 0;
}
snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, interface);
if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
*dns1 = addr.s_addr;
} else {
*dns1 = 0;
}
snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, interface);
if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
*dns2 = addr.s_addr;
} else {
*dns2 = 0;
}
snprintf(prop_name, sizeof(prop_name), "%s.%s.server", DHCP_PROP_NAME_PREFIX, interface);
if (property_get(prop_name, prop_value, NULL) && inet_aton(prop_value, &addr)) {
*server = addr.s_addr;
} else {
*server = 0;
}
snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, interface);
if (property_get(prop_name, prop_value, NULL)) {
*lease = atol(prop_value);
}
}
/*
* Start the dhcp client daemon, and wait for it to finish
* configuring the interface.
*/
int dhcp_do_request(const char *interface,
in_addr_t *ipaddr,
in_addr_t *gateway,
in_addr_t *mask,
in_addr_t *dns1,
in_addr_t *dns2,
in_addr_t *server,
uint32_t *lease)
{
char result_prop_name[PROPERTY_KEY_MAX];
char daemon_prop_name[PROPERTY_KEY_MAX];
char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
char daemon_cmd[PROPERTY_VALUE_MAX * 2];
const char *ctrl_prop = "ctl.start";
const char *desired_status = "running";
snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
DHCP_PROP_NAME_PREFIX,
interface);
snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
DAEMON_PROP_NAME,
interface);
/* Erase any previous setting of the dhcp result property */
property_set(result_prop_name, "");
/* Start the daemon and wait until it's ready */
if (property_get(HOSTNAME_PROP_NAME, prop_value, NULL) && (prop_value[0] != '\0'))
snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:-h %s %s", DAEMON_NAME, interface,
prop_value, interface);
else
snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME, interface, interface);
memset(prop_value, '\0', PROPERTY_VALUE_MAX);
property_set(ctrl_prop, daemon_cmd);
if (wait_for_property(daemon_prop_name, desired_status, 10) < 0) {
snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for dhcpcd to start");
return -1;
}
/* Wait for the daemon to return a result */
if (wait_for_property(result_prop_name, NULL, 30) < 0) {
snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP to finish");
return -1;
}
if (!property_get(result_prop_name, prop_value, NULL)) {
/* shouldn't ever happen, given the success of wait_for_property() */
snprintf(errmsg, sizeof(errmsg), "%s", "DHCP result property was not set");
return -1;
}
if (strcmp(prop_value, "ok") == 0) {
fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
return 0;
} else {
snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
return -1;
}
}
/**
* Stop the DHCP client daemon.
*/
int dhcp_stop(const char *interface)
{
char result_prop_name[PROPERTY_KEY_MAX];
char daemon_prop_name[PROPERTY_KEY_MAX];
char daemon_cmd[PROPERTY_VALUE_MAX * 2];
const char *ctrl_prop = "ctl.stop";
const char *desired_status = "stopped";
snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
DHCP_PROP_NAME_PREFIX,
interface);
snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
DAEMON_PROP_NAME,
interface);
snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, interface);
/* Stop the daemon and wait until it's reported to be stopped */
property_set(ctrl_prop, daemon_cmd);
if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
return -1;
}
property_set(result_prop_name, "failed");
return 0;
}
/**
* Release the current DHCP client lease.
*/
int dhcp_release_lease(const char *interface)
{
char daemon_prop_name[PROPERTY_KEY_MAX];
char daemon_cmd[PROPERTY_VALUE_MAX * 2];
const char *ctrl_prop = "ctl.stop";
const char *desired_status = "stopped";
snprintf(daemon_prop_name, sizeof(daemon_prop_name), "%s_%s",
DAEMON_PROP_NAME,
interface);
snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s", DAEMON_NAME, interface);
/* Stop the daemon and wait until it's reported to be stopped */
property_set(ctrl_prop, daemon_cmd);
if (wait_for_property(daemon_prop_name, desired_status, 5) < 0) {
return -1;
}
return 0;
}
char *dhcp_get_errmsg() {
return errmsg;
}
/**
* Run WiMAX dhcp renew service.
* "wimax_renew" service shoud be included in init.rc.
*/
int dhcp_do_request_renew(const char *interface,
in_addr_t *ipaddr,
in_addr_t *gateway,
in_addr_t *mask,
in_addr_t *dns1,
in_addr_t *dns2,
in_addr_t *server,
uint32_t *lease)
{
char result_prop_name[PROPERTY_KEY_MAX];
char prop_value[PROPERTY_VALUE_MAX] = {'\0'};
char daemon_cmd[PROPERTY_VALUE_MAX * 2];
const char *ctrl_prop = "ctl.start";
snprintf(result_prop_name, sizeof(result_prop_name), "%s.%s.result",
DHCP_PROP_NAME_PREFIX,
interface);
/* Erase any previous setting of the dhcp result property */
property_set(result_prop_name, "");
/* Start the renew daemon and wait until it's ready */
snprintf(daemon_cmd, sizeof(daemon_cmd), "%s_%s:%s", DAEMON_NAME_RENEW, interface, interface);
memset(prop_value, '\0', PROPERTY_VALUE_MAX);
property_set(ctrl_prop, daemon_cmd);
/* Wait for the daemon to return a result */
if (wait_for_property(result_prop_name, NULL, 30) < 0) {
snprintf(errmsg, sizeof(errmsg), "%s", "Timed out waiting for DHCP Renew to finish");
return -1;
}
if (!property_get(result_prop_name, prop_value, NULL)) {
/* shouldn't ever happen, given the success of wait_for_property() */
snprintf(errmsg, sizeof(errmsg), "%s", "DHCP Renew result property was not set");
return -1;
}
if (strcmp(prop_value, "ok") == 0) {
fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
return 0;
} else {
snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
return -1;
}
}
+573
View File
@@ -0,0 +1,573 @@
/*
* Copyright 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <cutils/properties.h>
#define LOG_TAG "DHCP"
#include <cutils/log.h>
#include <dirent.h>
#include "dhcpmsg.h"
#include "ifc_utils.h"
#include "packet.h"
#define VERBOSE 2
static int verbose = 1;
static char errmsg[2048];
typedef unsigned long long msecs_t;
#if VERBOSE
void dump_dhcp_msg();
#endif
msecs_t get_msecs(void)
{
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
return 0;
} else {
return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) +
(((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000));
}
}
void printerr(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(errmsg, sizeof(errmsg), fmt, ap);
va_end(ap);
LOGD("%s", errmsg);
}
const char *dhcp_lasterror()
{
return errmsg;
}
int fatal(const char *reason)
{
printerr("%s: %s\n", reason, strerror(errno));
return -1;
// exit(1);
}
const char *ipaddr(uint32_t addr)
{
static char buf[32];
sprintf(buf,"%d.%d.%d.%d",
addr & 255,
((addr >> 8) & 255),
((addr >> 16) & 255),
(addr >> 24));
return buf;
}
typedef struct dhcp_info dhcp_info;
struct dhcp_info {
uint32_t type;
uint32_t ipaddr;
uint32_t gateway;
uint32_t netmask;
uint32_t dns1;
uint32_t dns2;
uint32_t serveraddr;
uint32_t lease;
};
dhcp_info last_good_info;
void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *mask,
uint32_t *dns1, uint32_t *dns2, uint32_t *server,
uint32_t *lease)
{
*ipaddr = last_good_info.ipaddr;
*gateway = last_good_info.gateway;
*mask = last_good_info.netmask;
*dns1 = last_good_info.dns1;
*dns2 = last_good_info.dns2;
*server = last_good_info.serveraddr;
*lease = last_good_info.lease;
}
static int ifc_configure(const char *ifname, dhcp_info *info)
{
char dns_prop_name[PROPERTY_KEY_MAX];
if (ifc_set_addr(ifname, info->ipaddr)) {
printerr("failed to set ipaddr %s: %s\n", ipaddr(info->ipaddr), strerror(errno));
return -1;
}
if (ifc_set_mask(ifname, info->netmask)) {
printerr("failed to set netmask %s: %s\n", ipaddr(info->netmask), strerror(errno));
return -1;
}
#if 0
/*
* Removing adding default routes automatically when interface comes up. Connectivity service
* in android will determine the interface that needs to be used for default internet connection,
* when several interfaces are active simultaneously.
*/
if (ifc_create_default_route(ifname, info->gateway)) {
printerr("failed to set default route %s: %s\n", ipaddr(info->gateway), strerror(errno));
return -1;
}
#endif
snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname);
property_set(dns_prop_name, info->dns1 ? ipaddr(info->dns1) : "");
snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname);
property_set(dns_prop_name, info->dns2 ? ipaddr(info->dns2) : "");
snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.gw", ifname);
property_set(dns_prop_name, info->gateway ? ipaddr(info->gateway) : "");
last_good_info = *info;
return 0;
}
static const char *dhcp_type_to_name(uint32_t type)
{
switch(type) {
case DHCPDISCOVER: return "discover";
case DHCPOFFER: return "offer";
case DHCPREQUEST: return "request";
case DHCPDECLINE: return "decline";
case DHCPACK: return "ack";
case DHCPNAK: return "nak";
case DHCPRELEASE: return "release";
case DHCPINFORM: return "inform";
default: return "???";
}
}
void dump_dhcp_info(dhcp_info *info)
{
char addr[20], gway[20], mask[20];
LOGD("--- dhcp %s (%d) ---",
dhcp_type_to_name(info->type), info->type);
strcpy(addr, ipaddr(info->ipaddr));
strcpy(gway, ipaddr(info->gateway));
strcpy(mask, ipaddr(info->netmask));
LOGD("ip %s gw %s mask %s", addr, gway, mask);
if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
LOGD("server %s, lease %d seconds",
ipaddr(info->serveraddr), info->lease);
}
int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
{
uint8_t *x;
unsigned int opt;
int optlen;
memset(info, 0, sizeof(dhcp_info));
if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
len -= (DHCP_MSG_FIXED_SIZE + 4);
if (msg->options[0] != OPT_COOKIE1) return -1;
if (msg->options[1] != OPT_COOKIE2) return -1;
if (msg->options[2] != OPT_COOKIE3) return -1;
if (msg->options[3] != OPT_COOKIE4) return -1;
x = msg->options + 4;
while (len > 2) {
opt = *x++;
if (opt == OPT_PAD) {
len--;
continue;
}
if (opt == OPT_END) {
break;
}
optlen = *x++;
len -= 2;
if (optlen > len) {
break;
}
switch(opt) {
case OPT_SUBNET_MASK:
if (optlen >= 4) memcpy(&info->netmask, x, 4);
break;
case OPT_GATEWAY:
if (optlen >= 4) memcpy(&info->gateway, x, 4);
break;
case OPT_DNS:
if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
break;
case OPT_LEASE_TIME:
if (optlen >= 4) {
memcpy(&info->lease, x, 4);
info->lease = ntohl(info->lease);
}
break;
case OPT_SERVER_ID:
if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
break;
case OPT_MESSAGE_TYPE:
info->type = *x;
break;
default:
break;
}
x += optlen;
len -= optlen;
}
info->ipaddr = msg->yiaddr;
return 0;
}
#if VERBOSE
static void hex2str(char *buf, const unsigned char *array, int len)
{
int i;
char *cp = buf;
for (i = 0; i < len; i++) {
cp += sprintf(cp, " %02x ", array[i]);
}
}
void dump_dhcp_msg(dhcp_msg *msg, int len)
{
unsigned char *x;
unsigned int n,c;
int optsz;
const char *name;
char buf[2048];
LOGD("===== DHCP message:");
if (len < DHCP_MSG_FIXED_SIZE) {
LOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
return;
}
len -= DHCP_MSG_FIXED_SIZE;
if (msg->op == OP_BOOTREQUEST)
name = "BOOTREQUEST";
else if (msg->op == OP_BOOTREPLY)
name = "BOOTREPLY";
else
name = "????";
LOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
name, msg->op, msg->htype, msg->hlen, msg->hops);
LOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
LOGD("ciaddr = %s", ipaddr(msg->ciaddr));
LOGD("yiaddr = %s", ipaddr(msg->yiaddr));
LOGD("siaddr = %s", ipaddr(msg->siaddr));
LOGD("giaddr = %s", ipaddr(msg->giaddr));
c = msg->hlen > 16 ? 16 : msg->hlen;
hex2str(buf, msg->chaddr, c);
LOGD("chaddr = {%s}", buf);
for (n = 0; n < 64; n++) {
if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
if (msg->sname[n] == 0) break;
msg->sname[n] = '.';
}
}
msg->sname[63] = 0;
for (n = 0; n < 128; n++) {
if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
if (msg->file[n] == 0) break;
msg->file[n] = '.';
}
}
msg->file[127] = 0;
LOGD("sname = '%s'", msg->sname);
LOGD("file = '%s'", msg->file);
if (len < 4) return;
len -= 4;
x = msg->options + 4;
while (len > 2) {
if (*x == 0) {
x++;
len--;
continue;
}
if (*x == OPT_END) {
break;
}
len -= 2;
optsz = x[1];
if (optsz > len) break;
if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) {
if ((unsigned int)optsz < sizeof(buf) - 1) {
n = optsz;
} else {
n = sizeof(buf) - 1;
}
memcpy(buf, &x[2], n);
buf[n] = '\0';
} else {
hex2str(buf, &x[2], optsz);
}
if (x[0] == OPT_MESSAGE_TYPE)
name = dhcp_type_to_name(x[2]);
else
name = NULL;
LOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
len -= optsz;
x = x + optsz + 2;
}
}
#endif
static int send_message(int sock, int if_index, dhcp_msg *msg, int size)
{
#if VERBOSE > 1
dump_dhcp_msg(msg, size);
#endif
return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
}
static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
{
if (sz < DHCP_MSG_FIXED_SIZE) {
if (verbose) LOGD("netcfg: Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
return 0;
}
if (reply->op != OP_BOOTREPLY) {
if (verbose) LOGD("netcfg: Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
return 0;
}
if (reply->xid != msg->xid) {
if (verbose) LOGD("netcfg: Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
ntohl(msg->xid));
return 0;
}
if (reply->htype != msg->htype) {
if (verbose) LOGD("netcfg: Wrong Htype %d != %d\n", reply->htype, msg->htype);
return 0;
}
if (reply->hlen != msg->hlen) {
if (verbose) LOGD("netcfg: Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
return 0;
}
if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
if (verbose) LOGD("netcfg: Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
return 0;
}
return 1;
}
#define STATE_SELECTING 1
#define STATE_REQUESTING 2
#define TIMEOUT_INITIAL 4000
#define TIMEOUT_MAX 32000
int dhcp_init_ifc(const char *ifname)
{
dhcp_msg discover_msg;
dhcp_msg request_msg;
dhcp_msg reply;
dhcp_msg *msg;
dhcp_info info;
int s, r, size;
int valid_reply;
uint32_t xid;
unsigned char hwaddr[6];
struct pollfd pfd;
unsigned int state;
unsigned int timeout;
int if_index;
xid = (uint32_t) get_msecs();
if (ifc_get_hwaddr(ifname, hwaddr)) {
return fatal("cannot obtain interface address");
}
if (ifc_get_ifindex(ifname, &if_index)) {
return fatal("cannot obtain interface index");
}
s = open_raw_socket(ifname, hwaddr, if_index);
timeout = TIMEOUT_INITIAL;
state = STATE_SELECTING;
info.type = 0;
goto transmit;
for (;;) {
pfd.fd = s;
pfd.events = POLLIN;
pfd.revents = 0;
r = poll(&pfd, 1, timeout);
if (r == 0) {
#if VERBOSE
printerr("TIMEOUT\n");
#endif
if (timeout >= TIMEOUT_MAX) {
printerr("timed out\n");
if ( info.type == DHCPOFFER ) {
printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
return ifc_configure(ifname, &info);
}
errno = ETIME;
close(s);
return -1;
}
timeout = timeout * 2;
transmit:
size = 0;
msg = NULL;
switch(state) {
case STATE_SELECTING:
msg = &discover_msg;
size = init_dhcp_discover_msg(msg, hwaddr, xid);
break;
case STATE_REQUESTING:
msg = &request_msg;
size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
break;
default:
r = 0;
}
if (size != 0) {
r = send_message(s, if_index, msg, size);
if (r < 0) {
printerr("error sending dhcp msg: %s\n", strerror(errno));
}
}
continue;
}
if (r < 0) {
if ((errno == EAGAIN) || (errno == EINTR)) {
continue;
}
return fatal("poll failed");
}
errno = 0;
r = receive_packet(s, &reply);
if (r < 0) {
if (errno != 0) {
LOGD("receive_packet failed (%d): %s", r, strerror(errno));
if (errno == ENETDOWN || errno == ENXIO) {
return -1;
}
}
continue;
}
#if VERBOSE > 1
dump_dhcp_msg(&reply, r);
#endif
decode_dhcp_msg(&reply, r, &info);
if (state == STATE_SELECTING) {
valid_reply = is_valid_reply(&discover_msg, &reply, r);
} else {
valid_reply = is_valid_reply(&request_msg, &reply, r);
}
if (!valid_reply) {
printerr("invalid reply\n");
continue;
}
if (verbose) dump_dhcp_info(&info);
switch(state) {
case STATE_SELECTING:
if (info.type == DHCPOFFER) {
state = STATE_REQUESTING;
timeout = TIMEOUT_INITIAL;
xid++;
goto transmit;
}
break;
case STATE_REQUESTING:
if (info.type == DHCPACK) {
printerr("configuring %s\n", ifname);
close(s);
return ifc_configure(ifname, &info);
} else if (info.type == DHCPNAK) {
printerr("configuration request denied\n");
close(s);
return -1;
} else {
printerr("ignoring %s message in state %d\n",
dhcp_type_to_name(info.type), state);
}
break;
}
}
close(s);
return 0;
}
int do_dhcp(char *iname)
{
if (ifc_set_addr(iname, 0)) {
printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno));
return -1;
}
if (ifc_up(iname)) {
printerr("failed to bring up interface %s: %s\n", iname, strerror(errno));
return -1;
}
return dhcp_init_ifc(iname);
}
+100
View File
@@ -0,0 +1,100 @@
/*
* Copyright 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <netinet/in.h>
#include "dhcpmsg.h"
static void *init_dhcp_msg(dhcp_msg *msg, int type, void *hwaddr, uint32_t xid)
{
uint8_t *x;
memset(msg, 0, sizeof(dhcp_msg));
msg->op = OP_BOOTREQUEST;
msg->htype = HTYPE_ETHER;
msg->hlen = 6;
msg->hops = 0;
msg->flags = htons(FLAGS_BROADCAST);
msg->xid = xid;
memcpy(msg->chaddr, hwaddr, 6);
x = msg->options;
*x++ = OPT_COOKIE1;
*x++ = OPT_COOKIE2;
*x++ = OPT_COOKIE3;
*x++ = OPT_COOKIE4;
*x++ = OPT_MESSAGE_TYPE;
*x++ = 1;
*x++ = type;
return x;
}
int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid)
{
uint8_t *x;
x = init_dhcp_msg(msg, DHCPDISCOVER, hwaddr, xid);
*x++ = OPT_PARAMETER_LIST;
*x++ = 4;
*x++ = OPT_SUBNET_MASK;
*x++ = OPT_GATEWAY;
*x++ = OPT_DNS;
*x++ = OPT_BROADCAST_ADDR;
*x++ = OPT_END;
return DHCP_MSG_FIXED_SIZE + (x - msg->options);
}
int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
uint32_t ipaddr, uint32_t serveraddr)
{
uint8_t *x;
x = init_dhcp_msg(msg, DHCPREQUEST, hwaddr, xid);
*x++ = OPT_PARAMETER_LIST;
*x++ = 4;
*x++ = OPT_SUBNET_MASK;
*x++ = OPT_GATEWAY;
*x++ = OPT_DNS;
*x++ = OPT_BROADCAST_ADDR;
*x++ = OPT_REQUESTED_IP;
*x++ = 4;
memcpy(x, &ipaddr, 4);
x += 4;
*x++ = OPT_SERVER_ID;
*x++ = 4;
memcpy(x, &serveraddr, 4);
x += 4;
*x++ = OPT_END;
return DHCP_MSG_FIXED_SIZE + (x - msg->options);
}
+106
View File
@@ -0,0 +1,106 @@
/*
* Copyright 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _WIFI_DHCP_H_
#define _WIFI_DHCP_H_
#include <sys/types.h>
#define PORT_BOOTP_SERVER 67
#define PORT_BOOTP_CLIENT 68
/* RFC 2131 p 9 */
typedef struct dhcp_msg dhcp_msg;
#define OP_BOOTREQUEST 1
#define OP_BOOTREPLY 2
#define FLAGS_BROADCAST 0x8000
#define HTYPE_ETHER 1
struct dhcp_msg
{
uint8_t op; /* BOOTREQUEST / BOOTREPLY */
uint8_t htype; /* hw addr type */
uint8_t hlen; /* hw addr len */
uint8_t hops; /* client set to 0 */
uint32_t xid; /* transaction id */
uint16_t secs; /* seconds since start of acq */
uint16_t flags;
uint32_t ciaddr; /* client IP addr */
uint32_t yiaddr; /* your (client) IP addr */
uint32_t siaddr; /* ip addr of next server */
/* (DHCPOFFER and DHCPACK) */
uint32_t giaddr; /* relay agent IP addr */
uint8_t chaddr[16]; /* client hw addr */
char sname[64]; /* asciiz server hostname */
char file[128]; /* asciiz boot file name */
uint8_t options[1024]; /* optional parameters */
};
#define DHCP_MSG_FIXED_SIZE 236
/* first four bytes of options are a cookie to indicate that
** the payload are DHCP options as opposed to some other BOOTP
** extension.
*/
#define OPT_COOKIE1 0x63
#define OPT_COOKIE2 0x82
#define OPT_COOKIE3 0x53
#define OPT_COOKIE4 0x63
/* BOOTP/DHCP options - see RFC 2132 */
#define OPT_PAD 0
#define OPT_SUBNET_MASK 1 /* 4 <ipaddr> */
#define OPT_TIME_OFFSET 2 /* 4 <seconds> */
#define OPT_GATEWAY 3 /* 4*n <ipaddr> * n */
#define OPT_DNS 6 /* 4*n <ipaddr> * n */
#define OPT_DOMAIN_NAME 15 /* n <domainnamestring> */
#define OPT_BROADCAST_ADDR 28 /* 4 <ipaddr> */
#define OPT_REQUESTED_IP 50 /* 4 <ipaddr> */
#define OPT_LEASE_TIME 51 /* 4 <seconds> */
#define OPT_MESSAGE_TYPE 53 /* 1 <msgtype> */
#define OPT_SERVER_ID 54 /* 4 <ipaddr> */
#define OPT_PARAMETER_LIST 55 /* n <optcode> * n */
#define OPT_MESSAGE 56 /* n <errorstring> */
#define OPT_CLASS_ID 60 /* n <opaque> */
#define OPT_CLIENT_ID 61 /* n <opaque> */
#define OPT_END 255
/* DHCP message types */
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPDECLINE 4
#define DHCPACK 5
#define DHCPNAK 6
#define DHCPRELEASE 7
#define DHCPINFORM 8
int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid);
int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
uint32_t ipaddr, uint32_t serveraddr);
#endif
+580
View File
@@ -0,0 +1,580 @@
/*
* Copyright 2008, The Android Open Source Project
* Copyright (C) 2011, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include <linux/sockios.h>
#include <linux/route.h>
#ifdef IPV6_SUPPORTED
#include <linux/ipv6_route.h>
#endif
#include <netdb.h>
#include <linux/wireless.h>
#ifdef ANDROID
#define LOG_TAG "NetUtils"
#include <cutils/log.h>
#include <cutils/properties.h>
#else
#include <stdio.h>
#include <string.h>
#define LOGD printf
#define LOGW printf
#endif
static int ifc_ctl_sock = -1;
static int ifc_ctl_sock6 = -1;
void printerr(char *fmt, ...);
static const char *ipaddr_to_string(uint32_t addr)
{
struct in_addr in_addr;
in_addr.s_addr = addr;
return inet_ntoa(in_addr);
}
int ifc_init(void)
{
if (ifc_ctl_sock == -1) {
ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (ifc_ctl_sock < 0) {
printerr("socket() failed: %s\n", strerror(errno));
}
}
return ifc_ctl_sock < 0 ? -1 : 0;
}
int ifc_init6(void)
{
#ifdef IPV6_SUPPORTED
if (ifc_ctl_sock6 == -1) {
ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
if (ifc_ctl_sock6 < 0) {
printerr("socket() failed: %s\n", strerror(errno));
}
}
#endif
return ifc_ctl_sock6 < 0 ? -1 : 0;
}
void ifc_close(void)
{
if (ifc_ctl_sock != -1) {
(void)close(ifc_ctl_sock);
ifc_ctl_sock = -1;
}
}
void ifc_close6(void)
{
if (ifc_ctl_sock6 != -1) {
(void)close(ifc_ctl_sock6);
ifc_ctl_sock6 = -1;
}
}
static void ifc_init_ifr(const char *name, struct ifreq *ifr)
{
memset(ifr, 0, sizeof(struct ifreq));
strncpy(ifr->ifr_name, name, IFNAMSIZ);
ifr->ifr_name[IFNAMSIZ - 1] = 0;
}
int ifc_get_hwaddr(const char *name, void *ptr)
{
int r;
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr);
if(r < 0) return -1;
memcpy(ptr, &ifr.ifr_hwaddr.sa_data, 6);
return 0;
}
int ifc_get_ifindex(const char *name, int *if_indexp)
{
int r;
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
r = ioctl(ifc_ctl_sock, SIOCGIFINDEX, &ifr);
if(r < 0) return -1;
*if_indexp = ifr.ifr_ifindex;
return 0;
}
static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
{
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) return -1;
ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr);
}
int ifc_up(const char *name)
{
return ifc_set_flags(name, IFF_UP, 0);
}
int ifc_down(const char *name)
{
return ifc_set_flags(name, 0, IFF_UP);
}
static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr)
{
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
sin->sin_family = AF_INET;
sin->sin_port = 0;
sin->sin_addr.s_addr = addr;
}
int ifc_set_addr(const char *name, in_addr_t addr)
{
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
init_sockaddr_in(&ifr.ifr_addr, addr);
return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
}
int ifc_set_mask(const char *name, in_addr_t mask)
{
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
init_sockaddr_in(&ifr.ifr_addr, mask);
return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
}
int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
{
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
if (addr != NULL) {
if(ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr) < 0) {
*addr = 0;
} else {
*addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
}
}
if (mask != NULL) {
if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
*mask = 0;
} else {
*mask = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
}
}
if (flags != NULL) {
if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) {
*flags = 0;
} else {
*flags = ifr.ifr_flags;
}
}
return 0;
}
int ifc_get_mtu(const char *name, int *mtuSz)
{
struct ifreq ifr;
ifc_init_ifr(name, &ifr);
if (mtuSz != NULL) {
if(ioctl(ifc_ctl_sock, SIOCGIFMTU, &ifr) < 0) {
*mtuSz = 0;
return -2;
} else {
*mtuSz = ifr.ifr_mtu;
return 0;
}
}
return -1;
}
int ifc_create_default_route(const char *name, in_addr_t gateway)
{
return ifc_add_ipv4_route(name, gateway, 0);
}
int ifc_add_host_route(const char *name, in_addr_t addr)
{
return ifc_add_ipv4_route(name, addr, 32);
}
in_addr_t get_mask_from_prefix_length(int prefix_length)
{
in_addr_t mask = 0;
mask = ~mask << (32 - prefix_length);
mask = htonl(mask);
return mask;
}
int ifc_add_ipv4_route(const char *name, in_addr_t addr, int prefix_length)
{
struct rtentry rt;
int result;
int error;
in_addr_t mask;
memset(&rt, 0, sizeof(rt));
rt.rt_dst.sa_family = AF_INET;
rt.rt_dev = (void*) name;
if (prefix_length == 32) {
rt.rt_flags = RTF_UP | RTF_HOST;
init_sockaddr_in(&rt.rt_dst, addr);
init_sockaddr_in(&rt.rt_gateway, 0);
init_sockaddr_in(&rt.rt_genmask, 0);
} else {
rt.rt_flags = RTF_UP | RTF_GATEWAY;
init_sockaddr_in(&rt.rt_gateway, addr);
mask = get_mask_from_prefix_length(prefix_length);
init_sockaddr_in(&rt.rt_genmask, mask);
}
ifc_init();
result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
if (result < 0 && errno == EEXIST) {
result = 0;
}
error = errno;
ifc_close();
errno = error;
return result;
}
int ifc_enable(const char *ifname)
{
int result;
ifc_init();
result = ifc_up(ifname);
ifc_close();
return result;
}
int ifc_disable(const char *ifname)
{
int result;
ifc_init();
result = ifc_down(ifname);
ifc_set_addr(ifname, 0);
ifc_close();
return result;
}
int ifc_reset_connections(const char *ifname)
{
#ifdef HAVE_ANDROID_OS
int result;
in_addr_t myaddr;
struct ifreq ifr;
ifc_init();
ifc_get_info(ifname, &myaddr, NULL, NULL);
ifc_init_ifr(ifname, &ifr);
init_sockaddr_in(&ifr.ifr_addr, myaddr);
result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr);
ifc_close();
return result;
#else
return 0;
#endif
}
/*
* Remove the routes associated with the named interface.
*/
int ifc_remove_host_routes(const char *name)
{
char ifname[64];
in_addr_t dest, gway, mask;
int flags, refcnt, use, metric, mtu, win, irtt;
struct rtentry rt;
FILE *fp;
struct in_addr addr;
fp = fopen("/proc/net/route", "r");
if (fp == NULL)
return -1;
/* Skip the header line */
if (fscanf(fp, "%*[^\n]\n") < 0) {
fclose(fp);
return -1;
}
ifc_init();
for (;;) {
int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
&mtu, &win, &irtt);
if (nread != 11) {
break;
}
if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)
|| strcmp(ifname, name) != 0) {
continue;
}
memset(&rt, 0, sizeof(rt));
rt.rt_dev = (void *)name;
init_sockaddr_in(&rt.rt_dst, dest);
init_sockaddr_in(&rt.rt_gateway, gway);
init_sockaddr_in(&rt.rt_genmask, mask);
addr.s_addr = dest;
if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) {
LOGD("failed to remove route for %s to %s: %s",
ifname, inet_ntoa(addr), strerror(errno));
}
}
fclose(fp);
ifc_close();
return 0;
}
/*
* Return the address of the default gateway
*
* TODO: factor out common code from this and remove_host_routes()
* so that we only scan /proc/net/route in one place.
*/
int ifc_get_default_route(const char *ifname)
{
char name[64];
in_addr_t dest, gway, mask;
int flags, refcnt, use, metric, mtu, win, irtt;
int result;
FILE *fp;
fp = fopen("/proc/net/route", "r");
if (fp == NULL)
return 0;
/* Skip the header line */
if (fscanf(fp, "%*[^\n]\n") < 0) {
fclose(fp);
return 0;
}
ifc_init();
result = 0;
for (;;) {
int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
&mtu, &win, &irtt);
if (nread != 11) {
break;
}
if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
&& dest == 0
&& strcmp(ifname, name) == 0) {
result = gway;
break;
}
}
fclose(fp);
ifc_close();
return result;
}
/*
* Sets the specified gateway as the default route for the named interface.
*/
int ifc_set_default_route(const char *ifname, in_addr_t gateway)
{
struct in_addr addr;
int result;
ifc_init();
addr.s_addr = gateway;
if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
LOGD("failed to add %s as default route for %s: %s",
inet_ntoa(addr), ifname, strerror(errno));
}
ifc_close();
return result;
}
/*
* Removes the default route for the named interface.
*/
int ifc_remove_default_route(const char *ifname)
{
struct rtentry rt;
int result;
ifc_init();
memset(&rt, 0, sizeof(rt));
rt.rt_dev = (void *)ifname;
rt.rt_flags = RTF_UP|RTF_GATEWAY;
init_sockaddr_in(&rt.rt_dst, 0);
if ((result = ioctl(ifc_ctl_sock, SIOCDELRT, &rt)) < 0) {
LOGD("failed to remove default route for %s: %s", ifname, strerror(errno));
}
ifc_close();
return result;
}
int
ifc_configure(const char *ifname,
in_addr_t address,
in_addr_t netmask,
in_addr_t gateway,
in_addr_t dns1,
in_addr_t dns2) {
char dns_prop_name[PROPERTY_KEY_MAX];
ifc_init();
if (ifc_up(ifname)) {
printerr("failed to turn on interface %s: %s\n", ifname, strerror(errno));
ifc_close();
return -1;
}
if (ifc_set_addr(ifname, address)) {
printerr("failed to set ipaddr %s: %s\n", ipaddr_to_string(address), strerror(errno));
ifc_close();
return -1;
}
if (ifc_set_mask(ifname, netmask)) {
printerr("failed to set netmask %s: %s\n", ipaddr_to_string(netmask), strerror(errno));
ifc_close();
return -1;
}
if (ifc_create_default_route(ifname, gateway)) {
printerr("failed to set default route %s: %s\n", ipaddr_to_string(gateway), strerror(errno));
ifc_close();
return -1;
}
ifc_close();
snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns1", ifname);
property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : "");
snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns2", ifname);
property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : "");
return 0;
}
int ifc_add_route(const char *name, const char *addr, int prefix_length)
{
int ret = 0;
struct sockaddr_in ipv4_addr;
struct sockaddr_in6 ipv6_addr;
struct addrinfo *result, hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;/* Allow IPv4 or IPv6 */
hints.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo(addr, NULL, &hints, &result);
if (ret != 0) {
printerr("getaddrinfo failed: invalid address %s\n", addr);
return -1;
}
if (result->ai_family == AF_INET6) {
memcpy(&ipv6_addr, result->ai_addr, sizeof(struct sockaddr_in6));
ret = ifc_add_ipv6_route(name, ipv6_addr.sin6_addr, prefix_length);
} else if(result->ai_family == AF_INET) {
memcpy(&ipv4_addr, result->ai_addr, sizeof(struct sockaddr_in));
ret = ifc_add_ipv4_route(name, ipv4_addr.sin_addr.s_addr, prefix_length);
} else {
printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n",
result->ai_family);
ret = -1;
}
freeaddrinfo(result);
return ret;
}
int ifc_add_ipv6_route(const char *name, struct in6_addr in6_a, int prefix_length)
{
int result = -1;
#ifdef IPV6_SUPPORTED
struct in6_rtmsg rtmsg;
int ifindex;
int error;
memset(&rtmsg, 0, sizeof(rtmsg));
ifindex = if_nametoindex(name);
if (ifindex == 0) {
printerr("if_nametoindex() failed: interface %s\n", name);
return -1;
}
rtmsg.rtmsg_ifindex = ifindex;
if (prefix_length == 128) {
rtmsg.rtmsg_flags = RTF_UP | RTF_HOST;
rtmsg.rtmsg_dst = in6_a;
rtmsg.rtmsg_dst_len = prefix_length;
} else {
rtmsg.rtmsg_flags = RTF_UP | RTF_GATEWAY;
rtmsg.rtmsg_gateway = in6_a;
}
ifc_init6();
#endif
if (ifc_ctl_sock6 < 0) {
return -1;
}
#ifdef IPV6_SUPPORTED
result = ioctl(ifc_ctl_sock6, SIOCADDRT, &rtmsg);
if (result < 0 && errno == EEXIST) {
result = 0;
errno = 0;
}
error = errno;
ifc_close6();
errno = error;
#endif
return result;
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright 2008, The Android Open Source Project
* Copyright (C) 2011, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _IFC_UTILS_H_
#define _IFC_UTILS_H_
int ifc_init(void);
int ifc_get_ifindex(const char *name, int *if_indexp);
int ifc_get_hwaddr(const char *name, void *ptr);
int ifc_up(const char *name);
int ifc_down(const char *name);
int ifc_set_addr(const char *name, unsigned addr);
int ifc_set_mask(const char *name, unsigned mask);
int ifc_create_default_route(const char *name, unsigned addr);
int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags);
int ifc_get_mtu(const char *name, int *mtuSz);
#endif
+239
View File
@@ -0,0 +1,239 @@
/*
* Copyright 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <errno.h>
#ifdef ANDROID
#define LOG_TAG "DHCP"
#include <cutils/log.h>
#else
#include <stdio.h>
#include <string.h>
#define LOGD printf
#define LOGW printf
#endif
#include "dhcpmsg.h"
int fatal();
int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index)
{
int s, flag;
struct sockaddr_ll bindaddr;
if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
return fatal("socket(PF_PACKET)");
}
memset(&bindaddr, 0, sizeof(bindaddr));
bindaddr.sll_family = AF_PACKET;
bindaddr.sll_protocol = htons(ETH_P_IP);
bindaddr.sll_halen = ETH_ALEN;
memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
bindaddr.sll_ifindex = if_index;
if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
return fatal("Cannot bind raw socket to interface");
}
return s;
}
static uint32_t checksum(void *buffer, unsigned int count, uint32_t startsum)
{
uint16_t *up = (uint16_t *)buffer;
uint32_t sum = startsum;
uint32_t upper16;
while (count > 1) {
sum += *up++;
count -= 2;
}
if (count > 0) {
sum += (uint16_t) *(uint8_t *)up;
}
while ((upper16 = (sum >> 16)) != 0) {
sum = (sum & 0xffff) + upper16;
}
return sum;
}
static uint32_t finish_sum(uint32_t sum)
{
return ~sum & 0xffff;
}
int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport)
{
struct iphdr ip;
struct udphdr udp;
struct iovec iov[3];
uint32_t udpsum;
uint16_t temp;
struct msghdr msghdr;
struct sockaddr_ll destaddr;
ip.version = IPVERSION;
ip.ihl = sizeof(ip) >> 2;
ip.tos = 0;
ip.tot_len = htons(sizeof(ip) + sizeof(udp) + size);
ip.id = 0;
ip.frag_off = 0;
ip.ttl = IPDEFTTL;
ip.protocol = IPPROTO_UDP;
ip.check = 0;
ip.saddr = saddr;
ip.daddr = daddr;
ip.check = finish_sum(checksum(&ip, sizeof(ip), 0));
udp.source = htons(sport);
udp.dest = htons(dport);
udp.len = htons(sizeof(udp) + size);
udp.check = 0;
/* Calculate checksum for pseudo header */
udpsum = checksum(&ip.saddr, sizeof(ip.saddr), 0);
udpsum = checksum(&ip.daddr, sizeof(ip.daddr), udpsum);
temp = htons(IPPROTO_UDP);
udpsum = checksum(&temp, sizeof(temp), udpsum);
temp = udp.len;
udpsum = checksum(&temp, sizeof(temp), udpsum);
/* Add in the checksum for the udp header */
udpsum = checksum(&udp, sizeof(udp), udpsum);
/* Add in the checksum for the data */
udpsum = checksum(msg, size, udpsum);
udp.check = finish_sum(udpsum);
iov[0].iov_base = (char *)&ip;
iov[0].iov_len = sizeof(ip);
iov[1].iov_base = (char *)&udp;
iov[1].iov_len = sizeof(udp);
iov[2].iov_base = (char *)msg;
iov[2].iov_len = size;
memset(&destaddr, 0, sizeof(destaddr));
destaddr.sll_family = AF_PACKET;
destaddr.sll_protocol = htons(ETH_P_IP);
destaddr.sll_ifindex = if_index;
destaddr.sll_halen = ETH_ALEN;
memcpy(destaddr.sll_addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN);
msghdr.msg_name = &destaddr;
msghdr.msg_namelen = sizeof(destaddr);
msghdr.msg_iov = iov;
msghdr.msg_iovlen = sizeof(iov) / sizeof(struct iovec);
msghdr.msg_flags = 0;
msghdr.msg_control = 0;
msghdr.msg_controllen = 0;
return sendmsg(s, &msghdr, 0);
}
int receive_packet(int s, struct dhcp_msg *msg)
{
int nread;
int is_valid;
struct dhcp_packet {
struct iphdr ip;
struct udphdr udp;
struct dhcp_msg dhcp;
} packet;
int dhcp_size;
uint32_t sum;
uint16_t temp;
uint32_t saddr, daddr;
nread = read(s, &packet, sizeof(packet));
if (nread < 0) {
return -1;
}
/*
* The raw packet interface gives us all packets received by the
* network interface. We need to filter out all packets that are
* not meant for us.
*/
is_valid = 0;
if (nread < (int)(sizeof(struct iphdr) + sizeof(struct udphdr))) {
#if VERBOSE
LOGD("Packet is too small (%d) to be a UDP datagram", nread);
#endif
} else if (packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2)) {
#if VERBOSE
LOGD("Not a valid IP packet");
#endif
} else if (nread < ntohs(packet.ip.tot_len)) {
#if VERBOSE
LOGD("Packet was truncated (read %d, needed %d)", nread, ntohs(packet.ip.tot_len));
#endif
} else if (packet.ip.protocol != IPPROTO_UDP) {
#if VERBOSE
LOGD("IP protocol (%d) is not UDP", packet.ip.protocol);
#endif
} else if (packet.udp.dest != htons(PORT_BOOTP_CLIENT)) {
#if VERBOSE
LOGD("UDP dest port (%d) is not DHCP client", ntohs(packet.udp.dest));
#endif
} else {
is_valid = 1;
}
if (!is_valid) {
return -1;
}
/* Seems like it's probably a valid DHCP packet */
/* validate IP header checksum */
sum = finish_sum(checksum(&packet.ip, sizeof(packet.ip), 0));
if (sum != 0) {
LOGW("IP header checksum failure (0x%x)", packet.ip.check);
return -1;
}
/*
* Validate the UDP checksum.
* Since we don't need the IP header anymore, we "borrow" it
* to construct the pseudo header used in the checksum calculation.
*/
dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
saddr = packet.ip.saddr;
daddr = packet.ip.daddr;
nread = ntohs(packet.ip.tot_len);
memset(&packet.ip, 0, sizeof(packet.ip));
packet.ip.saddr = saddr;
packet.ip.daddr = daddr;
packet.ip.protocol = IPPROTO_UDP;
packet.ip.tot_len = packet.udp.len;
temp = packet.udp.check;
packet.udp.check = 0;
sum = finish_sum(checksum(&packet, nread, 0));
packet.udp.check = temp;
if (temp != sum) {
LOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
return -1;
}
memcpy(msg, &packet.dhcp, dhcp_size);
return dhcp_size;
}
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _WIFI_PACKET_H_
#define _WIFI_PACKET_H_
int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index);
int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport);
int receive_packet(int s, struct dhcp_msg *msg);
#endif