From: Roy Marples Date: Fri, 19 Jun 2015 14:01:25 +0000 (+0000) Subject: Move ARP state out of DHCP. X-Git-Tag: v6.9.1~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba251d82a54fbc81f700bbc55ae28c1a190a622d;p=thirdparty%2Fdhcpcd.git Move ARP state out of DHCP. --- diff --git a/arp.c b/arp.c index 46b6789d..70dd324a 100644 --- a/arp.c +++ b/arp.c @@ -122,12 +122,12 @@ arp_packet(void *arg) struct arphdr ar; struct arp_msg arm; ssize_t bytes; - struct dhcp_state *state; + struct iarp_state *state; struct arp_state *astate, *astaten; unsigned char *hw_s, *hw_t; int flags; - state = D_STATE(ifp); + state = ARP_STATE(ifp); flags = 0; while (!(flags & RAW_EOF)) { bytes = if_readrawpacket(ifp, ETHERTYPE_ARP, @@ -186,17 +186,17 @@ arp_packet(void *arg) static void arp_open(struct interface *ifp) { - struct dhcp_state *state; + struct iarp_state *state; - state = D_STATE(ifp); - if (state->arp_fd == -1) { - state->arp_fd = if_openrawsocket(ifp, ETHERTYPE_ARP); - if (state->arp_fd == -1) { + state = ARP_STATE(ifp); + if (state->fd == -1) { + state->fd = if_openrawsocket(ifp, ETHERTYPE_ARP); + if (state->fd == -1) { logger(ifp->ctx, LOG_ERR, "%s: %s: %m", __func__, ifp->name); return; } - eloop_event_add(ifp->ctx->eloop, state->arp_fd, + eloop_event_add(ifp->ctx->eloop, state->fd, arp_packet, ifp, NULL, NULL); } } @@ -297,10 +297,10 @@ arp_probe(struct arp_state *astate) struct arp_state * arp_find(struct interface *ifp, const struct in_addr *addr) { + struct iarp_state *state; struct arp_state *astate; - struct dhcp_state *state; - if ((state = D_STATE(ifp)) == NULL) + if ((state = ARP_STATE(ifp)) == NULL) goto out; TAILQ_FOREACH(astate, &state->arp_states, next) { if (astate->addr.s_addr == addr->s_addr && astate->iface == ifp) @@ -314,20 +314,31 @@ out: struct arp_state * arp_new(struct interface *ifp, const struct in_addr *addr) { + struct iarp_state *state; struct arp_state *astate; - struct dhcp_state *state; - if (addr && (astate = arp_find(ifp, addr))) - return astate; + if ((state = ARP_STATE(ifp)) == NULL) { + ifp->if_data[IF_DATA_ARP] = malloc(sizeof(*state)); + state = ARP_STATE(ifp); + if (state == NULL) { + logger(ifp->ctx, LOG_ERR, "%s: %m", __func__); + return NULL; + } + state->fd = -1; + TAILQ_INIT(&state->arp_states); + } else { + if (addr && (astate = arp_find(ifp, addr))) + return astate; + } if ((astate = calloc(1, sizeof(*astate))) == NULL) { logger(ifp->ctx, LOG_ERR, "%s: %s: %m", ifp->name, __func__); return NULL; } - state = D_STATE(ifp); astate->iface = ifp; if (addr) astate->addr = *addr; + state = ARP_STATE(ifp); TAILQ_INSERT_TAIL(&state->arp_states, astate, next); return astate; } @@ -342,21 +353,25 @@ arp_cancel(struct arp_state *astate) void arp_free(struct arp_state *astate) { - struct dhcp_state *state; - if (astate) { - eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate); - state = D_STATE(astate->iface); + if (astate != NULL) { + struct interface *ifp; + struct iarp_state *state; + + ifp = astate->iface; + eloop_timeout_delete(ifp->ctx->eloop, NULL, astate); + state = ARP_STATE(ifp); TAILQ_REMOVE(&state->arp_states, astate, next); free(astate); /* If there are no more ARP states, close the socket. */ - if (state->arp_fd != -1 && + if (state->fd != -1 && TAILQ_FIRST(&state->arp_states) == NULL) { - eloop_event_delete(ifp->ctx->eloop, state->arp_fd); - close(state->arp_fd); - state->arp_fd = -1; + eloop_event_delete(ifp->ctx->eloop, state->fd); + close(state->fd); + free(state); + ifp->if_data[IF_DATA_ARP] = NULL; } } } @@ -364,10 +379,10 @@ arp_free(struct arp_state *astate) void arp_free_but(struct arp_state *astate) { + struct iarp_state *state; struct arp_state *p, *n; - struct dhcp_state *state; - state = D_STATE(astate->iface); + state = ARP_STATE(astate->iface); TAILQ_FOREACH_SAFE(p, &state->arp_states, next, n) { if (p != astate) arp_free(p); @@ -377,24 +392,16 @@ arp_free_but(struct arp_state *astate) void arp_close(struct interface *ifp) { - struct dhcp_state *state = D_STATE(ifp); + struct iarp_state *state; struct arp_state *astate; - if (state == NULL) - return; - - if (state->arp_fd != -1) { - eloop_event_delete(ifp->ctx->eloop, state->arp_fd); - close(state->arp_fd); - state->arp_fd = -1; - } - - while ((astate = TAILQ_FIRST(&state->arp_states))) { -#ifndef __clang_analyzer__ - /* clang guard needed for a more compex variant on this bug: - * http://llvm.org/bugs/show_bug.cgi?id=18222 */ + /* Freeing the last state will also free the main state, + * so test for both. */ + for (;;) { + if ((state = ARP_STATE(ifp)) == NULL || + (astate = TAILQ_FIRST(&state->arp_states)) == NULL) + break; arp_free(astate); -#endif } } @@ -403,10 +410,10 @@ arp_handleifa(int cmd, struct interface *ifp, const struct in_addr *addr, int flags) { #ifdef IN_IFF_DUPLICATED - struct dhcp_state *state = D_STATE(ifp); + struct iarp_state *state; struct arp_state *astate, *asn; - if (cmd != RTM_NEWADDR || (state = D_STATE(ifp)) == NULL) + if (cmd != RTM_NEWADDR || (state = ARP_STATE(ifp)) == NULL) return; TAILQ_FOREACH_SAFE(astate, &state->arp_states, next, asn) { diff --git a/arp.h b/arp.h index 5e513b29..ce0e91fd 100644 --- a/arp.h +++ b/arp.h @@ -65,6 +65,16 @@ struct arp_state { }; TAILQ_HEAD(arp_statehead, arp_state); +struct iarp_state { + int fd; + struct arp_statehead arp_states; +}; + +#define ARP_STATE(ifp) \ + ((struct iarp_state *)(ifp)->if_data[IF_DATA_ARP]) +#define ARP_CSTATE(ifp) \ + ((const struct iarp_state *)(ifp)->if_data[IF_DATA_ARP]) + #ifdef INET void arp_report_conflicted(const struct arp_state *, const struct arp_msg *); void arp_announce(struct arp_state *); diff --git a/dhcp.c b/dhcp.c index f3c5610d..04c02998 100644 --- a/dhcp.c +++ b/dhcp.c @@ -3023,8 +3023,7 @@ dhcp_dump(struct interface *ifp) ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state)); if (state == NULL) goto eexit; - state->raw_fd = state->arp_fd = -1; - TAILQ_INIT(&state->arp_states); + state->raw_fd = -1; dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile), AF_INET, ifp); state->new = read_lease(ifp); @@ -3097,8 +3096,7 @@ dhcp_init(struct interface *ifp) if (state == NULL) return -1; /* 0 is a valid fd, so init to -1 */ - state->raw_fd = state->arp_fd = -1; - TAILQ_INIT(&state->arp_states); + state->raw_fd = -1; /* Now is a good time to find IPv4 routes */ if_initrt(ifp); diff --git a/dhcp.h b/dhcp.h index 1ac6fa1a..cd5c12ac 100644 --- a/dhcp.h +++ b/dhcp.h @@ -213,7 +213,6 @@ struct dhcp_state { int socket; int raw_fd; - int arp_fd; size_t buffer_size, buffer_len, buffer_pos; unsigned char *buffer; @@ -224,12 +223,8 @@ struct dhcp_state { char leasefile[sizeof(LEASEFILE) + IF_NAMESIZE + (IF_SSIDSIZE * 4)]; time_t start_uptime; - unsigned char *clientid; - struct authstate auth; - struct arp_statehead arp_states; - size_t arping_index; }; diff --git a/dhcpcd.h b/dhcpcd.h index f79c01d3..31b6959e 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -50,12 +50,13 @@ #define LINK_DOWN -1 #define IF_DATA_IPV4 0 -#define IF_DATA_IPV4LL 1 -#define IF_DATA_DHCP 2 -#define IF_DATA_IPV6 3 -#define IF_DATA_IPV6ND 4 -#define IF_DATA_DHCP6 5 -#define IF_DATA_MAX 6 +#define IF_DATA_ARP 1 +#define IF_DATA_IPV4LL 2 +#define IF_DATA_DHCP 3 +#define IF_DATA_IPV6 4 +#define IF_DATA_IPV6ND 5 +#define IF_DATA_DHCP6 6 +#define IF_DATA_MAX 7 /* If the interface does not support carrier status (ie PPP), * dhcpcd can poll it for the relevant flags periodically */ diff --git a/if-bsd.c b/if-bsd.c index b6df0b43..e82cd1db 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -381,7 +381,6 @@ if_sendrawpacket(const struct interface *ifp, uint16_t protocol, struct iovec iov[2]; struct ether_header hw; int fd; - const struct dhcp_state *state; memset(&hw, 0, ETHER_HDR_LEN); memset(&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); @@ -390,11 +389,7 @@ if_sendrawpacket(const struct interface *ifp, uint16_t protocol, iov[0].iov_len = ETHER_HDR_LEN; iov[1].iov_base = UNCONST(data); iov[1].iov_len = len; - state = D_CSTATE(ifp); - if (protocol == ETHERTYPE_ARP) - fd = state->arp_fd; - else - fd = state->raw_fd; + fd = ipv4_protocol_fd(ifp, protocol); return writev(fd, iov, 2); } @@ -411,10 +406,7 @@ if_readrawpacket(struct interface *ifp, uint16_t protocol, struct dhcp_state *state; state = D_STATE(ifp); - if (protocol == ETHERTYPE_ARP) - fd = state->arp_fd; - else - fd = state->raw_fd; + fd = ipv4_protocol_fd(ifp, protocol); *flags = 0; for (;;) { diff --git a/if-linux.c b/if-linux.c index 2acdf040..6c28f8c7 100644 --- a/if-linux.c +++ b/if-linux.c @@ -1197,7 +1197,6 @@ ssize_t if_sendrawpacket(const struct interface *ifp, uint16_t protocol, const void *data, size_t len) { - const struct dhcp_state *state; union sockunion { struct sockaddr sa; struct sockaddr_ll sll; @@ -1216,11 +1215,7 @@ if_sendrawpacket(const struct interface *ifp, uint16_t protocol, &ipv4_bcast_addr, sizeof(ipv4_bcast_addr)); else memset(&su.sll.sll_addr, 0xff, ifp->hwlen); - state = D_CSTATE(ifp); - if (protocol == ETHERTYPE_ARP) - fd = state->arp_fd; - else - fd = state->raw_fd; + fd = ipv4_protocol(ifp, protocol); return sendto(fd, data, len, 0, &su.sa, sizeof(su.sll)); } @@ -1253,10 +1248,7 @@ if_readrawpacket(struct interface *ifp, uint16_t protocol, #endif state = D_STATE(ifp); - if (protocol == ETHERTYPE_ARP) - fd = state->arp_fd; - else - fd = state->raw_fd; + fd = ipv4_protocol(ifp, protocol); bytes = recvmsg(fd, &msg, 0); if (bytes == -1) return -1; diff --git a/ipv4.c b/ipv4.c index 9dc5f1ac..d1d82509 100644 --- a/ipv4.c +++ b/ipv4.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -200,6 +201,23 @@ ipv4_init(struct dhcpcd_ctx *ctx) return 0; } +int +ipv4_protocol_fd(const struct interface *ifp, uint16_t protocol) +{ + + if (protocol == ETHERTYPE_ARP) { + const struct iarp_state *istate; + + istate = ARP_CSTATE(ifp); + return istate->fd; + } else { + const struct dhcp_state *dstate; + + dstate = D_CSTATE(ifp); + return dstate->raw_fd; + } +} + /* Interface comparer for working out ordering. */ int ipv4_ifcmp(const struct interface *si, const struct interface *ti) diff --git a/ipv4.h b/ipv4.h index 9c842230..8453fc28 100644 --- a/ipv4.h +++ b/ipv4.h @@ -88,6 +88,7 @@ struct ipv4_state { #ifdef INET int ipv4_init(struct dhcpcd_ctx *); +int ipv4_protocol_fd(const struct interface *, uint16_t); int ipv4_ifcmp(const struct interface *, const struct interface *); uint8_t inet_ntocidr(struct in_addr); int inet_cidrtoaddr(int, struct in_addr *);