/* Linux TUN device Test Port for Eclipse Titan * (C) 2017 by Harald Welte * Licensed under Eclipse Public License - v1.0 or GPLv2, at your choice */ #include #include #include #include #include #include #include #include #include #include #include "TunDevice_PT.hh" #include "TunDevice_PortType.hh" #include "TunDevice_Types.hh" namespace TunDevice__PortType { /* private helper to open the device */ void TunDevice__PT_PROVIDER::open_device(void) { struct ifreq ifr; int fd, err; log("%s: entering", __func__); if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { TTCN_error("Unable to open /dev/net/tun"); return; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; if (tun_data.dev) strncpy(ifr.ifr_name, tun_data.dev, IFNAMSIZ); if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) { TTCN_error("Unable to issue TUNSETIFF ioctl() for '%s'", ifr.ifr_name); close(fd); return; } log("%s: Successfully opened TUN device", __func__); if (!tun_data.dev) tun_data.dev = strdup(ifr.ifr_name); else strcpy(tun_data.dev, ifr.ifr_name); tun_data.fd = fd; Handler_Add_Fd_Read(fd); } /* private helper to closethe device */ void TunDevice__PT_PROVIDER::close_device(void) { if (tun_data.fd != -1) { close(tun_data.fd); tun_data.fd = -1; } } /* private log helper */ void TunDevice__PT_PROVIDER::log(const char *fmt, ...) { if (debugging) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("Tun test port (%s): ", get_name()); va_list args; va_start(args, fmt); TTCN_Logger::log_event_va_list(fmt, args); va_end(args); TTCN_Logger::end_event(); } } /* private log helper */ void TunDevice__PT_PROVIDER::logHex(const char *prompt, const OCTETSTRING& msg) { if (debugging) { TTCN_Logger::begin_event(TTCN_DEBUG); TTCN_Logger::log_event("Size: %d,\nMSG: ", msg.lengthof()); for (int i = 0; i < msg.lengthof(); i++) TTCN_Logger::log_event(" %02x", ((const unsigned char *)msg)[i]); TTCN_Logger::log_event("\n"); TTCN_Logger::end_event(); } } /* constructor */ TunDevice__PT_PROVIDER::TunDevice__PT_PROVIDER(const char *par_port_name) : PORT(par_port_name) { tun_data.fd = -1; tun_data.dev = NULL; debugging = false; } /* destructor */ TunDevice__PT_PROVIDER::~TunDevice__PT_PROVIDER() { close_device(); free(tun_data.dev); tun_data.dev = NULL; } /* setting a port parameter via config file */ void TunDevice__PT_PROVIDER::set_parameter(const char *parameter_name, const char *parameter_value) { //printf("%s(%s, %s)\n", __func__, parameter_name, parameter_value); if (!strcmp(parameter_name, "device_name")) tun_data.dev = strdup(parameter_value); if (!strcmp(parameter_name, "debugging")) debugging = true; } /*void TunDevice__PT_PROVIDER::Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable, boolean is_error) {}*/ void TunDevice__PT_PROVIDER::Handle_Fd_Event_Error(int fd) { } void TunDevice__PT_PROVIDER::Handle_Fd_Event_Writable(int fd) { } /* function called if FD becomes readable: pull packet from chardev */ void TunDevice__PT_PROVIDER::Handle_Fd_Event_Readable(int fd) { uint8_t msg[0xffff]; int rc; log("entering %s", __func__); rc = read(tun_data.fd, msg, sizeof(msg)); if (rc < 0) { TTCN_error("reading from tun"); return; } TunDevice__Types::Tun__recv recv; recv.msg() = OCTETSTRING(rc, msg); logHex("receveid data: ", recv.msg()); incoming_message(recv); } /*void TunDevice__PT_PROVIDER::Handle_Timeout(double time_since_last_call) {}*/ /* user map's to our test port -> open */ void TunDevice__PT_PROVIDER::user_map(const char *system_port) { open_device(); } /* user unmap's our test port -> close */ void TunDevice__PT_PROVIDER::user_unmap(const char *system_port) { close_device(); } /* user calls 'start' on given port */ void TunDevice__PT_PROVIDER::user_start() { } /* user calls 'stop' on given port */ void TunDevice__PT_PROVIDER::user_stop() { } /* user wants to send something through the port */ void TunDevice__PT_PROVIDER::outgoing_send(const TunDevice__Types::Tun__send& send_par) { int rc; log("entering %s", __func__); logHex("sending data: ", send_par.msg()); rc = write(tun_data.fd, (const char*)(const unsigned char*)send_par.msg(), send_par.msg().lengthof()); if (rc < 0) { TTCN_error("writing to tun"); return; } log("Nr of bytes sent = %d", rc); log("leaving %s", __func__); } } /* end of namespace */