@@ -33,6 +33,9 @@
#define FIXED_TLV_LEN(__tlv_type) \
htons(sizeof(__tlv_type) - sizeof(__tlv_type.header))
+#define FIXED_TLV_LEN_PTR(__tlv_type) \
+ htons(sizeof(*__tlv_type) - sizeof(__tlv_type->header))
+
enum data_source {
SOURCE_LOCAL = 0,
SOURCE_FIRST_HAND = 1,
@@ -93,6 +96,7 @@ enum clientmode {
CLIENT_MODESWITCH,
CLIENT_CHANGE_INTERFACE,
CLIENT_CHANGE_BAT_IFACE,
+ CLIENT_SERVER_STATUS,
};
struct interface {
@@ -155,6 +159,7 @@ int alfred_client_set_data(struct globals *globals);
int alfred_client_modeswitch(struct globals *globals);
int alfred_client_change_interface(struct globals *globals);
int alfred_client_change_bat_iface(struct globals *globals);
+int alfred_client_server_status(struct globals *globals);
/* recv.c */
int recv_alfred_packet(struct globals *globals, struct interface *interface,
int recv_sock);
@@ -325,3 +325,123 @@ int alfred_client_change_bat_iface(struct globals *globals)
return 0;
}
+
+int alfred_client_server_status(struct globals *globals)
+{
+ struct alfred_server_status_net_iface_v0 *status_net_iface;
+ struct alfred_server_status_bat_iface_v0 *status_bat_iface;
+ struct alfred_server_status_op_mode_v0 *status_op_mode;
+ struct alfred_server_status_req_v0 status_req;
+ struct alfred_server_status_rep_v0 *status_rep;
+ int ret, tlvsize, headsize, len, consumed;
+ struct alfred_tlv *status_tlv;
+ uint8_t buf[MAX_PAYLOAD];
+
+ if (unix_sock_open_client(globals))
+ return -1;
+
+ len = sizeof(status_req);
+ memset(&status_req, 0, len);
+
+ status_req.header.type = ALFRED_SERVER_STATUS;
+ status_req.header.version = ALFRED_VERSION;
+ status_req.header.length = 0;
+
+ ret = write(globals->unix_sock, (unsigned char *)&status_req, len);
+ if (ret != len)
+ fprintf(stderr, "%s: only wrote %d of %d bytes: %s\n",
+ __func__, ret, len, strerror(errno));
+
+ len = read(globals->unix_sock, buf, sizeof(buf));
+ if (len <= 0) {
+ perror("read from unix socket failed");
+ goto err;
+ }
+
+ ret = -1;
+ status_rep = (struct alfred_server_status_rep_v0 *)buf;
+
+ /* drop too small packets */
+ headsize = sizeof(status_rep->header);
+ if (len < headsize) {
+ perror("unexpected header size received from unix socket");
+ goto err;
+ }
+
+ if ((len - headsize) < ((int)ntohs(status_rep->header.length))) {
+ perror("unexpected packet size received from unix socket");
+ goto err;
+ }
+
+ if (status_rep->header.version != ALFRED_VERSION) {
+ perror("alfred version mismatch");
+ goto err;
+ }
+
+ headsize = ntohs(status_rep->header.length);
+
+ if (headsize < (int)(sizeof(*status_rep) - sizeof(status_rep->header)))
+ goto err;
+
+ consumed = sizeof(*status_rep);
+
+ while (len - consumed > 0) {
+ if (len - consumed < (int)sizeof(*status_tlv))
+ break;
+
+ status_tlv = (struct alfred_tlv *)(buf + consumed);
+
+ if (status_tlv->version != ALFRED_VERSION)
+ break;
+
+ tlvsize = ntohs(status_tlv->length);
+ tlvsize += sizeof(*status_tlv);
+
+ if (len - consumed < tlvsize)
+ break;
+
+ switch (status_tlv->type) {
+ case ALFRED_SERVER_OP_MODE:
+ if (tlvsize != sizeof(*status_op_mode))
+ break;
+
+ status_op_mode = (struct alfred_server_status_op_mode_v0 *)(buf + consumed);
+
+ switch (status_op_mode->mode) {
+ case ALFRED_MODESWITCH_SECONDARY:
+ fprintf(stdout, "- mode: secondary\n");
+ break;
+ case ALFRED_MODESWITCH_PRIMARY:
+ fprintf(stdout, "- mode: primary\n");
+ break;
+ default:
+ fprintf(stderr, "- mode: unknown\n");
+ break;
+ }
+
+ break;
+ case ALFRED_SERVER_NET_IFACE:
+ if (tlvsize != sizeof(*status_net_iface))
+ break;
+
+ status_net_iface = (struct alfred_server_status_net_iface_v0 *)(buf + consumed);
+ fprintf(stdout, "- interface: %s\n", status_net_iface->net_iface);
+ fprintf(stdout, "\t- status: %s\n",
+ status_net_iface->active == 1 ? "active" : "inactive");
+ break;
+ case ALFRED_SERVER_BAT_IFACE:
+ if (tlvsize != sizeof(*status_bat_iface))
+ break;
+
+ status_bat_iface = (struct alfred_server_status_bat_iface_v0 *)(buf + consumed);
+ fprintf(stdout, "- batman-adv interface: %s\n", status_bat_iface->bat_iface);
+ break;
+ }
+
+ consumed += tlvsize;
+ }
+
+err:
+ unix_sock_close(globals);
+ return 0;
+}
@@ -38,6 +38,7 @@ static void alfred_usage(void)
printf(" secondary switch daemon to mode secondary\n");
printf(" -I, --change-interface [interface] change to the specified interface(s)\n");
printf(" -B, --change-bat-iface [interface] change to the specified batman-adv interface\n");
+ printf(" -S, --server-status request server status info such as mode & interfaces\n");
printf("\n");
printf("server mode options:\n");
printf(" -i, --interface specify the interface (or comma separated list of interfaces) to listen on\n");
@@ -162,6 +163,7 @@ static struct globals *alfred_init(int argc, char *argv[])
{"modeswitch", required_argument, NULL, 'M'},
{"change-interface", required_argument, NULL, 'I'},
{"change-bat-iface", required_argument, NULL, 'B'},
+ {"server-status", required_argument, NULL, 'S'},
{"unix-path", required_argument, NULL, 'u'},
{"update-command", required_argument, NULL, 'c'},
{"version", no_argument, NULL, 'v'},
@@ -196,7 +198,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:I:B:u:dc:p:4:f", long_options,
+ while ((opt = getopt_long(argc, argv, "ms:r:hi:b:vV:M:I:B:Su:dc:p:4:f", long_options,
&opt_ind)) != -1) {
switch (opt) {
case 'r':
@@ -258,6 +260,9 @@ static struct globals *alfred_init(int argc, char *argv[])
globals->clientmode = CLIENT_CHANGE_BAT_IFACE;
globals->mesh_iface = strdup(optarg);
break;
+ case 'S':
+ globals->clientmode = CLIENT_SERVER_STATUS;
+ break;
case 'u':
globals->unix_path = optarg;
break;
@@ -321,6 +326,8 @@ int main(int argc, char *argv[])
return alfred_client_change_interface(globals);
case CLIENT_CHANGE_BAT_IFACE:
return alfred_client_change_bat_iface(globals);
+ case CLIENT_SERVER_STATUS:
+ return alfred_client_server_status(globals);
}
return 0;
@@ -94,6 +94,9 @@ Change the alfred server to use the new \fBinterface\fP(s)
.TP
\fB\-B\fP, \fB\-\-change\-bat\-iface\fP \fIinterface\fP
Change the alfred server to use the new \fBbatman-adv interface\fP
+.TP
+\fB\-S\fP, \fB\-\-server\-status\fP
+Request server status information such as mode & interfaces\fP
.
.SH SERVER OPTIONS
.TP
@@ -69,6 +69,7 @@ enum alfred_packet_type {
ALFRED_MODESWITCH = 5,
ALFRED_CHANGE_INTERFACE = 6,
ALFRED_CHANGE_BAT_IFACE = 7,
+ ALFRED_SERVER_STATUS = 8,
};
/* packets */
@@ -159,6 +160,73 @@ struct alfred_change_interface_v0 {
struct alfred_change_bat_iface_v0 {
struct alfred_tlv header;
char bat_iface[IFNAMSIZ];
+};
+
+/**
+ * enum alfred_packet_type - Types of packet stored in the main alfred_tlv
+ * @ALFRED_SERVER_MODE: Contains alfred mode information*
+ * @ALFRED_SERVER_NET_IFACE: Contains alfred network interface information*
+ * @ALFRED_SERVER_BAT_IFACE: Contains alfred batman interface information*
+ */
+enum alfred_server_status_type {
+ ALFRED_SERVER_OP_MODE = 0,
+ ALFRED_SERVER_NET_IFACE = 1,
+ ALFRED_SERVER_BAT_IFACE = 2,
+};
+
+/**
+ * struct alfred_server_status_req_v0 - server status request
+ * @header: TLV header describing the complete packet
+ *
+ * Sent to the daemon by client
+ */
+struct alfred_server_status_req_v0 {
+ struct alfred_tlv header;
+} __packed;
+
+/**
+ * struct alfred_server_status_op_mode_v0 - server op mode status information
+ * @op_mode: active op mode
+ *
+ * Sent to the client by daemon in response to status request
+ */
+struct alfred_server_status_op_mode_v0 {
+ struct alfred_tlv header;
+ uint8_t mode;
+} __packed;
+
+/**
+ * struct alfred_server_status_net_iface_v0 - server net iface status information
+ * @net_iface: configured network interface
+ * @active: network interface active/inactive status info
+ *
+ * Sent to the client by daemon in response to status request
+ */
+struct alfred_server_status_net_iface_v0 {
+ struct alfred_tlv header;
+ char net_iface[IFNAMSIZ];
+ uint8_t active;
+} __packed;
+
+/**
+ * struct alfred_server_status_bat_iface_v0 - server bat iface status information
+ * @op_mode: configured batman interface
+ *
+ * Sent to the client by daemon in response to status request
+ */
+struct alfred_server_status_bat_iface_v0 {
+ struct alfred_tlv header;
+ char bat_iface[IFNAMSIZ];
+} __packed;
+
+/**
+ * struct alfred_server_status_rep_v0 - server status reply
+ * @header: TLV header describing the complete packet
+ *
+ * Sent by the daemon to client in response to status request
+ */
+struct alfred_server_status_rep_v0 {
+ struct alfred_tlv header;
} __packed;
/**
@@ -366,6 +366,109 @@ err:
return ret;
}
+static int unix_sock_server_status(struct globals *globals, int client_sock)
+{
+ struct alfred_server_status_net_iface_v0 *status_net_iface;
+ struct alfred_server_status_bat_iface_v0 *status_bat_iface;
+ struct alfred_server_status_op_mode_v0 *status_op_mode;
+ struct alfred_server_status_rep_v0 *status_rep;
+ struct interface *interface;
+ uint8_t buf[MAX_PAYLOAD];
+ int ret = -1;
+ int len = 0;
+
+ /* too large? - should never happen */
+ if (sizeof(*status_rep) + len > sizeof(buf)) {
+ fprintf(stderr, "ERROR: send buffer too small for server_status\n");
+ goto err;
+ }
+
+ status_rep = (struct alfred_server_status_rep_v0 *)buf;
+ status_rep->header.type = ALFRED_SERVER_STATUS;
+ status_rep->header.version = ALFRED_VERSION;
+
+ len += sizeof(*status_rep);
+
+ /* too large? - should never happen */
+ if (sizeof(*status_op_mode) + len > sizeof(buf)) {
+ fprintf(stderr, "ERROR: send buffer too small for server_status op_mode\n");
+ goto err;
+ }
+
+ status_op_mode = (struct alfred_server_status_op_mode_v0 *)(buf + len);
+ status_op_mode->header.type = ALFRED_SERVER_OP_MODE;
+ status_op_mode->header.version = ALFRED_VERSION;
+ status_op_mode->header.length = FIXED_TLV_LEN_PTR(status_op_mode);
+
+ switch (globals->opmode) {
+ case OPMODE_SECONDARY:
+ status_op_mode->mode = ALFRED_MODESWITCH_SECONDARY;
+ break;
+ case OPMODE_PRIMARY:
+ status_op_mode->mode = ALFRED_MODESWITCH_PRIMARY;
+ break;
+ default:
+ break;
+ }
+
+ len += sizeof(*status_op_mode);
+
+ list_for_each_entry(interface, &globals->interfaces, list) {
+ /* too large? - should never happen */
+ if (sizeof(*status_net_iface) + len > sizeof(buf)) {
+ fprintf(stderr, "ERROR: send buffer too small for server_status iface\n");
+ goto err;
+ }
+
+ status_net_iface = (struct alfred_server_status_net_iface_v0 *)(buf + len);
+ status_net_iface->header.type = ALFRED_SERVER_NET_IFACE;
+ status_net_iface->header.version = ALFRED_VERSION;
+ status_net_iface->header.length = FIXED_TLV_LEN_PTR(status_net_iface);
+
+ strncpy(status_net_iface->net_iface, interface->interface,
+ sizeof(status_net_iface->net_iface));
+ status_net_iface->net_iface[sizeof(status_net_iface->net_iface) - 1] = '\0';
+ if (interface->netsock > -1)
+ status_net_iface->active = 1;
+ else
+ status_net_iface->active = 0;
+
+ len += sizeof(*status_net_iface);
+ }
+
+ /* too large? - should never happen */
+ if (sizeof(*status_bat_iface) + len > sizeof(buf)) {
+ fprintf(stderr, "ERROR: send buffer too small for server_status bat_iface\n");
+ goto err;
+ }
+
+ status_bat_iface = (struct alfred_server_status_bat_iface_v0 *)(buf + len);
+ status_bat_iface->header.type = ALFRED_SERVER_BAT_IFACE;
+ status_bat_iface->header.version = ALFRED_VERSION;
+ status_bat_iface->header.length = FIXED_TLV_LEN_PTR(status_bat_iface);
+
+ strncpy(status_bat_iface->bat_iface, globals->mesh_iface,
+ sizeof(status_bat_iface->bat_iface));
+ status_bat_iface->bat_iface[sizeof(status_bat_iface->bat_iface) - 1] = '\0';
+
+ len += sizeof(*status_bat_iface);
+ status_rep->header.length = htons(len - sizeof(status_rep->header));
+
+ ret = write(client_sock, buf, len);
+ if (ret != len) {
+ fprintf(stderr, "%s: only wrote %d of %d bytes: %s\n",
+ __func__, ret, len, strerror(errno));
+ ret = -1;
+ goto err;
+ }
+
+ ret = 0;
+
+err:
+ close(client_sock);
+ return ret;
+}
+
int unix_sock_read(struct globals *globals)
{
int client_sock;
@@ -428,6 +531,9 @@ int unix_sock_read(struct globals *globals)
(struct alfred_change_bat_iface_v0 *)packet,
client_sock);
break;
+ case ALFRED_SERVER_STATUS:
+ ret = unix_sock_server_status(globals, client_sock);
+ break;
default:
/* unknown packet type */
ret = -1;