From a9b9f51a9f7540214ba35058440b6778aef73382 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Mon, 2 Mar 2015 15:41:07 +1030 Subject: [PATCH] Add support for mdp clients to provide a link layer packet transport --- conf_schema.c | 6 +- constants.h | 3 + java/org/servalproject/codec/Base64.java | 70 +++-- .../servaldna/AbstractExternalInterface.java | 97 ++++++ mdp_client.h | 11 + overlay_interface.c | 281 ++++++++++-------- overlay_interface.h | 12 +- overlay_mdp.c | 111 ++++++- route_link.c | 6 +- serval.h | 1 + socket.h | 1 + 11 files changed, 460 insertions(+), 139 deletions(-) create mode 100644 java/org/servalproject/servaldna/AbstractExternalInterface.java diff --git a/conf_schema.c b/conf_schema.c index 7f5d856e..6b6b718d 100644 --- a/conf_schema.c +++ b/conf_schema.c @@ -760,6 +760,10 @@ int cf_opt_socket_type(short *typep, const char *text) *typep = SOCK_FILE; return CFOK; } + if (strcasecmp(text, "external") == 0) { + *typep = SOCK_EXT; + return CFOK; + } return CFINVALID; } @@ -1018,7 +1022,7 @@ int vld_network_interface(const struct cf_om_node *parent, struct config_network return result | CFINCOMPLETE; } } else { - if (nifp->socket_type != SOCK_DGRAM && !nifp->file[0]){ + if (nifp->socket_type != SOCK_DGRAM && nifp->socket_type != SOCK_EXT && !nifp->file[0]){ cf_warn_missing_node(parent, "file"); return result | CFSUB(CFINCOMPATIBLE); } diff --git a/constants.h b/constants.h index 1eae3498..408e8b89 100644 --- a/constants.h +++ b/constants.h @@ -184,6 +184,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // force state packet interval #define VOMP_CALL_STATUS_INTERVAL 1000 +// mdp client interface +#define SOCK_EXT 0xFE +// dummy file interface #define SOCK_FILE 0xFF #define SOCK_UNSPECIFIED 0 diff --git a/java/org/servalproject/codec/Base64.java b/java/org/servalproject/codec/Base64.java index 56ff6ac4..89df7773 100644 --- a/java/org/servalproject/codec/Base64.java +++ b/java/org/servalproject/codec/Base64.java @@ -24,12 +24,13 @@ import java.lang.StringBuilder; public class Base64 { - public static final char[] SYMBOLS = { - 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', - 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', - 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', - 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/', - '=' + public static final char[] SYMBOLS; + public static final String charSet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + static{ + char chars[] = new char[64]; + for (int i=0;i>> 2]); - buf = (byte)((b << 4) & 0x3f); - place = 1; + sb.append(SYMBOLS[val >>> 2]); + buf = (byte)((val << 4) & 0x3f); break; case 1: - sb.append(SYMBOLS[(b >>> 4) | buf]); - buf = (byte)((b << 2) & 0x3f); - place = 2; + sb.append(SYMBOLS[(val >>> 4) | buf]); + buf = (byte)((val << 2) & 0x3f); break; case 2: - sb.append(SYMBOLS[(b >>> 6) | buf]); - sb.append(SYMBOLS[b & 0x3f]); + sb.append(SYMBOLS[(val >>> 6) | buf]); + sb.append(SYMBOLS[val & 0x3f]); place = 0; break; } @@ -60,11 +60,47 @@ public class Base64 { sb.append(SYMBOLS[buf]); switch (place) { case 1: - sb.append(SYMBOLS[64]); + sb.append('='); case 2: - sb.append(SYMBOLS[64]); + sb.append('='); } return sb.toString(); } + public static byte[] decode(String value) + { + int len = value.length()/4 * 3; + if (value.endsWith("==")) + len -=2; + else if(value.endsWith("=")) + len --; + byte ret[] = new byte[len]; + int pos=0; + for (int i=0;i>4)&0x03); + if (pos>=ret.length) break; + ret[pos] = (byte) (val<<4); + break; + case 2: + ret[pos++] |= (byte) ((val>>2)&0x0F); + if (pos>=ret.length) break; + ret[pos] = (byte) (val<<6); + break; + case 3: + ret[pos++] |= (byte) (val & 0x3f); + break; + } + } + return ret; + } } diff --git a/java/org/servalproject/servaldna/AbstractExternalInterface.java b/java/org/servalproject/servaldna/AbstractExternalInterface.java new file mode 100644 index 00000000..837f3201 --- /dev/null +++ b/java/org/servalproject/servaldna/AbstractExternalInterface.java @@ -0,0 +1,97 @@ +package org.servalproject.servaldna; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; + +/** + * Created by jeremy on 8/05/14. + */ +public abstract class AbstractExternalInterface extends ChannelSelector.Handler { + private final ChannelSelector selector; + protected final MdpSocket socket; + + public AbstractExternalInterface(ChannelSelector selector, int loopbackMdpPort) throws IOException { + this.socket = new MdpSocket(loopbackMdpPort); + + this.selector = selector; + selector.register(this); + } + + public void close(){ + try { + selector.unregister(this); + } catch (IOException e) { + e.printStackTrace(); + } + socket.close(); + } + + private static final int MDP_INTERFACE=4; + private static final int MDP_INTERFACE_UP=0; + private static final int MDP_INTERFACE_DOWN=1; + private static final int MDP_INTERFACE_RECV=2; + + public void up(String config) throws IOException { + MdpPacket packet = new MdpPacket(); + packet.setRemotePort(MDP_INTERFACE); + packet.payload.put((byte) MDP_INTERFACE_UP); + packet.payload.put(config.getBytes()); + packet.payload.flip(); + packet.send((DatagramChannel)socket.getChannel()); + } + + public void down() throws IOException { + MdpPacket packet = new MdpPacket(); + packet.setRemotePort(MDP_INTERFACE); + packet.payload.put((byte) MDP_INTERFACE_DOWN); + packet.payload.flip(); + packet.send((DatagramChannel) socket.getChannel()); + } + + public void receivedPacket(byte recvaddr[], byte recvbytes[]) throws IOException { + receivedPacket(recvaddr, recvbytes, 0, recvbytes==null?0:recvbytes.length); + } + public void receivedPacket(byte recvaddr[], byte recvbytes[], int offset, int len) throws IOException { + MdpPacket packet = new MdpPacket(); + packet.setRemotePort(MDP_INTERFACE); + packet.payload.put((byte) MDP_INTERFACE_RECV); + packet.payload.put((byte) recvaddr.length); + packet.payload.put(recvaddr); + if (len>0) + packet.payload.put(recvbytes, offset, len); + packet.payload.flip(); + packet.send((DatagramChannel) socket.getChannel()); + } + + protected abstract void sendPacket(byte addr[], ByteBuffer payload); + + @Override + public void read() { + try { + MdpPacket response = new MdpPacket(); + socket.receive(response); + int addrlen = response.payload.get() & 0xFF; + byte addr[]=null; + if (addrlen>0) { + addr = new byte[addrlen]; + response.payload.get(addr); + } + sendPacket(addr, response.payload); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public SelectableChannel getChannel() throws IOException { + return socket.getChannel(); + } + + @Override + public int getInterest() { + return SelectionKey.OP_READ; + } +} diff --git a/mdp_client.h b/mdp_client.h index 2308a541..04a9ffeb 100644 --- a/mdp_client.h +++ b/mdp_client.h @@ -89,6 +89,17 @@ struct mdp_identity_request { */ #define MDP_SYNC_CONFIG 3 +/* External interface implementation + * + * Messages used for talking to a client application that implements a network + * interface that isn't based on simple file descriptors + * eg android bluetooth & wifi-direct +*/ +#define MDP_INTERFACE 4 +#define MDP_INTERFACE_UP 0 +#define MDP_INTERFACE_DOWN 1 +#define MDP_INTERFACE_RECV 2 + struct overlay_route_record{ sid_t sid; char interface_name[256]; diff --git a/overlay_interface.c b/overlay_interface.c index df131dd8..d1578980 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -59,22 +59,27 @@ struct profile_total sock_any_stats; static void overlay_interface_poll(struct sched_ent *alarm); -static void -overlay_interface_close(overlay_interface *interface){ +void overlay_interface_close(overlay_interface *interface) +{ + if (interface->alarm.poll.fd>=0){ + if (interface->address.addr.sa_family == AF_UNIX) + unlink(interface->address.local.sun_path); + if (is_watching(&interface->alarm)) + unwatch(&interface->alarm); + close(interface->alarm.poll.fd); + interface->alarm.poll.fd=-1; + } + + unschedule(&interface->alarm); + if (interface->radio_link_state) + radio_link_free(interface); + interface->state=INTERFACE_STATE_DOWN; + monitor_tell_formatted(MONITOR_INTERFACE, "\nINTERFACE:%s:DOWN\n", interface->name); INFOF("Interface %s addr %s is down", interface->name, alloca_socket_address(&interface->address)); - if (interface->address.addr.sa_family == AF_UNIX) - unlink(interface->address.local.sun_path); + link_interface_down(interface); - unschedule(&interface->alarm); - if (is_watching(&interface->alarm)) - unwatch(&interface->alarm); - close(interface->alarm.poll.fd); - if (interface->radio_link_state) - radio_link_free(interface); - interface->alarm.poll.fd=-1; - interface->state=INTERFACE_STATE_DOWN; } void overlay_interface_close_all() @@ -134,6 +139,12 @@ void interface_state_html(struct strbuf *b, struct overlay_interface *interface) case SOCK_FILE: strbuf_puts(b, "Socket: File
"); break; + case SOCK_EXT: + { + strbuf_puts(b, "Socket: External
"); + strbuf_sprintf(b, "Client: %s
", alloca_socket_address(&interface->address)); + } + break; } strbuf_sprintf(b, "TX: %d
", interface->tx_count); strbuf_sprintf(b, "RX: %d
", interface->recv_count); @@ -268,6 +279,22 @@ overlay_interface * overlay_interface_find_name(const char *name){ return NULL; } +// find an interface by name and address +overlay_interface * overlay_interface_find_name_addr(const char *name, struct socket_address *addr){ + int i; + for(i = 0; i < OVERLAY_MAX_INTERFACES; i++){ + if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN) + continue; + + if (cmp_sockaddr(addr, &overlay_interfaces[i].address)==0 + && (!name || strcasecmp(overlay_interfaces[i].name, name)==0)){ + return &overlay_interfaces[i]; + } + } + + return NULL; +} + static int interface_type_priority(int type) { switch(type){ @@ -405,61 +432,28 @@ overlay_interface_init_socket(overlay_interface *interface) return 0; } -/* Returns 0 if interface is successfully added. - * Returns 1 if interface is not added (eg, dummy file does not exist). - * Returns -1 in case of error (misconfiguration or system error). - */ -static int -overlay_interface_init(const char *name, struct socket_address *addr, - struct socket_address *netmask, - struct socket_address *broadcast, - const struct config_network_interface *ifconfig) +int overlay_interface_configure(struct overlay_interface *interface, const struct config_network_interface *ifconfig) { - int cleanup_ret = -1; - - int interface_id=-1; - int i; - for (i=0; istate=INTERFACE_STATE_DOWN; - - strncpy(interface->name, name, sizeof interface->name); - // copy ifconfig values interface->drop_broadcasts = ifconfig->drop_broadcasts; interface->drop_unicasts = ifconfig->drop_unicasts; interface->drop_packets = ifconfig->drop_packets; - interface->port = ifconfig->port; interface->type = ifconfig->type; interface->send_broadcasts = ifconfig->send_broadcasts; interface->dont_route = ifconfig->dont_route; interface->prefer_unicast = ifconfig->prefer_unicast; interface->default_route = ifconfig->default_route; + interface->destination->encapsulation = ifconfig->encapsulation; + interface->port = ifconfig->port; interface->socket_type = ifconfig->socket_type; interface->uartbps = ifconfig->uartbps; interface->ctsrts = ifconfig->ctsrts; - set_destination_ref(&interface->destination, NULL); - interface->destination = new_destination(interface, ifconfig->encapsulation); + interface->point_to_point = ifconfig->point_to_point; + interface->debug = ifconfig->debug; /* Pick a reasonable default MTU. This will ultimately get tuned by the bandwidth and other properties of the interface */ interface->mtu = 1200; - interface->point_to_point = ifconfig->point_to_point; - - interface->alarm.poll.fd=0; - interface->debug = ifconfig->debug; - interface->tx_count=0; - interface->recv_count=0; - // How often do we announce ourselves on this interface? int tick_ms=-1; int packet_interval=-1; @@ -505,72 +499,125 @@ overlay_interface_init(const char *name, struct socket_address *addr, reachable_timeout_ms = ifconfig->mdp.reachable_timeout_ms; if (packet_interval<0) - return WHYF("Invalid packet interval %d specified for interface %s", packet_interval, name); + return WHYF("Invalid packet interval %d specified for interface %s", packet_interval, interface->name); if (packet_interval==0){ - INFOF("Interface %s is not sending any traffic!", name); + INFOF("Interface %s is not sending any traffic!", interface->name); tick_ms=0; }else if (!interface->send_broadcasts){ - INFOF("Interface %s is not sending any broadcast traffic!", name); + INFOF("Interface %s is not sending any broadcast traffic!", interface->name); }else if (tick_ms==0) - INFOF("Interface %s is running tickless", name); + INFOF("Interface %s is running tickless", interface->name); if (tick_ms<0) - return WHYF("No tick interval specified for interface %s", name); + return WHYF("No tick interval specified for interface %s", interface->name); interface->destination->tick_ms = tick_ms; interface->destination->reachable_timeout_ms = reachable_timeout_ms >= 0 ? reachable_timeout_ms : tick_ms > 0 ? tick_ms * 5 : 2500; limit_init(&interface->destination->transfer_limit, packet_interval); + + return 0; +} + +/* Returns 0 if interface is successfully added. + * Returns 1 if interface is not added (eg, dummy file does not exist). + * Returns -1 in case of error (misconfiguration or system error). + */ +int +overlay_interface_init(const char *name, struct socket_address *addr, + struct socket_address *netmask, + struct socket_address *broadcast, + const struct config_network_interface *ifconfig) +{ + int cleanup_ret = -1; + + int interface_id=-1; + int i; + for (i=0; istate=INTERFACE_STATE_DOWN; + + strncpy(interface->name, name, sizeof interface->name); + + set_destination_ref(&interface->destination, NULL); + interface->destination = new_destination(interface); + + if (overlay_interface_configure(interface, ifconfig)==-1) + return -1; + + interface->alarm.poll.fd=0; + interface->tx_count=0; + interface->recv_count=0; if (addr) interface->address = *addr; if (broadcast) interface->destination->address = *broadcast; - interface->alarm.function = overlay_interface_poll; interface_poll_stats.name="overlay_interface_poll"; interface->alarm.stats=&interface_poll_stats; - if (ifconfig->socket_type == SOCK_DGRAM){ - if (ifconfig->drop_broadcasts || ifconfig->drop_unicasts || ifconfig->drop_packets) - FATALF("Invalid interface definition. We only support dropping packets on dummy file interfaces"); - if (netmask) - interface->netmask = netmask->inet.sin_addr; - else - interface->netmask = ifconfig->dummy_netmask; - interface->local_echo = 1; - - if (overlay_interface_init_socket(interface)) - return WHY("overlay_interface_init_socket() failed"); - }else{ - char read_file[1024]; - interface->local_echo = interface->point_to_point?0:1; - if (!FORMF_SERVAL_TMP_PATH(read_file, "%s/%s", config.server.interface_path, ifconfig->file)) - return -1; - if ((interface->alarm.poll.fd = open(read_file, O_APPEND|O_RDWR)) == -1) { - if (errno == ENOENT && ifconfig->socket_type == SOCK_FILE) { - cleanup_ret = 1; - WARNF("dummy interface not enabled: %s does not exist", alloca_str_toprint(read_file)); - } else { - cleanup_ret = WHYF_perror("file interface not enabled: open(%s, O_APPEND|O_RDWR)", alloca_str_toprint(read_file)); - } - goto cleanup; - } - - if (ifconfig->type==OVERLAY_INTERFACE_PACKETRADIO) - overlay_packetradio_setup_port(interface); - - switch (ifconfig->socket_type) { + switch(ifconfig->socket_type){ + case SOCK_DGRAM: + if (ifconfig->drop_broadcasts || ifconfig->drop_unicasts || ifconfig->drop_packets) + FATALF("Invalid interface definition. We only support dropping packets on dummy file interfaces"); + if (netmask) + interface->netmask = netmask->inet.sin_addr; + else + interface->netmask = ifconfig->dummy_netmask; + interface->local_echo = 1; + + if (overlay_interface_init_socket(interface)) + return WHY("overlay_interface_init_socket() failed"); + break; + + case SOCK_EXT: + interface->local_echo = 0; + interface->alarm.poll.fd = -1; + break; + case SOCK_STREAM: - radio_link_init(interface); - interface->alarm.poll.events=POLLIN|POLLOUT; - watch(&interface->alarm); - - break; case SOCK_FILE: - /* Seek to end of file as initial reading point */ - interface->recv_offset = lseek(interface->alarm.poll.fd,0,SEEK_END); - break; + { + char read_file[1024]; + interface->local_echo = interface->point_to_point?0:1; + if (!FORMF_SERVAL_TMP_PATH(read_file, "%s/%s", config.server.interface_path, ifconfig->file)) + return -1; + if ((interface->alarm.poll.fd = open(read_file, O_APPEND|O_RDWR)) == -1) { + if (errno == ENOENT && ifconfig->socket_type == SOCK_FILE) { + cleanup_ret = 1; + WARNF("dummy interface not enabled: %s does not exist", alloca_str_toprint(read_file)); + } else { + cleanup_ret = WHYF_perror("file interface not enabled: open(%s, O_APPEND|O_RDWR)", alloca_str_toprint(read_file)); + } + goto cleanup; + } + + if (ifconfig->type==OVERLAY_INTERFACE_PACKETRADIO) + overlay_packetradio_setup_port(interface); + + switch (ifconfig->socket_type) { + case SOCK_STREAM: + radio_link_init(interface); + interface->alarm.poll.events=POLLIN|POLLOUT; + watch(&interface->alarm); + break; + + case SOCK_FILE: + /* Seek to end of file as initial reading point */ + interface->recv_offset = lseek(interface->alarm.poll.fd,0,SEEK_END); + break; + } } } @@ -786,6 +833,7 @@ static void overlay_interface_poll(struct sched_ent *alarm) radio_link_tx(interface); return; case SOCK_DGRAM: + case SOCK_EXT: break; case SOCK_FILE: interface_read_file(interface); @@ -808,6 +856,7 @@ static void overlay_interface_poll(struct sched_ent *alarm) case SOCK_STREAM: radio_link_tx(interface); return; + case SOCK_EXT: case SOCK_DGRAM: case SOCK_FILE: //XXX error? fatal? @@ -831,6 +880,8 @@ static void overlay_interface_poll(struct sched_ent *alarm) case SOCK_FILE: interface_read_file(interface); break; + case SOCK_EXT: + break; } } @@ -903,9 +954,11 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o return WHYF("Cannot send to interface %s as it is down", interface->name); } - if (interface->debug) - DEBUGF("Sending on %s, len %zu: %s", interface->name, len, alloca_tohex(bytes, len>64?64:len)); - + if (config.debug.overlayinterfaces || interface->debug) + DEBUGF("Sending %zu byte overlay frame on %s to %s [%s]", + (size_t)len, interface->name, alloca_socket_address(&destination->address), + alloca_tohex(bytes, len>64?64:len)); + interface->tx_count++; switch(interface->socket_type){ @@ -960,13 +1013,14 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o return WHYF("only wrote %d of %d bytes", (int)nwrite, (int)sizeof(packet)); return 0; } - + case SOCK_EXT: + { + mdp_send_external_packet(interface, &destination->address, bytes, (size_t)len); + ob_free(buffer); + return 0; + } case SOCK_DGRAM: { - if (config.debug.overlayinterfaces) - DEBUGF("Sending %zu byte overlay frame on %s to %s", - (size_t)len, interface->name, alloca_socket_address(&destination->address)); - set_nonblock(interface->alarm.poll.fd); if (destination->address.addr.sa_family == AF_UNIX && !destination->unicast){ @@ -1051,20 +1105,12 @@ overlay_interface_register(char *name, DEBUGF("%s broadcast address: %s", name, alloca_socket_address(broadcast)); } - /* Search in the exist list of interfaces */ - for(i = 0; i < OVERLAY_MAX_INTERFACES; i++){ - if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN) - continue; - - if (strcasecmp(overlay_interfaces[i].name, name)==0 - && cmp_sockaddr(addr, &overlay_interfaces[i].address)==0){ - - // mark this interface as still alive - if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING) - overlay_interfaces[i].state=INTERFACE_STATE_UP; - - return 0; - } + struct overlay_interface *interface = overlay_interface_find_name_addr(name, addr); + if (interface){ + // mark this interface as still alive + if (interface->state == INTERFACE_STATE_DETECTING) + interface->state = INTERFACE_STATE_UP; + return 0; } /* New interface, so register it */ @@ -1135,6 +1181,9 @@ void overlay_interface_discover(struct sched_ent *alarm) case SOCK_STREAM: overlay_interface_init(ifconfig->file, &addr, NULL, &broadcast, ifconfig); break; + case SOCK_EXT: + // FAIL? + break; case SOCK_DGRAM: { // use a local dgram socket diff --git a/overlay_interface.h b/overlay_interface.h index 2c43a7fe..661ee9eb 100644 --- a/overlay_interface.h +++ b/overlay_interface.h @@ -143,7 +143,7 @@ typedef struct overlay_interface { */ extern overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES]; -struct network_destination * new_destination(struct overlay_interface *interface, char encapsulation); +struct network_destination * new_destination(struct overlay_interface *interface); struct network_destination * create_unicast_destination(struct socket_address *addr, struct overlay_interface *interface); struct network_destination * add_destination_ref(struct network_destination *ref); void release_destination_ref(struct network_destination *ref); @@ -151,6 +151,15 @@ int set_destination_ref(struct network_destination **ptr, struct network_destina DECLARE_ALARM(overlay_interface_discover); +struct config_network_interface; +int overlay_interface_configure(struct overlay_interface *interface, const struct config_network_interface *ifconfig); +int +overlay_interface_init(const char *name, struct socket_address *addr, + struct socket_address *netmask, + struct socket_address *broadcast, + const struct config_network_interface *ifconfig); +void overlay_interface_close(overlay_interface *interface); + int overlay_interface_register(char *name, struct socket_address *addr, struct socket_address *netmask, @@ -159,6 +168,7 @@ void overlay_interface_close_all(); overlay_interface * overlay_interface_get_default(); overlay_interface * overlay_interface_find(struct in_addr addr, int return_default); overlay_interface * overlay_interface_find_name(const char *name); +overlay_interface * overlay_interface_find_name_addr(const char *name, struct socket_address *addr); int overlay_interface_compare(overlay_interface *one, overlay_interface *two); int overlay_broadcast_ensemble(struct network_destination *destination, struct overlay_buffer *buffer); void interface_state_html(struct strbuf *b, struct overlay_interface *interface); diff --git a/overlay_mdp.c b/overlay_mdp.c index 4d00da85..dfdd4464 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -1110,7 +1110,7 @@ static int search_subscribers(struct subscriber *subscriber, void *context){ return 0; } -int overlay_mdp_address_list(struct overlay_mdp_addrlist *request, struct overlay_mdp_addrlist *response) +static int overlay_mdp_address_list(struct overlay_mdp_addrlist *request, struct overlay_mdp_addrlist *response) { if (config.debug.mdprequests) DEBUGF("MDP_GETADDRS first_sid=%u mode=%d", request->first_sid, request->mode); @@ -1340,6 +1340,110 @@ static int mdp_search_identities(struct socket_address *client, struct mdp_heade return 0; } +const char *external_name="ext"; // TODO? + +int mdp_send_external_packet(struct overlay_interface *interface, struct socket_address *address, const uint8_t *payload, size_t len) +{ + struct mdp_header header; + bzero(&header, sizeof header); + header.remote.port = MDP_INTERFACE; + uint8_t addrlen = address->addrlen; + + struct iovec iov[]={ + { + .iov_base = (void *)&header, + .iov_len = sizeof(struct mdp_header) + }, + { + .iov_base = (void *)&addrlen, + .iov_len = sizeof addrlen + }, + { + .iov_base = (void *)&address->raw, + .iov_len = addrlen + }, + { + .iov_base = (void *)payload, + .iov_len = len + } + }; + + struct msghdr hdr={ + .msg_name=&interface->address.addr, + .msg_namelen=interface->address.addrlen, + .msg_iov=iov, + .msg_iovlen=4, + }; + + int fd=-1; + switch(interface->address.addr.sa_family){ + case AF_UNIX: + fd = mdp_sock2.poll.fd; + break; + case AF_INET: + fd = mdp_sock2_inet.poll.fd; + break; + } + if (fd==-1) + return WHYF("Unhandled client family %d", interface->address.addr.sa_family); + + if (sendmsg(fd, &hdr, 0)<0) + return WHY_perror("sendmsg"); + + return 0; +} + +static void mdp_interface_packet(struct socket_address *client, struct mdp_header *UNUSED(header), + struct overlay_buffer *payload){ + int msg_type = ob_get(payload); + switch (msg_type){ + case MDP_INTERFACE_UP:{ + struct config_network_interface ifconfig; + cf_dfl_config_network_interface(&ifconfig); + + struct cf_om_node *conf_node = NULL; + int result = cf_om_parse(external_name, (char*)ob_current_ptr(payload), ob_remaining(payload), &conf_node); + if (result == CFOK || result == CFEMPTY){ + result = conf_node ? cf_opt_config_network_interface(&ifconfig, conf_node) : CFEMPTY; + } + + if (result == CFOK || result == CFEMPTY){ + if (ifconfig.socket_type != SOCK_EXT){ + // TODO log nice warning, pick right result code + result |= CFSUB(CFUNSUPPORTED); + } + } + + if (result == CFOK || result == CFEMPTY){ + struct overlay_interface *interface=overlay_interface_find_name_addr(external_name, client); + if (!interface){ + overlay_interface_init(external_name, client, NULL, NULL, &ifconfig); + }else{ + if (overlay_interface_configure(interface, &ifconfig)==-1) + overlay_interface_close(interface); + } + } + }break; + case MDP_INTERFACE_DOWN:{ + struct overlay_interface *interface=overlay_interface_find_name_addr(external_name, client); + if (interface) + overlay_interface_close(interface); + }break; + case MDP_INTERFACE_RECV:{ + struct overlay_interface *interface=overlay_interface_find_name_addr(external_name, client); + if (interface){ + struct socket_address addr; + addr.addrlen = ob_get(payload); + if (addr.addrlen > sizeof(addr)) + break; // TODO errors + bcopy(ob_get_bytes_ptr(payload, addr.addrlen), addr.raw, addr.addrlen); + packetOkOverlay(interface, ob_current_ptr(payload), ob_remaining(payload), &addr); + } + break; + } + } +} + static void mdp_process_packet(struct socket_address *client, struct mdp_header *header, struct overlay_buffer *payload) { @@ -1485,6 +1589,11 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header server_config_reload(NULL); mdp_reply_ok(client, header); break; + case MDP_INTERFACE: + if (config.debug.mdprequests) + DEBUGF("Processing MDP_INTERFACE from %s", alloca_socket_address(client)); + mdp_interface_packet(client, header, payload); + break; default: WHYF("Unknown command port %d", header->remote.port); mdp_reply_error(client, header); diff --git a/route_link.c b/route_link.c index aaa9b8b2..4f15ddaa 100644 --- a/route_link.c +++ b/route_link.c @@ -172,12 +172,11 @@ static int neighbour_find_best_link(struct neighbour *n); struct neighbour *neighbours=NULL; int route_version=0; -struct network_destination * new_destination(struct overlay_interface *interface, char encapsulation){ +struct network_destination * new_destination(struct overlay_interface *interface){ assert(interface); struct network_destination *ret = emalloc_zero(sizeof(struct network_destination)); if (ret){ ret->_ref_count=1; - ret->encapsulation = encapsulation; ret->interface = interface; ret->resend_delay = 1000; ret->last_tx = TIME_MS_NEVER_HAS; @@ -201,8 +200,9 @@ struct network_destination * create_unicast_destination(struct socket_address *a if (addr->addr.sa_family == AF_INET && (addr->inet.sin_addr.s_addr==0 || addr->inet.sin_port==0)) return NULL; - struct network_destination *ret = new_destination(interface, ENCAP_OVERLAY); + struct network_destination *ret = new_destination(interface); if (ret){ + ret->encapsulation = ENCAP_OVERLAY; ret->address = *addr; ret->unicast = 1; ret->tick_ms = interface->destination->tick_ms; diff --git a/serval.h b/serval.h index e3db34a0..5f683e4f 100644 --- a/serval.h +++ b/serval.h @@ -174,6 +174,7 @@ struct overlay_frame; struct broadcast; void overlay_mdp_clean_socket_files(); +int mdp_send_external_packet(struct overlay_interface *interface, struct socket_address *address, const uint8_t *payload, size_t len); int overlay_forward_payload(struct overlay_frame *f); int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len, diff --git a/socket.h b/socket.h index a6108367..594ae927 100644 --- a/socket.h +++ b/socket.h @@ -41,6 +41,7 @@ struct socket_address{ struct sockaddr_un local; // name "unix" is a predefined macro struct sockaddr_in inet; struct sockaddr_storage store; + uint8_t raw[255]; }; };