Wire up the netlink socket to the epoll handler. Still need to actually
react to events in the processing function. Pass the client_state structure to the netlink code explicitly rather than making it a global variable.
This commit is contained in:
parent
55bc002ad6
commit
9d03795a15
@ -24,13 +24,22 @@ enum {
|
|||||||
LM_RAW
|
LM_RAW
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IFS_NONE = 0,
|
||||||
|
IFS_UP,
|
||||||
|
IFS_DOWN,
|
||||||
|
IFS_SHUT,
|
||||||
|
IFS_REMOVED
|
||||||
|
};
|
||||||
|
|
||||||
struct client_state_t {
|
struct client_state_t {
|
||||||
unsigned long long leaseStartTime;
|
unsigned long long leaseStartTime;
|
||||||
int dhcpState;
|
int dhcpState;
|
||||||
int arpPrevState;
|
int arpPrevState;
|
||||||
|
int ifsPrevState;
|
||||||
int listenMode;
|
int listenMode;
|
||||||
int packetNum;
|
int packetNum;
|
||||||
int epollFd, signalFd, listenFd, arpFd;
|
int epollFd, signalFd, listenFd, arpFd, nlFd;
|
||||||
int timeout;
|
int timeout;
|
||||||
uint32_t requestedIP, serverAddr;
|
uint32_t requestedIP, serverAddr;
|
||||||
uint32_t lease, t1, t2, xid;
|
uint32_t lease, t1, t2, xid;
|
||||||
|
12
ndhc/ndhc.c
12
ndhc/ndhc.c
@ -33,7 +33,6 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
#include <sys/signalfd.h>
|
#include <sys/signalfd.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
@ -67,6 +66,7 @@
|
|||||||
struct client_state_t cs = {
|
struct client_state_t cs = {
|
||||||
.dhcpState = DS_INIT_SELECTING,
|
.dhcpState = DS_INIT_SELECTING,
|
||||||
.arpPrevState = DS_NULL,
|
.arpPrevState = DS_NULL,
|
||||||
|
.ifsPrevState = IFS_NONE,
|
||||||
.listenMode = LM_NONE,
|
.listenMode = LM_NONE,
|
||||||
.packetNum = 0,
|
.packetNum = 0,
|
||||||
.xid = 0,
|
.xid = 0,
|
||||||
@ -81,6 +81,7 @@ struct client_state_t cs = {
|
|||||||
.signalFd = -1,
|
.signalFd = -1,
|
||||||
.listenFd = -1,
|
.listenFd = -1,
|
||||||
.arpFd = -1,
|
.arpFd = -1,
|
||||||
|
.nlFd = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct client_config_t client_config = {
|
struct client_config_t client_config = {
|
||||||
@ -223,6 +224,7 @@ static void do_work(void)
|
|||||||
if (cs.epollFd == -1)
|
if (cs.epollFd == -1)
|
||||||
suicide("epoll_create1 failed");
|
suicide("epoll_create1 failed");
|
||||||
setup_signals(&cs);
|
setup_signals(&cs);
|
||||||
|
epoll_add(&cs, cs.nlFd);
|
||||||
change_listen_mode(&cs, LM_RAW);
|
change_listen_mode(&cs, LM_RAW);
|
||||||
handle_timeout(&cs);
|
handle_timeout(&cs);
|
||||||
|
|
||||||
@ -243,6 +245,8 @@ static void do_work(void)
|
|||||||
handle_packet(&cs);
|
handle_packet(&cs);
|
||||||
else if (fd == cs.arpFd)
|
else if (fd == cs.arpFd)
|
||||||
handle_arp_response(&cs);
|
handle_arp_response(&cs);
|
||||||
|
else if (fd == cs.nlFd)
|
||||||
|
handle_nl_message(&cs);
|
||||||
else
|
else
|
||||||
suicide("epoll_wait: unknown fd");
|
suicide("epoll_wait: unknown fd");
|
||||||
}
|
}
|
||||||
@ -363,11 +367,11 @@ int main(int argc, char **argv)
|
|||||||
write_pid(pidfile);
|
write_pid(pidfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nl_open() < 0) {
|
if (nl_open(&cs) < 0) {
|
||||||
log_line("FATAL - failed to open netlink socket");
|
log_line("FATAL - failed to open netlink socket");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (nl_getifdata(client_config.interface) < 0) {
|
if (nl_getifdata(client_config.interface, &cs) < 0) {
|
||||||
log_line("FATAL - failed to get interface MAC and index");
|
log_line("FATAL - failed to get interface MAC and index");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -398,6 +402,6 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
do_work();
|
do_work();
|
||||||
|
|
||||||
nl_close();
|
nl_close(&cs);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
111
ndhc/netlink.c
111
ndhc/netlink.c
@ -17,23 +17,17 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "netlink.h"
|
#include "netlink.h"
|
||||||
#include "config.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
// OS_REMOVED -> exit
|
|
||||||
// OS_SHUT -> exit
|
|
||||||
// OS_DOWN -> action
|
|
||||||
// OS_UP -> action
|
|
||||||
|
|
||||||
#define NLMSG_RECVSIZE 8192
|
#define NLMSG_RECVSIZE 8192
|
||||||
|
|
||||||
static int nl_socket = -1;
|
|
||||||
static unsigned int nl_seq;
|
static unsigned int nl_seq;
|
||||||
|
|
||||||
/* internal callback handling */
|
/* internal callback handling */
|
||||||
@ -43,7 +37,8 @@ static __u32 nlcb_pid;
|
|||||||
static unsigned int nlcb_seq;
|
static unsigned int nlcb_seq;
|
||||||
static char nlcb_run;
|
static char nlcb_run;
|
||||||
|
|
||||||
int nl_open() {
|
int nl_open(struct client_state_t *cs)
|
||||||
|
{
|
||||||
struct sockaddr_nl nlsock = {
|
struct sockaddr_nl nlsock = {
|
||||||
.nl_family = AF_NETLINK,
|
.nl_family = AF_NETLINK,
|
||||||
.nl_pad = 0,
|
.nl_pad = 0,
|
||||||
@ -53,37 +48,40 @@ int nl_open() {
|
|||||||
|
|
||||||
nlcb_pid = nlsock.nl_pid;
|
nlcb_pid = nlsock.nl_pid;
|
||||||
|
|
||||||
assert(nl_socket == -1);
|
assert(cs->nlFd == -1);
|
||||||
|
|
||||||
nl_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
cs->nlFd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
|
||||||
|
|
||||||
if (nl_socket == -1) return -1;
|
if (cs->nlFd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (bind(nl_socket, (const struct sockaddr *)&nlsock, sizeof(nlsock)))
|
if (bind(cs->nlFd, (const struct sockaddr *)&nlsock, sizeof(nlsock)))
|
||||||
goto err_close;
|
goto err_close;
|
||||||
|
|
||||||
if (fcntl(nl_socket, F_SETFD, FD_CLOEXEC))
|
if (fcntl(cs->nlFd, F_SETFD, FD_CLOEXEC))
|
||||||
goto err_close;
|
goto err_close;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_close:
|
err_close:
|
||||||
nl_close();
|
nl_close(cs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nl_close() {
|
void nl_close(struct client_state_t *cs)
|
||||||
close(nl_socket);
|
{
|
||||||
nl_socket = -1;
|
close(cs->nlFd);
|
||||||
|
cs->nlFd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nl_queryifstatus(int ifidx) {
|
void nl_queryifstatus(int ifidx, struct client_state_t *cs)
|
||||||
|
{
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr hdr;
|
struct nlmsghdr hdr;
|
||||||
struct ifinfomsg ifinfo;
|
struct ifinfomsg ifinfo;
|
||||||
} req;
|
} req;
|
||||||
|
|
||||||
req.hdr.nlmsg_len = sizeof(req);
|
req.hdr.nlmsg_len = sizeof req;
|
||||||
req.hdr.nlmsg_type = RTM_GETLINK;
|
req.hdr.nlmsg_type = RTM_GETLINK;
|
||||||
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
||||||
req.hdr.nlmsg_seq = ++nl_seq;
|
req.hdr.nlmsg_seq = ++nl_seq;
|
||||||
@ -93,11 +91,13 @@ void nl_queryifstatus(int ifidx) {
|
|||||||
req.ifinfo.ifi_flags = IFF_UP;
|
req.ifinfo.ifi_flags = IFF_UP;
|
||||||
req.ifinfo.ifi_change = 0xffffffff;
|
req.ifinfo.ifi_change = 0xffffffff;
|
||||||
|
|
||||||
send(nl_socket, &req, sizeof(req),0);
|
send(cs->nlFd, &req, sizeof req, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode netlink messages and process them
|
||||||
static void nl_handlemsg(struct nlmsghdr *msg, unsigned int len) {
|
static void nl_handlemsg(struct nlmsghdr *msg, unsigned int len,
|
||||||
|
struct client_state_t *cs)
|
||||||
|
{
|
||||||
if (len < sizeof(*msg)) return;
|
if (len < sizeof(*msg)) return;
|
||||||
|
|
||||||
while(NLMSG_OK(msg,len)) {
|
while(NLMSG_OK(msg,len)) {
|
||||||
@ -118,17 +118,41 @@ static void nl_handlemsg(struct nlmsghdr *msg, unsigned int len) {
|
|||||||
if (ifinfo->ifi_index != client_config.ifindex)
|
if (ifinfo->ifi_index != client_config.ifindex)
|
||||||
break;
|
break;
|
||||||
if (ifinfo->ifi_flags & IFF_UP) {
|
if (ifinfo->ifi_flags & IFF_UP) {
|
||||||
if (ifinfo->ifi_flags & IFF_RUNNING)
|
if (ifinfo->ifi_flags & IFF_RUNNING) {
|
||||||
printf("XXX_OS_UP() NYI\n");
|
if (cs->ifsPrevState != IFS_UP) {
|
||||||
else
|
cs->ifsPrevState = IFS_UP;
|
||||||
printf("XXX_OS_DOWN() NYI\n");
|
/*
|
||||||
} else
|
* If we have a lease, then check to see
|
||||||
printf("XXX_OS_SHUT() NYI\n");
|
* if our gateway is still valid. If it fails,
|
||||||
|
* state -> INIT_REBOOT.
|
||||||
|
*
|
||||||
|
* If we don't have a lease, state -> INIT.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cs->ifsPrevState != IFS_DOWN) {
|
||||||
|
cs->ifsPrevState = IFS_DOWN;
|
||||||
|
/*
|
||||||
|
* state -> DOWN
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cs->ifsPrevState != IFS_SHUT) {
|
||||||
|
cs->ifsPrevState = IFS_SHUT;
|
||||||
|
log_line("Interface shut down; exiting.");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case RTM_DELLINK:
|
case RTM_DELLINK:
|
||||||
if (ifinfo->ifi_index != client_config.ifindex)
|
if (ifinfo->ifi_index != client_config.ifindex)
|
||||||
break;
|
break;
|
||||||
printf("XXX_OS_REMOVED() NYI\n");
|
if (cs->ifsPrevState != IFS_REMOVED) {
|
||||||
|
cs->ifsPrevState = IFS_REMOVED;
|
||||||
|
log_line("Interface removed; exiting.");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -138,21 +162,35 @@ static void nl_handlemsg(struct nlmsghdr *msg, unsigned int len) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nl_sync_dump() {
|
void handle_nl_message(struct client_state_t *cs)
|
||||||
|
{
|
||||||
|
char c[NLMSG_RECVSIZE];
|
||||||
|
struct nlmsghdr *msg = (struct nlmsghdr *)c;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
assert(cs->nlFd != -1);
|
||||||
|
n = recv(cs->nlFd, c, NLMSG_RECVSIZE, 0);
|
||||||
|
nl_handlemsg(msg, n, cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for and synchronously process netlink replies until a callback completes
|
||||||
|
static void nl_sync_dump(struct client_state_t *cs)
|
||||||
|
{
|
||||||
char c[NLMSG_RECVSIZE];
|
char c[NLMSG_RECVSIZE];
|
||||||
struct nlmsghdr *msg = (struct nlmsghdr *)c;
|
struct nlmsghdr *msg = (struct nlmsghdr *)c;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
nlcb_seq = nl_seq;
|
nlcb_seq = nl_seq;
|
||||||
for(nlcb_run = 1; nlcb_run;) {
|
for(nlcb_run = 1; nlcb_run;) {
|
||||||
n = recv(nl_socket, c, NLMSG_RECVSIZE, 0);
|
n = recv(cs->nlFd, c, NLMSG_RECVSIZE, 0);
|
||||||
assert(n >= 0);
|
assert(n >= 0);
|
||||||
nl_handlemsg(msg,n);
|
nl_handlemsg(msg, n, cs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback function for getting interface mac address and index.
|
// Callback function for getting interface mac address and index.
|
||||||
static void copy_ifdata(struct nlmsghdr *msg, void **args) {
|
static void copy_ifdata(struct nlmsghdr *msg, void **args)
|
||||||
|
{
|
||||||
struct ifinfomsg *ifinfo = NLMSG_DATA(msg);
|
struct ifinfomsg *ifinfo = NLMSG_DATA(msg);
|
||||||
struct rtattr *rta = IFLA_RTA(ifinfo);
|
struct rtattr *rta = IFLA_RTA(ifinfo);
|
||||||
int len = NLMSG_PAYLOAD(msg, sizeof(*ifinfo));
|
int len = NLMSG_PAYLOAD(msg, sizeof(*ifinfo));
|
||||||
@ -193,7 +231,8 @@ static void copy_ifdata(struct nlmsghdr *msg, void **args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Gets interface mac address and index (synchronous).
|
// Gets interface mac address and index (synchronous).
|
||||||
int nl_getifdata(const char *ifname) {
|
int nl_getifdata(const char *ifname, struct client_state_t *cs)
|
||||||
|
{
|
||||||
struct {
|
struct {
|
||||||
struct nlmsghdr hdr;
|
struct nlmsghdr hdr;
|
||||||
struct ifinfomsg ifinfo;
|
struct ifinfomsg ifinfo;
|
||||||
@ -206,12 +245,12 @@ int nl_getifdata(const char *ifname) {
|
|||||||
req.hdr.nlmsg_pid = nlcb_pid;
|
req.hdr.nlmsg_pid = nlcb_pid;
|
||||||
req.ifinfo.ifi_family = AF_UNSPEC;
|
req.ifinfo.ifi_family = AF_UNSPEC;
|
||||||
|
|
||||||
if (send(nl_socket, &req, sizeof(req), 0) != sizeof(req)) return -1;
|
if (send(cs->nlFd, &req, sizeof(req), 0) != sizeof(req)) return -1;
|
||||||
|
|
||||||
nlcb_function = copy_ifdata;
|
nlcb_function = copy_ifdata;
|
||||||
nlcb_args[0] = NULL;
|
nlcb_args[0] = NULL;
|
||||||
|
|
||||||
nl_sync_dump();
|
nl_sync_dump(cs);
|
||||||
|
|
||||||
return nlcb_args[0]?0:-1;
|
return nlcb_args[0]?0:-1;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
#ifndef NK_NETLINK_H_
|
#ifndef NK_NETLINK_H_
|
||||||
#define NK_NETLINK_H_
|
#define NK_NETLINK_H_
|
||||||
|
|
||||||
int nl_open();
|
#include "config.h"
|
||||||
void nl_close();
|
|
||||||
void nl_queryifstatus(int ifidx);
|
int nl_open(struct client_state_t *cs);
|
||||||
int nl_getifdata(const char *ifname);
|
void nl_close(struct client_state_t *cs);
|
||||||
|
void nl_queryifstatus(int ifidx, struct client_state_t *cs);
|
||||||
|
void handle_nl_message(struct client_state_t *cs);
|
||||||
|
int nl_getifdata(const char *ifname, struct client_state_t *cs);
|
||||||
|
|
||||||
#endif /* NK_NETLINK_H_ */
|
#endif /* NK_NETLINK_H_ */
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user