]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Improve get_packet API and memcpy to structure instead of using union pointers.
authorRoy Marples <roy@marples.name>
Thu, 15 May 2008 10:10:39 +0000 (10:10 +0000)
committerRoy Marples <roy@marples.name>
Thu, 15 May 2008 10:10:39 +0000 (10:10 +0000)
bpf.c
client.c
net.c
net.h
socket.c

diff --git a/bpf.c b/bpf.c
index 470ad22c5f9ba16ade7f553b7a581db27ce1fb54..7d42953318ab82107633ec2306ca1e394629b90e 100644 (file)
--- a/bpf.c
+++ b/bpf.c
@@ -53,14 +53,14 @@ open_socket(struct interface *iface, int protocol)
 {
        int fd = -1;
        struct ifreq ifr;
-       int buf = 0;
+       int buf_len = 0;
        struct bpf_version pv;
        struct bpf_program pf;
 #ifdef BIOCIMMEDIATE
        int flags;
 #endif
 #ifdef _PATH_BPF
-       fd = open(_PATH_BPF, O_RDWR);
+       fd = open(_PATH_BPF, O_RDWR | O_NONBLOCK);
 #else
        char *device;
        int n = 0;
@@ -68,7 +68,7 @@ open_socket(struct interface *iface, int protocol)
        device = xmalloc(sizeof(char) * PATH_MAX);
        do {
                snprintf(device, PATH_MAX, "/dev/bpf%d", n++);
-               fd = open(device, O_RDWR);
+               fd = open(device, O_RDWR | O_NONBLOCK);
        } while (fd == -1 && errno == EBUSY);
        free(device);
 #endif
@@ -90,9 +90,11 @@ open_socket(struct interface *iface, int protocol)
                goto eexit;
 
        /* Get the required BPF buffer length from the kernel. */
-       if (ioctl(fd, BIOCGBLEN, &buf) == -1)
+       if (ioctl(fd, BIOCGBLEN, &buf_len) == -1)
                goto eexit;
-       iface->buffer_length = buf;
+       iface->buffer_size = buf_len;
+       iface->buffer = xmalloc(buf_len);
+       iface->buffer_len = iface->buffer_pos = 0;
 
 #ifdef BIOCIMMEDIATE
        flags = 1;
@@ -120,13 +122,15 @@ open_socket(struct interface *iface, int protocol)
        return fd;
 
 eexit:
+       free(iface->buffer);
+       iface->buffer = NULL;
        close(fd);
        return -1;
 }
 
 ssize_t
 send_raw_packet(const struct interface *iface, int type,
-               const unsigned char *data, ssize_t len)
+               const void *data, ssize_t len)
 {
        struct iovec iov[2];
        struct ether_header hw;
@@ -145,66 +149,49 @@ send_raw_packet(const struct interface *iface, int type,
 /* BPF requires that we read the entire buffer.
  * So we pass the buffer in the API so we can loop on >1 dhcp packet. */
 ssize_t
-get_packet(const struct interface *iface, unsigned char *data,
-          unsigned char *buffer, ssize_t *buffer_len, ssize_t *buffer_pos)
+get_packet(struct interface *iface, void *data, ssize_t len)
 {
-       union
-       {
-               unsigned char *buffer;
-               struct bpf_hdr *packet;
-       } bpf;
-       union
-       {
-               unsigned char *buffer;
-               struct ether_header *hw;
-       } hdr;
-       struct timespec ts;
-       ssize_t len;
-       unsigned char *payload;
-       const uint8_t *d;
-
-       bpf.buffer = buffer;
-
-       if (*buffer_pos < 1) {
-               memset(bpf.buffer, 0, iface->buffer_length);
-               *buffer_len = read(iface->fd, bpf.buffer, iface->buffer_length);
-               *buffer_pos = 0;
-               if (*buffer_len < 1) {
-                       ts.tv_sec = 3;
-                       ts.tv_nsec = 0;
-                       nanosleep(&ts, NULL);
-                       return -1;
+       struct bpf_hdr packet;
+       struct ether_header hw;
+       ssize_t cur_len;
+       const unsigned char *payload, *d;
+
+       for (;;) {
+               if (iface->buffer_len == 0) {
+                       cur_len = read(iface->fd, iface->buffer,
+                                      iface->buffer_size);
+                       if (cur_len == -1)
+                               return errno == EAGAIN ? 0 : -1;
+                       else if ((size_t)cur_len < sizeof(packet))
+                               return -1;
+                       iface->buffer_len = cur_len;
                }
-       } else
-               bpf.buffer += *buffer_pos;
-
-       for (; bpf.buffer - buffer < *buffer_len; 
-            bpf.buffer += BPF_WORDALIGN(bpf.packet->bh_hdrlen +
-                                        bpf.packet->bh_caplen),
-            *buffer_pos = bpf.buffer - buffer)
-       {
-               /* Ensure we have the whole packet */
-               if (bpf.packet->bh_caplen != bpf.packet->bh_datalen)
-                       continue;
-
-               hdr.buffer = bpf.buffer + bpf.packet->bh_hdrlen;
-               payload = hdr.buffer + sizeof(*hdr.hw);
-
-               /* If it's an ARP reply, then just send it back */
-               if (hdr.hw->ether_type == htons (ETHERTYPE_ARP)) {
-                       len = bpf.packet->bh_caplen - sizeof(*hdr.hw);
+
+               cur_len = -1;
+
+               memcpy(&packet, iface->buffer + iface->buffer_pos,
+                      sizeof(packet));
+               if (packet.bh_caplen != packet.bh_datalen)
+                       goto next; /* Incomplete packet, drop. */
+               if (iface->buffer_pos + packet.bh_caplen + packet.bh_hdrlen >
+                   iface->buffer_len)
+                       goto next; /* Packet beyond buffer, drop. */
+               memcpy(&hw, iface->buffer + packet.bh_hdrlen, sizeof(hw));
+               payload = iface->buffer + packet.bh_hdrlen + sizeof(hw);
+               if (hw.ether_type == htons(ETHERTYPE_ARP)) {
+                       cur_len = packet.bh_caplen - sizeof(hw);
                        memcpy(data, payload, len);
-                       return len;
-               } else {
-                       if (valid_udp_packet(payload) >= 0) {
-                               len = get_udp_data(&d, payload);
-                               memcpy(data, d, len);
-                               return len;
-                       }
-               }
+               } else if (valid_udp_packet(payload) >= 0) {
+                       cur_len = get_udp_data(&d, payload);
+                       memcpy(data, d, cur_len);
+               } else
+                       cur_len = -1;
+next:
+               iface->buffer_pos += BPF_WORDALIGN(packet.bh_hdrlen +
+                                                  packet.bh_caplen);
+               if (iface->buffer_pos >= iface->buffer_len)
+                       iface->buffer_len = iface->buffer_pos = 0;
+               if (cur_len != -1)
+                       return cur_len;
        }
-
-       /* No valid packets left, so return */
-       *buffer_pos = 0;
-       return -1;
 }
index c3681f49414a79957164b4eca8b2f66ca54c24fb..9639e85c81c1892d51851fa1bb70915ac87bf23e 100644 (file)
--- a/client.c
+++ b/client.c
@@ -105,9 +105,6 @@ struct if_state {
        time_t nakoff;
        uint32_t xid;
        int socket;
-       unsigned char *buffer;
-       ssize_t buffer_len;
-       ssize_t buffer_pos;
        int *pidfd;
 };
 
@@ -1186,24 +1183,19 @@ handle_packet(struct if_state *state, const struct options *options)
        uint8_t *p;
        ssize_t bytes;
 
-       /* Allocate our buffer space for BPF.
-        * We cannot do this until we have opened our socket as we don't
-        * know how much of a buffer we need until then. */
-       if (!state->buffer)
-               state->buffer = xmalloc(iface->buffer_length);
-       state->buffer_len = iface->buffer_length;
-       state->buffer_pos = 0;
-
        /* We loop through until our buffer is empty.
         * The benefit is that if we get >1 DHCP packet in our buffer and
         * the first one fails for any reason, we can use the next. */
 
        dhcp = xmalloc(sizeof(*dhcp));
-       do {
-               bytes = get_packet(iface, (uint8_t *)dhcp, state->buffer,
-                                  &state->buffer_len, &state->buffer_pos);
+       do {    
+               bytes = get_packet(iface, dhcp, sizeof(*dhcp));
                if (bytes == -1)
                        break;
+               if (bytes == 0) {
+                       free(dhcp);
+                       return 0;
+               }
                if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
                        logger(LOG_DEBUG, "bogus cookie, ignoring");
                        continue;
@@ -1226,7 +1218,8 @@ handle_packet(struct if_state *state, const struct options *options)
                }
                if (handle_dhcp(state, &dhcp, options) == 0)
                        return 0;
-       } while (state->buffer_pos != 0);
+       } while (iface->buffer_pos != 0);
+
        free(dhcp);
        return -1;
 }
@@ -1302,7 +1295,6 @@ eexit:
                        retval = 0;
                if (state->options & DHCPCD_DAEMONISED)
                        unlink(options->pidfile);
-               free(state->buffer);
                free(state->dhcp);
                free(state->old_dhcp);
                free(state);
diff --git a/net.c b/net.c
index 9de0bdb9ba93fb862149e44ad8e31ae8d2983754..b79af24322bed041fb1e9d83eeaec0ea8aa0d4c4 100644 (file)
--- a/net.c
+++ b/net.c
@@ -221,7 +221,7 @@ do_interface(const char *ifname,
                len *= 2;
        }
 
-       for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) {
+       for (p = (char *)ifc.ifc_buf; p < (char *)ifc.ifc_buf + ifc.ifc_len;) {
                /* Cast the ifc buffer to an ifreq cleanly */
                ifreqs.buffer = p;
                ifr = ifreqs.ifr;
@@ -468,28 +468,20 @@ struct udp_dhcp_packet
 };
 
 static uint16_t
-checksum(uint8_t *addr, uint16_t len)
+checksum(const void *data, uint16_t len)
 {
+       const uint8_t *addr = data;
        uint32_t sum = 0;
-       union
-       {
-               uint8_t *addr;
-               uint16_t *i;
-       } p;
-       uint16_t nleft = len;
-       uint8_t a = 0;
-
-       p.addr = addr;
-       while (nleft > 1) {
-               sum += *p.i++;
-               nleft -= 2;
-       }
 
-       if (nleft == 1) {
-               memcpy(&a, p.i, 1);
-               sum += ntohs(a) << 8;
+       while (len > 1) {
+               sum += addr[0] + addr[1] * 256;
+               addr += 2;
+               len -= 2;
        }
 
+       if (len == 1)
+               sum += *addr;
+
        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >> 16);
 
@@ -530,7 +522,7 @@ make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
        udp->uh_dport = htons(DHCP_SERVER_PORT);
        udp->uh_ulen = htons(sizeof(*udp) + length);
        ip->ip_len = udp->uh_ulen;
-       udp->uh_sum = checksum((uint8_t *)udpp, sizeof(*udpp));
+       udp->uh_sum = checksum(udpp, sizeof(*udpp));
 
        ip->ip_v = IPVERSION;
        ip->ip_hl = 5;
@@ -541,7 +533,7 @@ make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
        ip->ip_off = htons(IP_DF); /* Don't fragment */
        ip->ip_ttl = IPDEFTTL;
 
-       ip->ip_sum = checksum((uint8_t *)ip, sizeof(*ip));
+       ip->ip_sum = checksum(ip, sizeof(*ip));
 
        *packet = (uint8_t *)udpp;
        return sizeof(*ip) + sizeof(*udp) + length;
@@ -550,27 +542,17 @@ make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
 ssize_t
 get_udp_data(const uint8_t **data, const uint8_t *udp)
 {
-       union
-       {
-               const uint8_t *data;
-               const struct udp_dhcp_packet *packet;
-       } d;
-
-       d.data = udp;
-       *data = (const uint8_t *)&d.packet->dhcp;
-       return ntohs(d.packet->ip.ip_len) -
-               sizeof(d.packet->ip) -
-               sizeof(d.packet->udp);
+       struct udp_dhcp_packet packet;
+
+       memcpy(&packet, udp, sizeof(packet));
+       *data = udp + offsetof(struct udp_dhcp_packet, dhcp);
+       return ntohs(packet.ip.ip_len) - sizeof(packet.ip) - sizeof(packet.udp);
 }
 
 int
-valid_udp_packet(uint8_t *data)
+valid_udp_packet(const uint8_t *data)
 {
-       union
-       {
-               uint8_t *data;
-               struct udp_dhcp_packet *packet;
-       } d;
+       struct udp_dhcp_packet packet;
        uint16_t bytes;
        uint16_t ipsum;
        uint16_t iplen;
@@ -579,39 +561,32 @@ valid_udp_packet(uint8_t *data)
        struct in_addr dest;
        int retval = 0;
 
-       d.data = data;
-       bytes = ntohs(d.packet->ip.ip_len);
-       ipsum = d.packet->ip.ip_sum;
-       iplen = d.packet->ip.ip_len;
-       udpsum = d.packet->udp.uh_sum;
+       memcpy(&packet, data, sizeof(packet));
+       bytes = ntohs(packet.ip.ip_len);
+       ipsum = packet.ip.ip_sum;
+       iplen = packet.ip.ip_len;
+       udpsum = packet.udp.uh_sum;
 
-       d.data = data;
-       d.packet->ip.ip_sum = 0;
-       if (ipsum != checksum((uint8_t *)&d.packet->ip, sizeof(d.packet->ip))) {
+       if (0 != checksum(&packet.ip, sizeof(packet.ip))) {
                errno = EINVAL;
-               retval = -1;
-               goto eexit;
+               return -1;
        }
 
-       memcpy(&source, &d.packet->ip.ip_src, sizeof(d.packet->ip.ip_src));
-       memcpy(&dest, &d.packet->ip.ip_dst, sizeof(d.packet->ip.ip_dst));
-       memset(&d.packet->ip, 0, sizeof(d.packet->ip));
-       d.packet->udp.uh_sum = 0;
-
-       d.packet->ip.ip_p = IPPROTO_UDP;
-       memcpy(&d.packet->ip.ip_src, &source, sizeof(d.packet->ip.ip_src));
-       memcpy(&d.packet->ip.ip_dst, &dest, sizeof(d.packet->ip.ip_dst));
-       d.packet->ip.ip_len = d.packet->udp.uh_ulen;
-       if (udpsum && udpsum != checksum(d.data, bytes)) {
+       packet.ip.ip_sum = 0;
+       memcpy(&source, &packet.ip.ip_src, sizeof(packet.ip.ip_src));
+       memcpy(&dest, &packet.ip.ip_dst, sizeof(packet.ip.ip_dst));
+       memset(&packet.ip, 0, sizeof(packet.ip));
+       packet.udp.uh_sum = 0;
+
+       packet.ip.ip_p = IPPROTO_UDP;
+       memcpy(&packet.ip.ip_src, &source, sizeof(packet.ip.ip_src));
+       memcpy(&packet.ip.ip_dst, &dest, sizeof(packet.ip.ip_dst));
+       packet.ip.ip_len = packet.udp.uh_ulen;
+       if (udpsum && udpsum != checksum(&packet, bytes)) {
                errno = EINVAL;
                retval = -1;
        }
 
-eexit:
-       d.packet->ip.ip_sum = ipsum;
-       d.packet->ip.ip_len = iplen;
-       d.packet->udp.uh_sum = udpsum;
-
        return retval;
 }
 
@@ -622,51 +597,38 @@ eexit:
 #define NCLAIMS                 2
 #define CLAIM_INTERVAL          200
 
-/* Linux does not seem to define these handy macros */
-#ifndef ar_sha
-#define ar_sha(ap) (((caddr_t)((ap) + 1)) + 0)
-#define ar_spa(ap) (((caddr_t)((ap) + 1)) + (ap)->ar_hln)
-#define ar_tha(ap) (((caddr_t)((ap) + 1)) + (ap)->ar_hln + (ap)->ar_pln)
-#define ar_tpa(ap) (((caddr_t)((ap) + 1)) + 2 * (ap)->ar_hln + (ap)->ar_pln)
-#endif
-
-#ifndef arphdr_len
-#define arphdr_len2(ar_hln, ar_pln) (sizeof(struct arphdr) + \
-                                    2 * (ar_hln) + 2 * (ar_pln))
-#define arphdr_len(ap) (arphdr_len2((ap)->ar_hln, (ap)->ar_pln))
-#endif
-
 static int
 send_arp(const struct interface *iface, int op, struct in_addr sip,
         const unsigned char *taddr, struct in_addr tip)
 {
        struct arphdr *arp;
-       size_t arpsize = arphdr_len2(iface->hwlen, sizeof(sip));
-       caddr_t tha;
+       size_t arpsize;
+       unsigned char *p;
        int retval;
 
+       arpsize = sizeof(*arp) + 2 * iface->hwlen + 2 *sizeof(sip);
+
        arp = xzalloc(arpsize);
        arp->ar_hrd = htons(iface->family);
        arp->ar_pro = htons(ETHERTYPE_IP);
        arp->ar_hln = iface->hwlen;
        arp->ar_pln = sizeof(sip);
        arp->ar_op = htons(op);
-       memcpy(ar_sha(arp), iface->hwaddr, (size_t)arp->ar_hln);
-       memcpy(ar_spa(arp), &sip, (size_t)arp->ar_pln);
-       if (taddr) {
-               /* NetBSD can return NULL from ar_tha, which is probably wrong
-                * but we still need to deal with it */
-               if (! (tha = ar_tha(arp))) {
-                       free(arp);
-                       errno = EINVAL;
-                       return -1;
-               }
-               memcpy(tha, taddr, (size_t)arp->ar_hln);
-       }
-       memcpy(ar_tpa(arp), &tip, (size_t)arp->ar_pln);
+       p = (unsigned char *)arp;
+       p += sizeof(*arp);
+       memcpy(p, iface->hwaddr, iface->hwlen);
+       p += iface->hwlen;
+       memcpy(p, &sip, sizeof(sip));
+       p += sizeof(sip);
+
+       if (taddr != NULL)
+               memcpy(p, taddr, iface->hwlen);
+       else
+               memset(p, 0, iface->hwlen);
+       p += iface->hwlen;
+       memcpy(p, &tip, sizeof(tip));
 
-       retval = send_raw_packet(iface, ETHERTYPE_ARP,
-                                (uint8_t *)arp, arphdr_len(arp));
+       retval = send_raw_packet(iface, ETHERTYPE_ARP, arp, arpsize);
        if (retval == -1)
                logger(LOG_ERR,"send_packet: %s", strerror(errno));
        free(arp);
@@ -676,9 +638,11 @@ send_arp(const struct interface *iface, int op, struct in_addr sip,
 int
 arp_claim(struct interface *iface, struct in_addr address)
 {
-       struct arphdr *reply = NULL;
+       struct arphdr reply;
+       uint8_t arp_reply[sizeof(reply) + 2 * 4 /* IPv4 */ + 2 * 8 /* EUI64 */];
+       struct in_addr reply_ipv4;
+       struct ether_addr reply_mac;
        long timeout = 0;
-       unsigned char *buffer;
        int retval = -1;
        int nprobes = 0;
        int nclaims = 0;
@@ -687,20 +651,10 @@ arp_claim(struct interface *iface, struct in_addr address)
                { -1, POLLIN, 0 },
                { -1, POLLIN, 0 }
        };
-       ssize_t bufpos = 0;
-       ssize_t buflen = iface->buffer_length;
        int bytes;
        int s = 0;
        struct timeval stopat;
        struct timeval now;
-       union {
-               unsigned char *c;
-               struct in_addr *a;
-       } rp;
-       union {
-               unsigned char *c;
-               struct ether_addr *a;
-       } rh;
 
        if (!iface->arpable) {
                logger(LOG_DEBUG, "interface `%s' is not ARPable", iface->name);
@@ -721,12 +675,8 @@ arp_claim(struct interface *iface, struct in_addr address)
        fds[0].fd = signal_fd();
        fds[1].fd = iface->fd;
        memset(&null_address, 0, sizeof(null_address));
-       buffer = xmalloc(iface->buffer_length);
-       reply = xmalloc(iface->buffer_length);
 
        for (;;) {
-               bufpos = 0;
-               buflen = iface->buffer_length;
                s = 0;
 
                /* Only poll if we have a timeout */
@@ -797,53 +747,50 @@ arp_claim(struct interface *iface, struct in_addr address)
                if (!(fds[1].revents & POLLIN))
                        continue;
 
-               memset(buffer, 0, buflen);
-               do {
-                       memset(reply, 0, iface->buffer_length);
-                       if ((bytes = get_packet(iface, (unsigned char *) reply,
-                                               buffer,
-                                               &buflen, &bufpos)) == -1)
+               for (;;) {
+                       memset(arp_reply, 0, sizeof(arp_reply));
+                       bytes = get_packet(iface, &arp_reply, sizeof(arp_reply));
+                       if (bytes <= 0)
                                break;
 
+                       memcpy(&reply, arp_reply, sizeof(reply));
                        /* Only these types are recognised */
-                       if (reply->ar_op != htons(ARPOP_REPLY))
+                       if (reply.ar_op != htons(ARPOP_REPLY))
                                continue;
 
                        /* Protocol must be IP. */
-                       if (reply->ar_pro != htons(ETHERTYPE_IP))
+                       if (reply.ar_pro != htons(ETHERTYPE_IP))
                                continue;
-                       if (reply->ar_pln != sizeof(address))
+                       if (reply.ar_pln != sizeof(reply_ipv4))
                                continue;
-                       if ((unsigned)bytes < sizeof(reply) +
-                           2 * (4 +reply->ar_hln))
+                       if ((size_t)bytes < sizeof(reply) + 2 * (4 + reply.ar_hln) ||
+                           reply.ar_hln > 8)
                                continue;
 
-                       rp.c = (unsigned char *)ar_spa(reply);
-                       rh.c = (unsigned char *)ar_sha(reply);
+                       memcpy(&reply_mac, arp_reply + sizeof(reply), reply.ar_hln);
+                       memcpy(&reply_ipv4, arp_reply + sizeof(reply) + reply.ar_hln, reply.ar_hln);
 
                        /* Ensure the ARP reply is for the our address */
-                       if (rp.a->s_addr != address.s_addr)
+                       if (reply_ipv4.s_addr != address.s_addr)
                                continue;
 
                        /* Some systems send a reply back from our hwaddress,
                         * which is wierd */
-                       if (reply->ar_hln == iface->hwlen &&
-                           memcmp(rh.c, iface->hwaddr, iface->hwlen) == 0)
+                       if (reply.ar_hln == iface->hwlen &&
+                           memcmp(&reply_mac, iface->hwaddr, iface->hwlen) == 0)
                                continue;
 
                        logger(LOG_ERR, "ARPOP_REPLY received from %s (%s)",
-                              inet_ntoa(*rp.a),
-                              hwaddr_ntoa(rh.c, (size_t)reply->ar_hln));
+                              inet_ntoa(reply_ipv4),
+                              hwaddr_ntoa((unsigned char *)&reply_mac, (size_t)reply.ar_hln));
                        retval = -1;
                        goto eexit;
-               } while (bufpos != 0);
+               }
        }
 
 eexit:
        close(iface->fd);
        iface->fd = -1;
-       free(buffer);
-       free(reply);
        return retval;
 }
 #endif
diff --git a/net.h b/net.h
index ef968e18fd464f299eb0f6b2f42a84c878fd3ced..8e5d2b3734e91540fe12bb1e964ec2f306a1a397 100644 (file)
--- a/net.h
+++ b/net.h
@@ -105,7 +105,8 @@ struct interface
 
        int fd;
        int udp_fd;
-       size_t buffer_length;
+       size_t buffer_size, buffer_pos, buffer_len;
+       unsigned char *buffer;
 
 #ifdef __linux__
        int socket_protocol;
@@ -160,7 +161,7 @@ int open_udp_socket(struct interface *);
 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(uint8_t *);
+int valid_udp_packet(const uint8_t *);
 
 #ifdef __linux__
 void setup_packet_filters(void);
@@ -169,9 +170,8 @@ 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 uint8_t *, ssize_t);
-ssize_t get_packet(const struct interface *, uint8_t *,
-                  uint8_t *, ssize_t *, ssize_t *);
+                       const void *, ssize_t);
+ssize_t get_packet(struct interface *, void *, ssize_t);
 
 #ifdef ENABLE_ARP
 int arp_claim(struct interface *, struct in_addr);
index 6ae104f2d7a8a8392761438a7dfd46c36cb0f1e9..136a609b9a54efd434680886a873f50161a9a22b 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -91,7 +91,7 @@ setup_packet_filters(void)
 int
 open_socket(struct interface *iface, int protocol)
 {
-       int s;
+       int flags, s;
        union sockunion {
                struct sockaddr sa;
                struct sockaddr_in sin;
@@ -126,13 +126,13 @@ open_socket(struct interface *iface, int protocol)
 
        if (bind(s, &su.sa, sizeof(su)) == -1)
                goto eexit;
-
+       if (close_on_exec(s) == -1)
+               goto eexit;
        if (iface->fd > -1)
                close(iface->fd);
        iface->fd = s;
        iface->socket_protocol = protocol;
-       iface->buffer_length = BUFFER_LENGTH;
-
+       iface->buffer_length = 0;
        return s;
 
 eexit:
@@ -142,7 +142,7 @@ eexit:
 
 ssize_t
 send_raw_packet(const struct interface *iface, int type,
-               const uint8_t *data, ssize_t len)
+               const void *data, ssize_t len)
 {
        union sockunion {
                struct sockaddr sa;
@@ -171,37 +171,26 @@ send_raw_packet(const struct interface *iface, int type,
 /* Linux has no need for the buffer as we can read as much as we want.
  * We only have the buffer listed to keep the same API. */
 ssize_t
-get_packet(const struct interface *iface, uint8_t *data,
-          uint8_t *buffer, ssize_t *buffer_len, ssize_t *buffer_pos)
+get_packet(struct interface *iface, void *data, ssize_t len)
 {
        ssize_t bytes;
        struct timespec ts;
        const uint8_t *p;
 
-       /* We don't use the given buffer, but we need to rewind the position */
-       *buffer_pos = 0;
+       memset(data, 0, len);
+       bytes = read(iface->fd, data, len);
 
-       memset(buffer, 0, iface->buffer_length);
-       bytes = read(iface->fd, buffer, iface->buffer_length);
+       if (bytes == -1)
+               return errno == EGAIN ? 0 : -1;
 
-       if (bytes == -1) {
-               ts.tv_sec = 3;
-               ts.tv_nsec = 0;
-               nanosleep(&ts, NULL);
-               return -1;
-       }
-
-       *buffer_len = bytes;
        /* If it's an ARP reply, then just send it back */
-       if (iface->socket_protocol == ETHERTYPE_ARP) {
-               memcpy(data, buffer, bytes);
+       if (iface->socket_protocol == ETHERTYPE_ARP)
                return bytes;
-       }
 
-       if (valid_udp_packet(buffer) != 0)
+       if (valid_udp_packet(data) != 0)
                return -1;
 
        bytes = get_udp_data(&p, buffer);
-       memcpy(data, p, bytes);
+       memmove(data, p, bytes);
        return bytes;
 }