5G-MAG Reference Tools - MBMS Modem
Gw.cpp
Go to the documentation of this file.
1 // 5G-MAG Reference Tools
2 // MBMS Modem Process
3 //
4 // Copyright (C) 2021 Klaus Kühnhammer (Österreichische Rundfunksender GmbH & Co KG)
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU Affero General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Affero General Public License for more details.
15 //
16 // You should have received a copy of the GNU Affero General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19 
20 #include "Gw.h"
21 
22 #include <arpa/inet.h>
23 #include <fcntl.h>
24 #include <linux/if_tun.h>
25 #include <net/if.h>
26 #include <netinet/ip.h>
27 #include <netinet/udp.h>
28 #include <sys/ioctl.h>
29 #include <sys/socket.h>
30 
31 #include <algorithm>
32 #include <cerrno>
33 
34 #include "spdlog/spdlog.h"
35 
36 void Gw::write_pdu_mch(uint32_t mch_idx, uint32_t lcid, srsran::unique_byte_buffer_t pdu) {
37  char* err_str = nullptr;
38  if (pdu->N_bytes > 2) {
39  spdlog::debug("GW: RX MCH PDU ({} B), MCH idx {}. Stack latency: {} us", pdu->N_bytes, mch_idx, pdu->get_latency_us().count());
40 
41  if (_tun_fd < 0) {
42  spdlog::warn("TUN/TAP not up - dropping gw RX message\n");
43  } else {
44  auto ip_hdr = reinterpret_cast<iphdr*>(pdu->msg);
45  if (ip_hdr->protocol == 17 /*UDP*/) {
46  auto udp_hdr = reinterpret_cast<udphdr*>(pdu->msg + 4U * ip_hdr->ihl);
47  char dest[INET6_ADDRSTRLEN] = ""; // NOLINT
48  inet_ntop(AF_INET, (const void*)&ip_hdr->daddr, dest, sizeof(dest));
49 
50  _phy.set_dest_for_lcid(mch_idx, lcid, std::string(dest) + ":" + std::to_string(ntohs(udp_hdr->dest)));
51 
52  auto ptr = reinterpret_cast<uint16_t*>(ip_hdr);
53  int32_t sum = 0;
54  sum += *ptr++; // ihl / version / dscp
55  sum += *ptr++; // total len
56  sum += *ptr++; // id
57  sum += *ptr++; // frag offset
58  sum += *ptr++; // ttl + protocol
59  ptr++; // skip checksum
60  sum += *ptr++; // src
61  sum += *ptr++; // src
62  sum += *ptr++; // dst
63  sum += *ptr; // dst
64 
65  sum = (sum >> 16) + (sum & 0xffff);
66  sum += (sum >> 16);
67 
68  uint16_t chk = ~sum;
69  if (ip_hdr->check != chk) {
70  spdlog::info("Wrong IP header checksum {}, should be {}. Correcting.", ip_hdr->check, chk);
71  ip_hdr->check = chk;
72  }
73  }
74 
75  _wr_mutex.lock();
76  int n = write(_tun_fd, pdu->msg, pdu->N_bytes);
77  _wr_mutex.unlock();
78 
79  if (n > 0 && (pdu->N_bytes != static_cast<uint32_t>(n))) {
80  spdlog::warn("DL TUN/TAP short write");
81  }
82  if (n == 0) {
83  spdlog::warn("DL TUN/TAP 0 write");
84  }
85  if (n < 0) {
86  err_str = strerror(errno);
87  spdlog::warn("DL TUN/TAP write error {}", err_str);
88  }
89  }
90  }
91 }
92 
94  if (_tun_fd != -1) {
95  close(_tun_fd);
96  }
97 }
98 
99 void Gw::init() {
100  char* err_str = nullptr;
101  struct ifreq ifr = {};
102 
103  _tun_fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
104  spdlog::info("TUN file descriptor {}", _tun_fd);
105  if (0 > _tun_fd) {
106  err_str = strerror(errno);
107  spdlog::error("Failed to open TUN device {}", err_str);
108  _tun_fd = -1;
109  }
110 
111  std::string dev_name = "mbms_modem_tun";
112  if (nullptr != std::getenv("MODEM_TUN_INTERFACE")) {
113  dev_name = std::getenv("MODEM_TUN_INTERFACE");
114  }
115 
116  memset(&ifr, 0, sizeof(ifr));
117  ifr.ifr_flags = IFF_UP | IFF_TUN | IFF_NO_PI;
118  strncpy(ifr.ifr_ifrn.ifrn_name, dev_name.c_str(),
119  std::min(dev_name.length(), static_cast<size_t>(IFNAMSIZ - 1)));
120  ifr.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = 0;
121 
122  if (0 > ioctl(_tun_fd, TUNSETIFF, &ifr)) {
123  err_str = strerror(errno);
124  spdlog::error("Failed to set TUN device name {}", err_str);
125  close(_tun_fd);
126  _tun_fd = -1;
127  }
128 
129  if (0 > ioctl(_tun_fd, TUNSETPERSIST, 1)) {
130  err_str = strerror(errno);
131  spdlog::warn("Failed to set TUNSETPERSIST\n");
132  }
133 }
int32_t _tun_fd
Definition: Gw.h:78
Phy & _phy
Definition: Gw.h:79
virtual ~Gw()
Default destructor.
Definition: Gw.cpp:93
void write_pdu_mch(uint32_t mch_idx, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override
Handle a MCH PDU.
Definition: Gw.cpp:36
void init()
Creates the TUN interface according to params from Cfg.
Definition: Gw.cpp:99
std::mutex _wr_mutex
Definition: Gw.h:77
void set_dest_for_lcid(uint32_t mch_idx, int lcid, std::string dest)
Definition: Phy.h:177