/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
state->fail.s_addr = 0;
for(;;) {
bytes = get_raw_packet(iface, ETHERTYPE_ARP,
- arp_buffer, sizeof(arp_buffer));
+ arp_buffer, sizeof(arp_buffer), NULL);
if (bytes == 0 || bytes == -1)
return;
/* We must have a full ARP header */
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* So we pass the buffer in the API so we can loop on >1 packet. */
ssize_t
get_raw_packet(struct interface *iface, int protocol,
- void *data, ssize_t len)
+ void *data, ssize_t len, int *partialcsum)
{
int fd = -1;
struct bpf_hdr packet;
else
fd = iface->raw_fd;
+ if (partialcsum != NULL)
+ *partialcsum = 0; /* Not supported on BSD */
+
for (;;) {
if (iface->buffer_len == 0) {
bytes = read(fd, iface->buffer, iface->buffer_size);
const uint8_t *pp;
ssize_t bytes;
struct in_addr from;
- int i;
+ int i, partialcsum = 0;
/* We loop through until our buffer is empty.
* The benefit is that if we get >1 DHCP packet in our buffer and
packet = xmalloc(udp_dhcp_len);
for(;;) {
bytes = get_raw_packet(iface, ETHERTYPE_IP,
- packet, udp_dhcp_len);
+ packet, udp_dhcp_len, &partialcsum);
if (bytes == 0 || bytes == -1)
break;
- if (valid_udp_packet(packet, bytes, &from) == -1) {
+ if (valid_udp_packet(packet, bytes, &from, partialcsum) == -1) {
syslog(LOG_ERR, "%s: invalid UDP packet from %s",
iface->name, inet_ntoa(from));
continue;
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#ifdef __linux__
# include <asm/types.h> /* needed for 2.4 kernels for the below header */
# include <linux/filter.h>
-# include <netpacket/packet.h>
+# include <linux/if_packet.h>
# define bpf_insn sock_filter
# define BPF_SKIPTYPE
# define BPF_ETHCOOK -ETH_HLEN
} su;
struct sock_fprog pf;
int *fd;
+#ifdef PACKET_AUXDATA
+ int n;
+#endif
if ((s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol))) == -1)
return -1;
}
if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)) != 0)
goto eexit;
+#ifdef PACKET_AUXDATA
+ n = 1;
+ if (setsockopt(s, SOL_PACKET, PACKET_AUXDATA, &n, sizeof(n)) != 0) {
+ if (errno != ENOPROTOOPT)
+ goto eexit;
+ }
+#endif
if (set_cloexec(s) == -1)
goto eexit;
if (set_nonblock(s) == -1)
}
ssize_t
-get_raw_packet(struct interface *iface, int protocol, void *data, ssize_t len)
+get_raw_packet(struct interface *iface, int protocol,
+ void *data, ssize_t len, int *partialcsum)
{
+ struct iovec iov = {
+ .iov_base = data,
+ .iov_len = len,
+ };
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+#ifdef PACKET_AUXDATA
+ unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
+ struct cmsghdr *cmsg;
+ struct tpacket_auxdata *aux;
+#endif
+
ssize_t bytes;
int fd = -1;
+#ifdef PACKET_AUXDATA
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof(cmsgbuf);
+#endif
+
if (protocol == ETHERTYPE_ARP)
fd = iface->arp_fd;
else
fd = iface->raw_fd;
- bytes = read(fd, data, len);
+ bytes = recvmsg(fd, &msg, 0);
if (bytes == -1)
return errno == EAGAIN ? 0 : -1;
+ if (partialcsum != NULL) {
+ *partialcsum = 0;
+#ifdef PACKET_AUXDATA
+ for (cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level == SOL_PACKET &&
+ cmsg->cmsg_type == PACKET_AUXDATA) {
+ aux = (void *)CMSG_DATA(cmsg);
+ *partialcsum = aux->tp_status &
+ TP_STATUS_CSUMNOTREADY;
+ }
+ }
+#endif
+ }
return bytes;
}
/*
* dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
}
int
-valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from)
+valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
+ int noudpcsum)
{
struct udp_dhcp_packet packet;
uint16_t bytes, udpsum;
errno = EINVAL;
return -1;
}
- udpsum = packet.udp.uh_sum;
- packet.udp.uh_sum = 0;
- packet.ip.ip_hl = 0;
- packet.ip.ip_v = 0;
- packet.ip.ip_tos = 0;
- packet.ip.ip_len = packet.udp.uh_ulen;
- packet.ip.ip_id = 0;
- packet.ip.ip_off = 0;
- packet.ip.ip_ttl = 0;
- packet.ip.ip_sum = 0;
- if (udpsum && checksum(&packet, bytes) != udpsum) {
- errno = EINVAL;
- return -1;
+
+ if (noudpcsum == 0) {
+ udpsum = packet.udp.uh_sum;
+ packet.udp.uh_sum = 0;
+ packet.ip.ip_hl = 0;
+ packet.ip.ip_v = 0;
+ packet.ip.ip_tos = 0;
+ packet.ip.ip_len = packet.udp.uh_ulen;
+ packet.ip.ip_id = 0;
+ packet.ip.ip_off = 0;
+ packet.ip.ip_ttl = 0;
+ packet.ip.ip_sum = 0;
+ if (udpsum && checksum(&packet, bytes) != udpsum) {
+ errno = EINVAL;
+ return -1;
+ }
}
return 0;
ssize_t make_udp_packet(uint8_t **, const uint8_t *, size_t,
struct in_addr, struct in_addr);
ssize_t get_udp_data(const uint8_t **, const uint8_t *);
-int valid_udp_packet(const uint8_t *, size_t, struct in_addr *);
+int valid_udp_packet(const uint8_t *, size_t, struct in_addr *, int noudpcsum);
int open_socket(struct interface *, int);
ssize_t send_packet(const struct interface *, struct in_addr,
const uint8_t *, ssize_t);
ssize_t send_raw_packet(const struct interface *, int,
const void *, ssize_t);
-ssize_t get_raw_packet(struct interface *, int, void *, ssize_t);
+ssize_t get_raw_packet(struct interface *, int, void *, ssize_t, int *);
int init_sockets(void);
int open_link_socket(void);