/*
* DHCP library with GLib integration
*
- * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
+ * Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
+#include <fcntl.h>
#include "gdhcp.h"
#include "common.h"
+#include "../src/connman.h"
static const DHCPOption client_options[] = {
{ OPTION_IP, 0x01 }, /* subnet-mask */
{ OPTION_IP | OPTION_LIST, 0x06 }, /* domain-name-servers */
{ OPTION_STRING, 0x0c }, /* hostname */
{ OPTION_STRING, 0x0f }, /* domain-name */
+ { OPTION_U16, 0x1a }, /* mtu */
{ OPTION_IP | OPTION_LIST, 0x2a }, /* ntp-servers */
{ OPTION_U32, 0x33 }, /* dhcp-lease-time */
/* Options below will not be exposed to user */
break;
if (opt_code == code) {
- if (option_len != NULL)
+ if (option_len)
*option_len = opt_len;
- if (rem == 0)
- found = NULL;
- else
- found = optionptr + 2 + 2;
+ found = optionptr + 2 + 2;
count++;
}
optionptr += len;
}
- if (option_count != NULL)
+ if (option_count)
*option_count = count;
return found;
bad_packet:
- if (option_len != NULL)
+ if (option_len)
*option_len = 0;
- if (option_count != NULL)
+ if (option_count)
*option_count = 0;
return NULL;
}
put_be32(data, option + OPT_DATA);
dhcp_add_binary_option(packet, option);
-
- return;
}
void dhcp_add_option_uint16(struct dhcp_packet *packet, uint8_t code,
put_be16(data, option + OPT_DATA);
dhcp_add_binary_option(packet, option);
-
- return;
}
void dhcp_add_option_uint8(struct dhcp_packet *packet, uint8_t code,
option[OPT_DATA] = data;
dhcp_add_binary_option(packet, option);
-
- return;
}
void dhcp_init_header(struct dhcp_packet *packet, char type)
void dhcpv6_init_header(struct dhcpv6_packet *packet, uint8_t type)
{
int id;
+ uint64_t rand;
memset(packet, 0, sizeof(*packet));
packet->message = type;
- id = random();
+ __connman_util_get_random(&rand);
+ id = rand;
packet->transaction_id[0] = (id >> 16) & 0xff;
packet->transaction_id[1] = (id >> 8) & 0xff;
packet->transaction_id[2] = id & 0xff;
}
-static gboolean check_vendor(uint8_t *option_vendor, const char *vendor)
-{
- uint8_t vendor_length = sizeof(vendor) - 1;
-
- if (option_vendor[OPT_LEN - OPT_DATA] != vendor_length)
- return FALSE;
-
- if (memcmp(option_vendor, vendor, vendor_length) != 0)
- return FALSE;
-
- return TRUE;
-}
-
-static void check_broken_vendor(struct dhcp_packet *packet)
-{
- uint8_t *vendor;
-
- if (packet->op != BOOTREQUEST)
- return;
-
- vendor = dhcp_get_option(packet, DHCP_VENDOR);
- if (vendor == NULL)
- return;
-
- if (check_vendor(vendor, "MSFT 98") == TRUE)
- packet->flags |= htons(BROADCAST_FLAG);
-}
-
int dhcp_recv_l3_packet(struct dhcp_packet *packet, int fd)
{
int n;
if (packet->cookie != htonl(DHCP_MAGIC))
return -EPROTO;
- check_broken_vendor(packet);
-
return n;
}
static const struct in6_addr in6addr_all_dhcp_relay_agents_and_servers_mc =
IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS_MC_INIT;
-/* from netinet/in.h */
-struct in6_pktinfo {
- struct in6_addr ipi6_addr; /* src/dst IPv6 address */
- unsigned int ipi6_ifindex; /* send/recv interface index */
-};
-
int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len)
{
struct msghdr m;
struct iovec v;
struct in6_pktinfo *pktinfo;
struct cmsghdr *cmsg;
- int fd, ret;
+ int fd, ret, opt = 1;
+ struct sockaddr_in6 src;
struct sockaddr_in6 dst;
void *control_buf;
size_t control_buf_len;
if (fd < 0)
return -errno;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
+
+ memset(&src, 0, sizeof(src));
+ src.sin6_family = AF_INET6;
+ src.sin6_port = htons(DHCPV6_CLIENT_PORT);
+
+ if (bind(fd, (struct sockaddr *) &src, sizeof(src)) <0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
+
memset(&dst, 0, sizeof(dst));
dst.sin6_family = AF_INET6;
dst.sin6_port = htons(DHCPV6_SERVER_PORT);
control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
control_buf = g_try_malloc0(control_buf_len);
- if (control_buf == NULL) {
+ if (!control_buf) {
close(fd);
return -ENOMEM;
}
m.msg_controllen = cmsg->cmsg_len;
ret = sendmsg(fd, &m, 0);
- if (ret < 0)
- perror("DHCPv6 msg send failed");
+ if (ret < 0) {
+ char *msg = "DHCPv6 msg send failed";
+
+ if (errno == EADDRNOTAVAIL) {
+ char *str = g_strdup_printf("%s (index %d)",
+ msg, index);
+ perror(str);
+ g_free(str);
+ } else
+ perror(msg);
+ }
g_free(control_buf);
close(fd);
}
int dhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
- uint32_t source_ip, int source_port, uint32_t dest_ip,
- int dest_port, const uint8_t *dest_arp, int ifindex)
+ uint32_t source_ip, int source_port,
+ uint32_t dest_ip, int dest_port,
+ const uint8_t *dest_arp, int ifindex, bool bcast)
{
struct sockaddr_ll dest;
struct ip_udp_dhcp_packet packet;
offsetof(struct ip_udp_dhcp_packet, udp),
};
- fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IP));
+ fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
+ if (bcast)
+ dhcp_pkt->flags |= htons(BROADCAST_FLAG);
+
memset(&dest, 0, sizeof(dest));
memset(&packet, 0, sizeof(packet));
packet.data = *dhcp_pkt;
dest.sll_halen = 6;
memcpy(dest.sll_addr, dest_arp, 6);
if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
+ int err = errno;
close(fd);
- return -errno;
+ return -err;
}
packet.ip.protocol = IPPROTO_UDP;
*/
n = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0,
(struct sockaddr *) &dest, sizeof(dest));
- close(fd);
+ if (n < 0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
- if (n < 0)
- return -errno;
+ close(fd);
return n;
}
int dhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
uint32_t source_ip, int source_port,
- uint32_t dest_ip, int dest_port)
+ uint32_t dest_ip, int dest_port,
+ const char *interface)
{
struct sockaddr_in client;
int fd, n, opt = 1;
if (fd < 0)
return -errno;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
+ interface, strlen(interface) + 1) < 0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(source_port);
client.sin_addr.s_addr = htonl(source_ip);
if (bind(fd, (struct sockaddr *) &client, sizeof(client)) < 0) {
+ int err = errno;
close(fd);
- return -errno;
+ return -err;
}
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(dest_port);
- client.sin_addr.s_addr = dest_ip;
+ client.sin_addr.s_addr = htonl(dest_ip);
if (connect(fd, (struct sockaddr *) &client, sizeof(client)) < 0) {
+ int err = errno;
close(fd);
- return -errno;
+ return -err;
}
n = write(fd, dhcp_pkt, DHCP_SIZE);
+ if (n < 0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
close(fd);
- if (n < 0)
- return -errno;
-
return n;
}
if (fd < 0)
return -errno;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
+ int err = errno;
+ close(fd);
+ return -err;
+ }
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
interface, strlen(interface) + 1) < 0) {
+ int err = errno;
close(fd);
- return -1;
+ return -err;
}
if (family == AF_INET) {
return g_strdup(ifr.ifr_name);
}
-gboolean interface_is_up(int index)
+bool interface_is_up(int index)
{
int sk, err;
struct ifreq ifr;
- gboolean ret = FALSE;
+ bool ret = false;
sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sk < 0) {
perror("Open socket error");
- return FALSE;
+ return false;
}
memset(&ifr, 0, sizeof(ifr));
}
if (ifr.ifr_flags & IFF_UP)
- ret = TRUE;
+ ret = true;
done:
close(sk);