diff --git a/dist/tools/chamoc/.gitignore b/dist/tools/chamoc/.gitignore new file mode 100644 index 000000000..25db5d7ee --- /dev/null +++ b/dist/tools/chamoc/.gitignore @@ -0,0 +1,2 @@ + +CHAMOC.out diff --git a/dist/tools/chamoc/autoconfigure.sh b/dist/tools/chamoc/autoconfigure.sh new file mode 100755 index 000000000..4c10fc3ec --- /dev/null +++ b/dist/tools/chamoc/autoconfigure.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash + +SUDO=${SUDO:-sudo} +PREFIX=64 +NPREFIX=:: + +unsupported_platform() { + echo "unsupported platform" >&2 + echo "(currently supported \`uname -s\` 'Darwin' and 'Linux')" >&2 +} + +case "$(uname -s)" in + Darwin) + PLATFORM="OSX";; + Linux) + PLATFORM="Linux";; + *) + unsupported_platform + exit 1 + ;; +esac + +INTERFACE_CHECK_COUNTER=5 # 5 attempts to find usb interface + +find_interface() { + INTERFACE=$(ls -A /sys/bus/usb/drivers/cdc_ether/*/net/ 2>/dev/null) + INTERFACE_CHECK=$(echo -n "${INTERFACE}" | head -c1 | wc -c) + if [ "${INTERFACE_CHECK}" -eq 0 ] && [ ${INTERFACE_CHECK_COUNTER} != 0 ]; then + # We want to have multiple opportunities to find the USB interface + # as sometimes it can take a few seconds for it to enumerate after + # the device has been flashed. + sleep 1 + ((INTERFACE_CHECK_COUNTER=INTERFACE_CHECK_COUNTER-1)) + find_interface + fi + INTERFACE=${INTERFACE%/} +} + +echo "Waiting for network interface." +find_interface + +add_addresses(){ + case "${PLATFORM}" in + Linux) + ${SUDO} sysctl -w net.ipv6.conf."${INTERFACE}".forwarding=1 + ${SUDO} sysctl -w net.ipv6.conf."${INTERFACE}".accept_ra=0 + ${SUDO} ip link set "${INTERFACE}" up + ${SUDO} ip a a "${IPV6_GLOBAL}"/64 dev "${INTERFACE}" + ${SUDO} ip route add "${NPREFIX}" via "${IPV6_GLOBAL}" dev "${INTERFACE}" + gcc -Iinclude *.c -o CHAMOC.out + echo "Start sending a nib add request" + ${SUDO} ./CHAMOC.out nib add "${INTERFACE}" "${IPV6_GLOBAL}" "${PREFIX}" + ;; + OSX) + ${SUDO} sysctl -w net.ipv6.conf."${INTERFACE}".forwarding=1 + ${SUDO} sysctl -w net.ipv6.conf."${INTERFACE}".accept_ra=0 + ${SUDO} ip link set "${INTERFACE}" up + ${SUDO} ip a a "${IPV6_GLOBAL}"/64 dev "${INTERFACE}" + ${SUDO} ip route add "${NPREFIX}" via "${IPV6_GLOBAL}" dev "${INTERFACE}" + gcc -Iinclude *.c -o CHAMOC.out + echo "Start sending a nib add request" + ${SUDO} ./CHAMOC.out nib add "${INTERFACE}" "${IPV6_GLOBAL}" "${PREFIX}" + ;; + esac +} + +close_connection(){ + echo "Start sending a nib delete request" + ${SUDO} ./CHAMOC.out nib del "${INTERFACE}" "${IPV6_GLOBAL}" "${PREFIX}" + ${SUDO} ip link set "${INTERFACE}" up + ${SUDO} ip a d "${IPV6_GLOBAL}"/64 dev "${INTERFACE}" + ${SUDO} ip route del "${NPREFIX}" via "${IPV6_GLOBAL}" dev "${INTERFACE}" +} + +IPV6_GLOBAL=$1 + +if [ -z "${IPV6_GLOBAL}" ]; then + IPV6_GLOBAL="2001:db8::1" +fi + +find_interface + +if [ -z "${INTERFACE}" ]; then + echo "USB network interface not found" +else + add_addresses + echo "Connection started" + echo "Press any key to close connection" + read -r -n 1 + close_connection +fi diff --git a/dist/tools/chamoc/chamoc_msg.c b/dist/tools/chamoc/chamoc_msg.c new file mode 100644 index 000000000..441b94464 --- /dev/null +++ b/dist/tools/chamoc/chamoc_msg.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022 Mesh4all + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief CHAMOC_MSG + * + * @author eduazocar + */ + +#include +#include +#include +#include +#include +#include +#include +#include "client.h" +#include "chamoc_msg.h" + +int serialize(chamoc_message_t msg, char *buffer, uint8_t len) { + uint8_t strbuff[19] = {msg.message, msg.seqno, msg.prefix}; + for (int i = 0; i < 16; i++) { + strbuff[3 + i] = msg.addr.in_8[i]; + } + memcpy(buffer, strbuff, len); +} + +int connect_chamos(chamos_client_t client, char *buffer, uint8_t len) { + struct timeval tv; + tv.tv_sec = 2; + tv.tv_usec = 0; + int tries = 0; + if (setsockopt(client.socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0) { + printf("configuration_failed\n"); + return -1; + } + + while (tries < 5) { + send_message(&client, (uint8_t *)buffer, len); + recv(client.socket, buffer, len, 0); + if (buffer[0] == MSG_ACK) { + printf("Request Confirmed\n"); + break; + } else { + tries++; + if (tries < 5) { + printf("Bad Request, Trying Again\n"); + } else { + printf("Time Out\n\n"); + } + } + } + return 1; +} + +uint8_t craft_seqno(chamos_client_t *client) { client->seqno += 1; } + +int8_t send_message(chamos_client_t *client, uint8_t *msg, uint8_t len) { + if (client->socket < 0) { + return -1; + } + sendto(client->socket, msg, len, 0, (struct sockaddr *)&client->csock, sizeof(client->csock)); + return 1; +} + +#ifdef DEBUG_MODE +void printf_buff(char *buffer, uint8_t len) { + for (int i = 0; i < len; i++) { + if (i > 2) { + printf("%02hhx", (uint8_t)buffer[i]); + } else { + printf("%d", (uint8_t)buffer[i]); + } + } + printf("\n"); +} +#endif diff --git a/dist/tools/chamoc/client.c b/dist/tools/chamoc/client.c new file mode 100644 index 000000000..927561748 --- /dev/null +++ b/dist/tools/chamoc/client.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 Mesh4all + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief CHAMOC_client + * + * @author eduazocar + */ + +#include +#include +#include +#include +#include +#include +#include +#include "client.h" +#include "chamoc_msg.h" +#include "nib.h" + +chamos_client_t new_client(char *netif) { + chamos_client_t client; + socklen_t client_len = sizeof(client.csock); + client.socket = socket(PF_INET6, SOCK_DGRAM, 0); + memset(&client.csock, '\0', sizeof(client.csock)); + client.csock.sin6_family = AF_INET6; + client.csock.sin6_port = htons(CHAMOC_PORT); + if (inet_pton(AF_INET6, MULTICAST_ADDR, &client.csock.sin6_addr) < 0) { + client.socket = -1; + }; + if (setsockopt(client.socket, SOL_SOCKET, SO_BINDTODEVICE, netif, client_len) < 0) { + printf("Failed binding\n"); + } + if (client.socket < 0) { + printf("Wrong socket init \n"); + exit(0); + } + return client; +} diff --git a/dist/tools/chamoc/doc.txt b/dist/tools/chamoc/doc.txt new file mode 100644 index 000000000..8febadc2a --- /dev/null +++ b/dist/tools/chamoc/doc.txt @@ -0,0 +1,102 @@ +/** +@defgroup chamoc Chamoc +@ingroup network + +## CHAMOC (Communication Handler for Addressing Management | Origin client) + +The module CHAMOC It's used for client-side communication for nib routing table. +In this tools will be there an compiled program called CHAMOC.out that has a client +interface with an m4a-24g board. The client node will be sending `chamoc_message_t` data. +that contains an `[Type message]` tell to the system how process the message. (Nib_add or Nib_del), +others field are the `[sequence number], [host ip address] to add as neighborh route, +and the `[network lenght prefix] generally is /64. + +### Steps to initialize the client socket + +- You should has the chamos_server in your m4a-24g board (Also, could run the chamoc_server inside to the test directory) +- Run the ./start_network.sh script and assign the board global address as argument (e.g: 2001:db8::1 64) +- Run the ./autoconfig.sh script +- Wait that nib_request is accepted. + +### start_network.sh + +When you are running start_network.sh and add an ipv6 address like this: +```sh + ./start_network.sh 2001:db8::1/64 +``` +you are assigning to the m4a-24g board (`usb-cdc element`) the global address to stablish the communication +in the wired interface. + +### Testing communication + +before to run the autoconfig.sh script you can do some pings to the m4a-24g board interface. +first follow these steps to locate, and do ping between both devices. + +- Locate your interface + +using net-tools +```sh + ifconfig + # Output + enx5a008df2d56b: flags=4163 mtu 1500 + inet 192.168.1.199 netmask 255.255.255.0 broadcast 192.168.1.255 + inet6 fe80::98eb:d858:51a0:dcc0 prefixlen 64 scopeid 0x20 + inet6 2001:db8::1 prefixlen 64 scopeid 0x0 + ether 5a:00:8d:f2:d5:6b txqueuelen 1000 (Ethernet) +... + +``` + +```sh + ifconfig +``` + +with ip address command. +```sh + ip address show + # Output + 22: enx5a008df2d56b: mtu 1500 qdisc fq_codel s + ... + valid_lft forever preferred_lft forever + inet6 2001:db8::1/64 scope global + valid_lft forever preferred_lft forever + inet6 fe80::98eb:d858:51a0:dcc0/64 scope link noprefixroute + valid_lft forever preferred_lft forever + +``` +@note : Observe that the interface has the wish global address (e.g: 2001:db8::1/64). + +- Do ping6 to the M4a-24g address `2001:db8::2/64` +```sh + ping 2001:db8::2 -c3 + # expected output + PING 2001:db8::2(2001:db8::2) 56 data bytes + 64 bytes from 2001:db8::2: icmp_seq=1 ttl=64 time=0.911 ms + 64 bytes from 2001:db8::2: icmp_seq=2 ttl=64 time=1.02 ms + 64 bytes from 2001:db8::2: icmp_seq=3 ttl=64 time=1.01 ms +``` + +### autoconfigure: + +Running the script you will has as result the compilation and execution to the client program CHAMOC.out +This test automatically will be start sending the nib_add and nib_del request taking as parameters. +`[Name of interface]``[ip address]``[prefix_len]. + +``sh + ./autoconfigure.sh + Waiting for network interface. + Start sending a nib add request + Bad Request, Trying Again # Timeout time to wait a response + Request Confirmed # Case when the request was correctly sent + Start sending a nib delete request + Request Confirmed +``` + +@note: the chamoc intercomunnication has five attempts to wait a response from the server + +### Running with chamoc_server + in the folder /test, there are an example of chamoc_server running. this will be + waiting and MSG_NIB_ADD or MSG_NIB_DEL, if these are received correctly response with a + MSG_ACK, in case that the message was wrong received, the server will send an MSG_NACK. + To start this server only has to run the script in the test_folder. +*/ diff --git a/dist/tools/chamoc/include/chamoc_msg.h b/dist/tools/chamoc/include/chamoc_msg.h new file mode 100644 index 000000000..ed7ff64d3 --- /dev/null +++ b/dist/tools/chamoc/include/chamoc_msg.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 Mesh4all.org + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @ingroup Chamoc CHAMOC Messages + * @brief Message structures and functions under CHAMOS, refers all intercomunication, sending + * and receiving messages from the server + * + * @{ + * + * @file + * + * @author eduazocar + */ + +#ifndef CHAMOC_MSG_H +#define CHAMOC_MSG_H + +#include +#include +#include +#include "client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief model of an ipv6 address + * + */ + +typedef union { + uint8_t in_8[16]; + uint16_t in_16[8]; + uint32_t in_32[4]; +} ipv6_addr_t; + +/** + * @brief Type of messages presents in CHAMOC and CHAMOS intercomunnication + * + */ + +enum { + MSG_ACK = 0, + MSG_NACK, + MSG_NIB_ADD, + MSG_NIB_DEL, +}; + +/** + * @brief Struct of a chamoc message, this contains the type of message, sequence number, ipv6 + * address and its prefix. + * + */ + +typedef struct { + uint8_t message; + uint8_t seqno; + uint8_t prefix; + ipv6_addr_t addr; +} chamoc_message_t; + +/** + * @brief Serializator to CHAMOS message + * @param[in] msg Contains a chamoc_message_t struct providing [type, seqno, prefix, ipv6 address] + * @param[out] buffer Output buffer with an byte array containing info about chamoc message + * @param[in] len size of the buffer + */ + +int serialize(chamoc_message_t msg, char *buffer, uint8_t len); + +/** + * @brief Connect both sockets client and server + * @param[in] client Chamos Socket client + * @param[inout] buffer Can return the last response of the server + * @param[in] len size of the buffer + */ + +int connect_chamos(chamos_client_t client, char *buffer, uint8_t len); + +/** + * @brief increment sequence number of an client; + * @param[in] client Chamos Socket client + */ + +uint8_t craft_seqno(chamos_client_t *client); + +/** + * @brief send message to the other socket + * @param[in] client Chamos Socket client + * @param[in] msg Process an serialized message and then send it to the server socket + * @param[in] len size of the buffer + */ + +int8_t send_message(chamos_client_t *client, uint8_t *msg, uint8_t len); + +#ifdef DEBUG_MODE +void printf_buff(char *buffer, uint8_t len); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CHAMOC_MSG_H */ +/** @} */ diff --git a/dist/tools/chamoc/include/client.h b/dist/tools/chamoc/include/client.h new file mode 100644 index 000000000..f60e3b2a0 --- /dev/null +++ b/dist/tools/chamoc/include/client.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 Mesh4all.org + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @ingroup Chamoc + * @brief CHAMOC client socket connection + * + * @{ + * + * @file + * + * @author eduazocar + */ + +#ifndef CLIENT_H +#define CLIENT_H + +#include +#include +#include +#include +#include + +#define MULTICAST_ADDR "ff02::1" + +/** + * @brief CHAMOC PORT defined as 6977 to testing, this is not official port + * + */ + +#define CHAMOC_PORT 6977 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Struct Properties or elements of a client + * + */ + +typedef struct { + uint8_t seqno; + uint8_t *pending_acks; + int socket; + struct sockaddr_in6 csock; +} chamos_client_t; + +/** + * @brief Create an socket client under CHAMOS + * @param[in] netif refers to the name of an interface in the system. example enp2s0 + */ + +chamos_client_t new_client(char* netif); + +#ifdef __cplusplus +} +#endif + +#endif /* CLIENT_H */ +/** @} */ diff --git a/dist/tools/chamoc/include/nib.h b/dist/tools/chamoc/include/nib.h new file mode 100644 index 000000000..6a007dd82 --- /dev/null +++ b/dist/tools/chamoc/include/nib.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 Mesh4all.org + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @ingroup CHAMOC CHAMOC NIB + * @brief Provide modes to generate an nib_add or nib_del request and send it to the server. + * + * @{ + * + * @file + * + * @author eduazocar + */ + +#ifndef NIB_H +#define NIB_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Function gives the necessary settings to provide an socket a nib add or nib_del address + * request. + * @param[in] Iface refers to the name of an interface in the system. example enp2s0 + * @param[in] prefix the prefix of the Ipv6 address + * @param[in] ip ipv6 address represented by a string + * @param[in] msg_type Represent the message type (NIB_ADD or NIB_DEL) + */ + +int nib_req(char *iface, char *ip, uint8_t prefix, uint8_t msg_type); + +#ifdef __cplusplus +} +#endif + +#endif /* NIB_H */ +/** @} */ diff --git a/dist/tools/chamoc/main.c b/dist/tools/chamoc/main.c new file mode 100644 index 000000000..a7b3da746 --- /dev/null +++ b/dist/tools/chamoc/main.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022 Mesh4all + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief CHAMOC_main + * + * @author eduazocar + */ + +#include +#include +#include +#include "chamoc_msg.h" +#include "nib.h" + +int main(int argc, char **argv) { + if (argc < 2 || argc > 6) { + printf("Usage [add, del] [iface] [ipv6_address] [prefix]\n"); + } + if (strcmp(argv[1], "nib") == 0) { + if (argc < 6) { + printf("Wrong Passed\n"); + } else if (strcmp(argv[2], "add") == 0) { + nib_req(argv[3], argv[4], (uint8_t)atoi(argv[5]), MSG_NIB_ADD); + } else if (strcmp(argv[2], "del") == 0) { + nib_req(argv[3], argv[4], (uint8_t)atoi(argv[5]), MSG_NIB_DEL); + } + } +} diff --git a/dist/tools/chamoc/nib.c b/dist/tools/chamoc/nib.c new file mode 100644 index 000000000..f319ceb41 --- /dev/null +++ b/dist/tools/chamoc/nib.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 Mesh4all + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief chamoc_nib + * + * @author eduazocar + */ + +#include +#include +#include +#include "client.h" +#include +#include +#include "chamoc_msg.h" + +int nib_req(char *iface, char *ip, uint8_t prefix, uint8_t msg_type) { + if (msg_type == 2 || 3) { + chamos_client_t client = new_client(iface); + char buff[19]; + chamoc_message_t message = { + .message = msg_type, + .prefix = prefix, + .seqno = 0, + }; + if (inet_pton(AF_INET6, ip, &message.addr) < 0) { + client.socket = -1; + }; + serialize(message, buff, sizeof(buff)); + connect_chamos(client, buff, sizeof(buff)); + close(client.socket); + return 1; + } else { + printf("Message type not supported in nib request\n"); + } +} diff --git a/dist/tools/chamoc/start_network.sh b/dist/tools/chamoc/start_network.sh new file mode 100755 index 000000000..208d44064 --- /dev/null +++ b/dist/tools/chamoc/start_network.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +SUDO=${SUDO:-sudo} + +USB_CDC_ECM_DIR="$(dirname "$(readlink -f "$0")")" + +INTERFACE_CHECK_COUNTER=5 # 5 attempts to find usb interface + +find_interface() { + INTERFACE=$(ls -A /sys/bus/usb/drivers/cdc_ether/*/net/ 2>/dev/null) + INTERFACE_CHECK=$(echo -n "${INTERFACE}" | head -c1 | wc -c) + if [ "${INTERFACE_CHECK}" -eq 0 ] && [ ${INTERFACE_CHECK_COUNTER} != 0 ]; then + # We want to have multiple opportunities to find the USB interface + # as sometimes it can take a few seconds for it to enumerate after + # the device has been flashed. + sleep 1 + ((INTERFACE_CHECK_COUNTER=INTERFACE_CHECK_COUNTER-1)) + find_interface + fi + INTERFACE=${INTERFACE%/} +} + +echo "Waiting for network interface." +find_interface + +if [ "${INTERFACE_CHECK}" -eq 0 ]; then + echo "Unable to find network interface" + exit 1 +else + echo "Found interface: ${INTERFACE}" +fi + +setup_interface() { + ${SUDO} sysctl -w net.ipv6.conf."${INTERFACE}".forwarding=1 + ${SUDO} sysctl -w net.ipv6.conf."${INTERFACE}".accept_ra=0 + ${SUDO} ip link set "${INTERFACE}" up + ${SUDO} ip a a 2001:db8::1/64 dev "${INTERFACE}" + ${SUDO} ip route add "${PREFIX}" via 2001:db8::1 dev "${INTERFACE}" +} + +cleanup_interface() { + ${SUDO} ip a d 2001:db8::1/64 dev "${INTERFACE}" + ${SUDO} ip route del "${PREFIX}" via 2001:db8::1 dev "${INTERFACE}" +} + +cleanup() { + echo "Cleaning up..." + cleanup_interface + trap "" INT QUIT TERM EXIT +} + + +PREFIX=$1 + +if [ -n "$2" ]; then + PORT=$2 +fi + +trap "cleanup" INT QUIT TERM EXIT + +setup_interface + +if [ -z "${PORT}" ]; then + echo "Network enabled over CDC-ECM" + echo "Press Return to stop" + read -r +else + "${USB_CDC_ECM_DIR}/../pyterm/pyterm" -p "${PORT}" +fi diff --git a/firmware/network/Kconfig b/firmware/network/Kconfig index 01d4e83e4..667fbb0be 100644 --- a/firmware/network/Kconfig +++ b/firmware/network/Kconfig @@ -3,4 +3,5 @@ rsource "udp_server/Kconfig" rsource "udp_client/Kconfig" rsource "radio/Kconfig" rsource "rpl_protocol/Kconfig" +rsource "chamos/Kconfig" endmenu diff --git a/firmware/network/chamos/Kconfig b/firmware/network/chamos/Kconfig new file mode 100644 index 000000000..45da41b2a --- /dev/null +++ b/firmware/network/chamos/Kconfig @@ -0,0 +1,5 @@ +menu "Chamos server" + config HEADER_ADDRESS_MULTICAST + string "MULTICAST IPV6 HEADER" + default "ff02::1" +endmenu diff --git a/firmware/network/chamos/Makefile b/firmware/network/chamos/Makefile new file mode 100644 index 000000000..48422e909 --- /dev/null +++ b/firmware/network/chamos/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/firmware/network/chamos/Makefile.dep b/firmware/network/chamos/Makefile.dep new file mode 100644 index 000000000..482d8da06 --- /dev/null +++ b/firmware/network/chamos/Makefile.dep @@ -0,0 +1,2 @@ +USEMODULE += gnrc_sock +USEMODULE += gnrc_sock_udp diff --git a/firmware/network/chamos/Makefile.include b/firmware/network/chamos/Makefile.include new file mode 100644 index 000000000..efec9da97 --- /dev/null +++ b/firmware/network/chamos/Makefile.include @@ -0,0 +1,2 @@ +USEMODULE_INCLUDES_chamos := $(LAST_MAKEFILEDIR)/include +USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_chamos) diff --git a/firmware/network/chamos/chamos.c b/firmware/network/chamos/chamos.c new file mode 100644 index 000000000..cbf826419 --- /dev/null +++ b/firmware/network/chamos/chamos.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2022 Mesh4all + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @brief CHAMOS Communication Handler for Addressing Management | Origin Server + * + * @author RocioRojas + */ +#include +#include +#include + +#include "chamos.h" +#include "net/gnrc/ipv6/nib/ft.h" +#include "xtimer.h" + +#define CHAMOS_MSG_QUEUE_SIZE (8) +#define SERVER_BUFFER_SIZE (100) + +/** + * @brief GNRC netif + */ +static gnrc_netif_t *_netif; +sock_udp_t chamos_sock = {}; +sock_udp_ep_t server; +bool chamos_running = false; + +uint8_t chamos_buffer[SERVER_BUFFER_SIZE]; +char chamos_stack[THREAD_STACKSIZE_DEFAULT]; +msg_t chamos_msg_queue[CHAMOS_MSG_QUEUE_SIZE]; +kernel_pid_t chamos_thread_pid; + +int server_send_ack(chamos_msg_t *msg, sock_udp_ep_t *remote, bool flag_ack_val) { + uint8_t buf[2]; + if (flag_ack_val) { + buf[0] = MSG_ACK; + } else { + buf[0] = MSG_NACK; + } + buf[1] = msg->seqno; + return sock_udp_send(&chamos_sock, buf, sizeof(buf), remote); +} + +int msg_process(chamos_msg_t *msg) { + switch (msg->msg_type) { + case MSG_NIB_ADD: + printf("Adding NIB entry\n"); + ipv6_addr_t next_hop = {.u8 = {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}; + if (gnrc_ipv6_nib_ft_add(&msg->ip, msg->ip_len, &next_hop, + _netif->pid, 0) < 0) { + return -ENOMEM; + } + break; + case MSG_NIB_DEL: + gnrc_ipv6_nib_ft_del(&msg->ip, msg->ip_len); + break; + + default: + return -EINVAL; + } + return 0; +} + +int chamos_parse_buff(chamos_msg_t *chamos_msg, uint8_t *buffer, size_t len) { + memset(chamos_msg, 0, sizeof(chamos_msg_t)); + if (len < 3) { + printf("Chamos: invalid message size! \n"); + return -EINVAL; + } + uint8_t type = buffer[0]; + uint8_t seqno = buffer[1]; + uint8_t ip_len = buffer[2]; + + switch (type) { + case MSG_NIB_ADD: + if (len < sizeof(chamos_msg_t)) { + printf("Chamos: NIB ADD invalid message size! \n"); + return -EINVAL; + } + chamos_msg->msg_type = type; + chamos_msg->seqno = seqno; + chamos_msg->ip_len = ip_len; + memcpy(&chamos_msg->ip, &buffer[3], sizeof(ipv6_addr_t)); + break; + case MSG_NIB_DEL: + if (len < sizeof(chamos_msg_t)) { + printf("Chamos: NIB DEL invalid message size! \n"); + return -EINVAL; + } + chamos_msg->msg_type = type; + chamos_msg->seqno = seqno; + chamos_msg->ip_len = ip_len; + memcpy(&chamos_msg->ip, &buffer[3], sizeof(ipv6_addr_t)); + break; + default: + printf("Invalid message type \n"); + return -EINVAL; + } + return 0; +} +void *chamos_thread(void *arg) { + (void)arg; + sock_udp_ep_t remote; + chamos_msg_t msg; + bool flag_ack = false; + while (true) { + int err_rx = sock_udp_recv(&chamos_sock, chamos_buffer, sizeof(chamos_buffer), + SOCK_NO_TIMEOUT, &remote); + if (err_rx < 0) { + if (err_rx == -EADDRINUSE) { + printf("Chamos: address is already used \n"); + } + if (err_rx == -EAFNOSUPPORT) { + printf("Chamos: endpoint is not supported.\n"); + } + if (err_rx == -EINVAL) { + printf( + "Chamos: remote has an invalid address or does not have a valid interface.\n"); + } + if (err_rx == -ENOMEM) { + printf("Chamos: not enough resources can be provided for `chamos_sock` to be " + "created \n"); + } + continue; + } + if (err_rx == 0) { + printf("Chamos: packet doesn't have a payload, dropping \n"); + continue; + } + if (chamos_parse_buff(&msg, chamos_buffer, err_rx) < 0) { + printf("Couldn't parse received message.\n"); + }else{ + flag_ack = true; + } + if (msg_process(&msg) < 0) { + printf("Couldn't process message.\n"); + flag_ack = false; + } + if (server_send_ack(&msg, &remote, flag_ack) < 0) { + printf("Couldn't send the ACK!\n"); + } + } + return NULL; +} + +int chamos_init(uint16_t port, gnrc_netif_t *netiface) { + server.port = port; + server.family = AF_INET6; + server.netif = netiface->pid; + ipv6_addr_t group; + msg_init_queue(chamos_msg_queue, CHAMOS_MSG_QUEUE_SIZE); + if (ipv6_addr_from_str(&group, CONFIG_HEADER_ADDRESS_MULTICAST) == NULL) { + printf("Invalid IPv6 group address"); + return -EINVAL; + } + if (gnrc_netif_ipv6_group_join(netiface, &group) < 0) { + printf("Couldn't join IPv6 group"); + return -1; + } + if (sock_udp_create(&chamos_sock, &server, NULL, 0) < 0) { + printf("Couldn't create UDP socket"); + return -1; + } + memcpy(&server.addr, &group, sizeof(ipv6_addr_t)); + chamos_running = true; + _netif = netiface; + printf("Success: started UDP server on port %u\n", server.port); + chamos_thread_pid = thread_create(chamos_stack, sizeof(chamos_stack), THREAD_PRIORITY_MAIN - 1, + THREAD_CREATE_STACKTEST, chamos_thread, NULL, "chamos"); + + return 0; +} diff --git a/firmware/network/chamos/doc.txt b/firmware/network/chamos/doc.txt new file mode 100644 index 000000000..ccfb74e2e --- /dev/null +++ b/firmware/network/chamos/doc.txt @@ -0,0 +1,31 @@ +/** +@defgroup Chamos Chamos +@ingroup network + +## What goes here? + +The module CHAMOS (Communication Handler for Addressing Management | Origin Server) It's used for server-side communication for nib routing table. + +### This module contains: + +- Turning on UDP socked. +- Receive the message. +- Process the message and adding it to NIB. +- Send the ack and the nack message to the client. + +### Frame: + +- First number is the ```type``` which is given by: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + MSG_NIB_ADD = 1, /**< Add entry to NIB */ + MSG_NIB_DEL = 2, /**< Delete entry from NIB */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- The second value is the sequence number ``` seqno ```. + +- The third value is the buffer size. + +- From the fourth value is the ipv6 address. + +*/ \ No newline at end of file diff --git a/firmware/network/chamos/include/chamos.h b/firmware/network/chamos/include/chamos.h new file mode 100644 index 000000000..788b3049a --- /dev/null +++ b/firmware/network/chamos/include/chamos.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022 Mesh4all + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @ingroup Chamos + * @{ + * @file + * @brief CHAMOS Communication Handler for Addressing Management | Origin Server + * @author RocioRojas + * + */ + +#ifndef CHAMOS_H +#define CHAMOS_H + +#include "net/gnrc.h" +#include "net/sock/udp.h" +#include "net/ipv6/addr.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @enum CHAMOS message types + */ +enum chamos_msg_types_t{ + MSG_ACK = 0, /**< Message acknowledged */ + MSG_NACK = 1, /**< Message not acknowledged */ + MSG_NIB_ADD = 2, /**< Add entry to NIB */ + MSG_NIB_DEL = 3, /**< Delete entry from NIB */ +}; + +/** + * @brief CHAMOS message + */ +typedef struct { + uint8_t msg_type; /**< Message type */ + uint8_t seqno; /**< Sequence number */ + uint8_t ip_len; /**< IP address pfx_len */ + ipv6_addr_t ip; /**< IP address */ +} chamos_msg_t; + +/** + * @brief this function is used to send ack + * + * @param msg [in] Frame + * @param remote [in] sock udp + * @param good_ack [in] bool + * @return int + */ +int server_send_ack(chamos_msg_t *msg, sock_udp_ep_t *remote, bool flag_ack_val); + +/** + * @brief this function is used to init the module + * + * @param netiface nteif + * @param port [in] port + * @return int + */ +int chamos_init(uint16_t port, gnrc_netif_t *netiface); + +#ifdef __cplusplus +} +#endif +#endif /* CHAMOS_H */ +/** @} */ diff --git a/tests/chamoc_server/.gitignore b/tests/chamoc_server/.gitignore new file mode 100644 index 000000000..9a66f1fdb --- /dev/null +++ b/tests/chamoc_server/.gitignore @@ -0,0 +1 @@ +chamoc_server \ No newline at end of file diff --git a/tests/chamoc_server/chamoc_server.c b/tests/chamoc_server/chamoc_server.c new file mode 100644 index 000000000..8f9f16082 --- /dev/null +++ b/tests/chamoc_server/chamoc_server.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 Mesh4all + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief chamoc_server_test + * + * @author eduazocar + */ + +#include +#include +#include +#include +#include +#include +#include +#include "chamoc_msg.h" + +void main(int argc, char **argv) { + if (argc != 2) { + printf("Usage: %s \n", argv[0]); + exit(0); + } + int port = atoi(argv[1]); + int sockfd; + struct sockaddr_in6 si_me, si_other; + char buffer[19]; + socklen_t addr_size; + + sockfd = socket(AF_INET6, SOCK_DGRAM, 0); + + int reuseaddr; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)); + memset(&si_me, '\0', sizeof(si_me)); + si_me.sin6_family = AF_INET6; + si_me.sin6_port = htons(port); + si_me.sin6_addr = in6addr_any; + bind(sockfd, (struct sockaddr *)&si_me, sizeof(si_me)); + addr_size = sizeof(si_other); + memset(buffer, 0, sizeof(buffer)); + printf("Server it's running\n"); + recvfrom(sockfd, buffer, 1024, 0, (struct sockaddr *)&si_other, &addr_size); + printf("Packet Received: "); + for (int i = 0; i < sizeof(buffer); i++) { + printf("%02hhx", (uint8_t)buffer[i]); + } + printf("\nServer address is: %s\n", + inet_ntop(AF_INET6, &si_me.sin6_addr, buffer, sizeof(buffer))); + printf("\nClient address is: %s\n", + inet_ntop(AF_INET6, &si_other.sin6_addr, buffer, sizeof(buffer))); + if (buffer[0] == MSG_NIB_ADD || MSG_NIB_DEL) { + buffer[0] = MSG_ACK; + } else { + buffer[0] = MSG_NACK; + } + sendto(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&si_other, addr_size); +} diff --git a/tests/chamoc_server/run.sh b/tests/chamoc_server/run.sh new file mode 100755 index 000000000..ab218bffe --- /dev/null +++ b/tests/chamoc_server/run.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +TEST_APP="chamoc_server" + +CC=gcc +CFLAGS=-o +INCLUDES_DIR=../../dist/tools/chamoc/include +INCLUDE=-I${INCLUDES_DIR} +TEST_FILE=chamoc_server.c +SERVER_PORT=6977 + +compile(){ + ${CC} ${INCLUDE} ${TEST_FILE} ${CFLAGS} ${TEST_APP} +} + +run(){ + ./${TEST_APP} ${SERVER_PORT} +} + +compile +run diff --git a/tests/chamos_test/Kconfig b/tests/chamos_test/Kconfig new file mode 100644 index 000000000..7dd039a70 --- /dev/null +++ b/tests/chamos_test/Kconfig @@ -0,0 +1 @@ +rsource "../../firmware/network/chamos/Kconfig" diff --git a/tests/chamos_test/Makefile b/tests/chamos_test/Makefile new file mode 100644 index 000000000..51cca34d4 --- /dev/null +++ b/tests/chamos_test/Makefile @@ -0,0 +1,7 @@ +include ../Makefile.tests_common + +USEMODULE += embunit +USEMODULE += chamos +USEMODULE += border_router + +include $(RIOTBASE)/Makefile.include diff --git a/tests/chamos_test/doc.txt b/tests/chamos_test/doc.txt new file mode 100644 index 000000000..f40fd2a0a --- /dev/null +++ b/tests/chamos_test/doc.txt @@ -0,0 +1,25 @@ +@defgroup chamos_test chamos test module +@ingroup test_group +@{ + +## Test Chamos module + +Here the unit tests are carried out on the chamos module. + +To test the code in automatic mode: + +```c +make flash test + +``` + +To test the code in interactive mode: + +```c +make flash term + +``` + +@} + + */ diff --git a/tests/chamos_test/main.c b/tests/chamos_test/main.c new file mode 100644 index 000000000..5bfd1133f --- /dev/null +++ b/tests/chamos_test/main.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2022 Mesh4all + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @brief chamos test + * + * @author RocioRojas + */ +#include +#include +#include +#include "embUnit.h" +#include "chamos.h" +#include "border_router.h" +#define SERVER_BUFFER_SIZE (100) + +uint8_t chamos_buffer_test[SERVER_BUFFER_SIZE]; + +void start_chamos(void) { + + gnrc_netif_t *iface; + iface = gnrc_netif_get_by_type(NETDEV_ANY, NETDEV_INDEX_ANY); + if (iface == NULL) { + return; + } + int err = chamos_init(1337, iface); + TEST_ASSERT_EQUAL_INT(0, err); +} + +void send_udp_message_to_chamos(void) { + chamos_msg_t msg; + msg.msg_type = MSG_NIB_ADD; + msg.seqno = 0; + msg.ip_len = 64; + ipv6_addr_from_str(&msg.ip, "2001:db8:"); + uint8_t buf[2]; + ssize_t res; +sock_udp_ep_t local = SOCK_IPV6_EP_ANY; + local.port = 1338; + sock_udp_ep_t remote = {.family = AF_INET6}; + + if (ipv6_addr_from_str((ipv6_addr_t *)&remote.addr, "::1") == NULL) { + puts("Error: unable to parse destination address"); + return; + } + if (ipv6_addr_is_link_local((ipv6_addr_t *)&remote.addr)) { + gnrc_netif_t *netif = gnrc_netif_get_by_type(NETDEV_ANY, NETDEV_INDEX_ANY); + remote.netif = (uint16_t)netif->pid; + } + remote.port = 1337; + + sock_udp_t sock; + + if (sock_udp_create(&sock, &local, NULL, 0) < 0) { + puts("Error creating UDP sock"); + return; + } + + if (sock_udp_send(&sock, &msg, sizeof(msg), &remote) < 0) { + puts("Error sending message"); + sock_udp_close(&sock); + return; + } + if ((res = sock_udp_recv(&sock, buf, sizeof(buf), 1 * US_PER_SEC, + NULL)) < 0) { + if (res == -ETIMEDOUT) { + puts("Timed out"); + } + else { + puts("Error receiving message"); + } + } + else { + printf("Received message: \""); + for (int i = 0; i < res; i++) { + printf("%x", buf[i]); + } + printf("\"\n"); + } + if (buf[0] == MSG_ACK){ + printf("Received ACK \n"); + }else{ + printf("Received NACK \n"); + } + sock_udp_close(&sock); + TEST_ASSERT_EQUAL_INT(MSG_ACK, buf[0]); +} + +Test *tests_chamos_tests(void) { + EMB_UNIT_TESTFIXTURES(fixtures){ + new_TestFixture(start_chamos), + new_TestFixture(send_udp_message_to_chamos), + }; + + EMB_UNIT_TESTCALLER(chamos_tests, NULL, NULL, fixtures); + + return (Test *)&chamos_tests; +} + +int main(void) { + TESTS_START(); + TESTS_RUN(tests_chamos_tests()); + TESTS_END(); + return 0; +} diff --git a/tests/chamos_test/test/01-run.py b/tests/chamos_test/test/01-run.py new file mode 100644 index 000000000..bccd6a160 --- /dev/null +++ b/tests/chamos_test/test/01-run.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2017 Freie Universität Berlin +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run_check_unittests + +if __name__ == "__main__": + sys.exit(run_check_unittests())