[B.A.T.M.A.N.] [PATCHv2] alfred: support for changing interfaces

Simon Wunderlich
2014-09-03T11:41:30Z

From: Simon Wunderlich <simon@open-mesh.com>

This patch adds support for changing the interface alfreds listens to on
the fly without restarting alfred.

Signed-off-by: Simon Wunderlich <simon@open-mesh.com>

---
Changes to PATCH:
* fix const warning
---
alfred.h | 4 +++-
client.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++
main.c | 66 +++++++++++++++++++++++++++++++++++-------------------------
man/alfred.8 | 3 +++
packet.h | 17 ++++++++++++++++
unix_sock.c | 38 ++++++++++++++++++++++++++++++++++
vis/vis.c | 2 +-
7 files changed, 155 insertions(+), 29 deletions(-)

diff --git a/alfred.h b/alfred.h
index 35ac4dd..c83f7f0 100644
--- a/alfred.h
+++ b/alfred.h
@@ -86,6 +86,7 @@ enum clientmode {
CLIENT_REQUEST_DATA,
CLIENT_SET_DATA,
CLIENT_MODESWITCH,
+ CLIENT_CHANGE_INTERFACE,
};

struct globals {
@@ -93,7 +94,7 @@ struct globals {
struct in6_addr address;
uint32_t scope_id;
struct server *best_server; /* NULL if we are a server ourselves */
- const char *interface;
+ char *interface;
const char *mesh_iface;
enum opmode opmode;
enum clientmode clientmode;
@@ -125,6 +126,7 @@ int set_best_server(struct globals *globals);
int alfred_client_request_data(struct globals *globals);
int alfred_client_set_data(struct globals *globals);
int alfred_client_modeswitch(struct globals *globals);
+int alfred_client_change_interface(struct globals *globals);
/* recv.c */
int recv_alfred_packet(struct globals *globals);
struct transaction_head *
diff --git a/client.c b/client.c
index b868719..48313db 100644
--- a/client.c
+++ b/client.c
@@ -22,6 +22,7 @@
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
+#include <sys/ioctl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -218,3 +219,56 @@ int alfred_client_modeswitch(struct globals *globals)
unix_sock_close(globals);
return 0;
}
+
+int alfred_client_change_interface(struct globals *globals)
+{
+ unsigned char buf[MAX_PAYLOAD];
+ struct alfred_change_interface_v0 *change_interface;
+ struct ifreq ifr;
+ int ret, len;
+ int sock = -1;
+
+ if (unix_sock_open_client(globals))
+ return -1;
+
+ if (strlen(globals->interface) > IFNAMSIZ) {
+ fprintf(stderr, "%s: interface name too long, not changing\n",
+ __func__);
+ return 0;
+ }
+
+ sock = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ perror("can't open socket");
+ return -1;
+ }
+
+ strncpy(ifr.ifr_name, globals->interface, IFNAMSIZ);
+ ifr.ifr_name[IFNAMSIZ - 1] = '\0';
+ if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) {
+ fprintf(stderr, "%s: can't find interface, not changing\n",
+ __func__);
+ close(sock);
+ return -1;
+ }
+
+ close(sock);
+
+ change_interface = (struct alfred_change_interface_v0 *)buf;
+ len = sizeof(*change_interface);
+
+ change_interface->header.type = ALFRED_CHANGE_INTERFACE;
+ change_interface->header.version = ALFRED_VERSION;
+ change_interface->header.length = htons(len - sizeof(change_interface->header));
+ memcpy(change_interface->iface, globals->interface,
+ sizeof(change_interface->iface));
+
+ ret = write(globals->unix_sock, buf, len);
+ if (ret != len)
+ fprintf(stderr, "%s: only wrote %d of %d bytes: %s\n",
+ __func__, ret, len, strerror(errno));
+
+ unix_sock_close(globals);
+
+ return 0;
+}
diff --git a/main.c b/main.c
index 1add44e..5a4f1e6 100644
--- a/main.c
+++ b/main.c
@@ -33,25 +33,29 @@ static void alfred_usage(void)
{
printf("Usage: alfred [options]\n");
printf("client mode options:\n");
- printf(" -s, --set-data [data type] sets new data to distribute from stdin\n");
- printf(" for the supplied data type (0-255)\n");
- printf(" -r, --request [data type] collect data from the network and prints\n");
- printf(" it on the network\n");
- printf(" -V, --req-version specify the data version set for -s\n");
- printf(" -M, --modeswitch master switch daemon to mode master\n");
- printf(" slave switch daemon to mode slave\n");
+ printf(" -s, --set-data [data type] sets new data to distribute from stdin\n");
+ printf(" for the supplied data type (0-255)\n");
+ printf(" -r, --request [data type] collect data from the network and prints\n");
+ printf(" it on the network\n");
+ printf(" -V, --req-version specify the data version set for -s\n");
+ printf(" -M, --modeswitch master switch daemon to mode master\n");
+ printf(" slave switch daemon to mode slave\n");
+ printf(" -I, --change-interface [interface] change to the specified interface\n");
printf("\n");
printf("server mode options:\n");
- printf(" -i, --interface specify the interface to listen on\n");
- printf(" -b specify the batman-adv interface configured on the system (default: bat0)\n");
- printf(" use 'none' to disable the batman-adv based best server selection\n");
- printf(" -m, --master start up the daemon in master mode, which\n");
- printf(" accepts data from slaves and synces it with\n");
- printf(" other masters\n");
+ printf(" -i, --interface specify the interface to listen on\n");
+ printf(" -b specify the batman-adv interface\n");
+ printf(" configured on the system (default: bat0)\n");
+ printf(" use 'none' to disable the batman-adv\n");
+ printf(" based best server selection\n");
+ printf(" -m, --master start up the daemon in master mode, which\n");
+ printf(" accepts data from slaves and synces it with\n");
+ printf(" other masters\n");
printf("\n");
- printf(" -u, --unix-path [path] path to unix socket used for client-server communication (default: \""ALFRED_SOCK_PATH_DEFAULT"\")\n");
- printf(" -v, --version print the version\n");
- printf(" -h, --help this help\n");
+ printf(" -u, --unix-path [path] path to unix socket used for client-server\n");
+ printf(" communication (default: \""ALFRED_SOCK_PATH_DEFAULT"\")\n");
+ printf(" -v, --version print the version\n");
+ printf(" -h, --help this help\n");
printf("\n");
}

@@ -60,16 +64,17 @@ static struct globals *alfred_init(int argc, char *argv[])
int opt, opt_ind, i;
struct globals *globals;
struct option long_options[] = {
- {"set-data", required_argument, NULL, 's'},
- {"request", required_argument, NULL, 'r'},
- {"interface", required_argument, NULL, 'i'},
- {"master", no_argument, NULL, 'm'},
- {"help", no_argument, NULL, 'h'},
- {"req-version", required_argument, NULL, 'V'},
- {"modeswitch", required_argument, NULL, 'M'},
- {"unix-path", required_argument, NULL, 'u'},
- {"version", no_argument, NULL, 'v'},
- {NULL, 0, NULL, 0},
+ {"set-data", required_argument, NULL, 's'},
+ {"request", required_argument, NULL, 'r'},
+ {"interface", required_argument, NULL, 'i'},
+ {"master", no_argument, NULL, 'm'},
+ {"help", no_argument, NULL, 'h'},
+ {"req-version", required_argument, NULL, 'V'},
+ {"modeswitch", required_argument, NULL, 'M'},
+ {"change-interface", required_argument, NULL, 'I'},
+ {"unix-path", required_argument, NULL, 'u'},
+ {"version", no_argument, NULL, 'v'},
+ {NULL, 0, NULL, 0},
};

globals = &alfred_globals;
@@ -85,7 +90,7 @@ static struct globals *alfred_init(int argc, char *argv[])

time_random_seed();

- while ((opt = getopt_long(argc, argv, "ms:r:hi:b:vV:M:u:", long_options,
+ while ((opt = getopt_long(argc, argv, "ms:r:hi:b:vV:M:I:u:", long_options,
&opt_ind)) != -1) {
switch (opt) {
case 'r':
@@ -135,6 +140,10 @@ static struct globals *alfred_init(int argc, char *argv[])
}
globals->clientmode = CLIENT_MODESWITCH;
break;
+ case 'I':
+ globals->clientmode = CLIENT_CHANGE_INTERFACE;
+ globals->interface = strdup(optarg);
+ break;
case 'u':
globals->unix_path = optarg;
break;
@@ -176,6 +185,9 @@ int main(int argc, char *argv[])
case CLIENT_MODESWITCH:
return alfred_client_modeswitch(globals);
break;
+ case CLIENT_CHANGE_INTERFACE:
+ return alfred_client_change_interface(globals);
+ break;
}

return 0;
diff --git a/man/alfred.8 b/man/alfred.8
index c90caa8..35dee45 100644
--- a/man/alfred.8
+++ b/man/alfred.8
@@ -80,6 +80,9 @@ to 0 ('\fB\-V\fP 0').
\fBslave\fP
Switch daemon to mode slave
.fi
+.TP
+\fB\-I\fP, \fB\-\-change\-interface\fP \fIinterface\fP
+Change the alfred server to use the new \fBinterface\fP
.
.SH SERVER OPTIONS
.TP
diff --git a/packet.h b/packet.h
index ba8c5f6..dc06d65 100644
--- a/packet.h
+++ b/packet.h
@@ -20,6 +20,8 @@
#ifndef _ALFRED_PACKET_H
#define _ALFRED_PACKET_H

+#include <net/if.h> /* IFNAMSIZ */
+
#define __packed __attribute__ ((packed))

/* basic blocks */
@@ -67,6 +69,7 @@ struct alfred_transaction_mgmt {
* @ALFRED_STATUS_TXEND: Transaction was finished by sender
* @ALFRED_STATUS_ERROR: Error was detected during the transaction
* @ALFRED_MODESWITCH: Switch between different operation modes
+ * @ALFRED_CHANGE_INTERFACE: Change the listening interface
*/
enum alfred_packet_type {
ALFRED_PUSH_DATA = 0,
@@ -75,6 +78,7 @@ enum alfred_packet_type {
ALFRED_STATUS_TXEND = 3,
ALFRED_STATUS_ERROR = 4,
ALFRED_MODESWITCH = 5,
+ ALFRED_CHANGE_INTERFACE = 6,
};

/* packets */
@@ -143,6 +147,19 @@ struct alfred_modeswitch_v0 {
} __packed;

/**
+ * struct alfred_change_interface_v0 - Request to change the interface
+ * @header: TLV header describing the complete packet
+ * @iface: interface name to be changed to
+ *
+ * Sent to the daemon by client
+ */
+struct alfred_change_interface_v0 {
+ struct alfred_tlv header;
+ char iface[IFNAMSIZ];
+} __packed;
+
+
+/**
* struct alfred_status_v0 - Status info of a transaction
* @header: TLV header describing the complete packet
* @tx: Transaction identificator and sequence number of packet
diff --git a/unix_sock.c b/unix_sock.c
index cc0d25c..516c0a5 100644
--- a/unix_sock.c
+++ b/unix_sock.c
@@ -298,6 +298,38 @@ err:
return ret;
}

+static int
+unix_sock_change_iface(struct globals *globals,
+ struct alfred_change_interface_v0 *change_iface,
+ int client_sock)
+{
+ int len, ret = -1;
+ char *iface;
+
+ len = ntohs(change_iface->header.length);
+
+ if (len < (int)(sizeof(*change_iface) - sizeof(change_iface->header)))
+ goto err;
+
+ iface = malloc(IFNAMSIZ + 1);
+ if (!iface)
+ goto err;
+
+ memcpy(iface, change_iface->iface, IFNAMSIZ);
+ iface[IFNAMSIZ] = 0;
+
+ netsock_close(globals->netsock);
+
+ free(globals->interface);
+ globals->interface = iface;
+ netsock_open(globals);
+
+ ret = 0;
+err:
+ close(client_sock);
+ return ret;
+}
+
int unix_sock_read(struct globals *globals)
{
int client_sock;
@@ -350,6 +382,12 @@ int unix_sock_read(struct globals *globals)
(struct alfred_modeswitch_v0 *)packet,
client_sock);
break;
+ case ALFRED_CHANGE_INTERFACE:
+ ret = unix_sock_change_iface(globals,
+ (struct alfred_change_interface_v0 *)packet,
+ client_sock);
+ break;
+
default:
/* unknown packet type */
ret = -1;
diff --git a/vis/vis.c b/vis/vis.c
index 00372ab..3dd5c8c 100644
--- a/vis/vis.c
+++ b/vis/vis.c
@@ -23,7 +23,7 @@
#include <dirent.h>
#include <errno.h>
#include <getopt.h>
-#include <linux/if.h>
+#include <net/if.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdbool.h>
--
2.1.0