5 #include "networkInterfaces.h"
6 #include "configuration.h"
7 #include "gpsConversion.h"
22 /** The size of the buffer in which the received NMEA string is stored */
23 #define BUFFER_SIZE_RX_NMEA 2048
25 /** The size of the buffer in which the received downlink message is stored */
26 #define BUFFER_SIZE_RX_DOWNLINK 2048
28 /** The size of the buffer in which the converted NMEA string is assembled for
29 * transmission over OSLR */
30 #define BUFFER_SIZE_TX_OLSR 512
32 /** The de-duplication list */
33 static DeDupList deDupList;
35 /** When false, use olsr_printf in pudError, otherwise use olsr_syslog */
36 static bool pudErrorUseSysLog = false;
39 Report a plugin error.
42 when true then errno is used in the error message; the error reason is also
45 a pointer to the format string
47 arguments to the format string
49 void pudError(bool useErrno, const char *format, ...) {
52 const char *stringErr;
54 if ((format == NULL) || (*format == '\0')) {
58 stringErr = "Unknown error";
60 stringErr = strerror(errno);
65 va_start(arglist, format);
66 vsnprintf(strDesc, sizeof(strDesc), format, arglist);
71 stringErr = strerror(errno);
78 if (!pudErrorUseSysLog)
79 olsr_printf(0, "%s: %s%s%s\n", PUD_PLUGIN_ABBR, strDesc, colon, stringErr);
81 olsr_syslog(OLSR_LOG_ERR, "%s: %s%s%s\n", PUD_PLUGIN_ABBR, strDesc, colon, stringErr);
85 Sends a buffer out on all transmit interfaces
90 the number of bytes in the buffer
92 static void sendToAllTxInterfaces(unsigned char *buffer,
93 unsigned int bufferLength) {
94 union olsr_sockaddr * txAddress = getTxMcAddr();
97 TRxTxNetworkInterface *txNetworkInterfaces = getTxNetworkInterfaces();
99 if (txAddress->in.sa_family == AF_INET) {
100 addr = &txAddress->in4;
101 addrSize = sizeof(struct sockaddr_in);
103 addr = &txAddress->in6;
104 addrSize = sizeof(struct sockaddr_in6);
107 while (txNetworkInterfaces != NULL) {
108 TRxTxNetworkInterface *networkInterface = txNetworkInterfaces;
110 if (sendto(networkInterface->socketFd, buffer, bufferLength, 0, addr, addrSize) < 0) {
111 pudError(true, "Transmit error on interface %s", &networkInterface->name[0]);
113 txNetworkInterfaces = networkInterface->next;
118 Called by OLSR core when a packet for the plugin is received from the OLSR
119 network. It converts the packet into an NMEA string and transmits it over all
120 transmit non-OLSR network interfaces.
123 a pointer to the received OLSR message
125 a pointer to the OLSR network interface on which the packet was received
127 a pointer to the IP address of the sender
130 - true when the packet was processed
133 bool packetReceivedFromOlsr(union olsr_message *olsrMessage,
134 struct interface *in_if __attribute__ ((unused)), union olsr_ip_addr *ipaddr __attribute__ ((unused))) {
135 const union olsr_ip_addr * originator = getOlsrMessageOriginator(
136 olsr_cnf->ip_version, olsrMessage);
137 unsigned int transmitStringLength;
138 unsigned char buffer[BUFFER_SIZE_TX_OLSR];
140 /* when we do not loopback then check if the message originated from this
142 if (!getUseLoopback() && ipequal(originator, &olsr_cnf->main_addr)) {
146 /* do deduplication: when we have already seen this message from the same
147 * originator then just back off */
148 if (likely(getUseDeDup())) {
149 if (isInDeDupList(&deDupList, olsrMessage)) {
153 addToDeDup(&deDupList, olsrMessage);
156 transmitStringLength = gpsFromOlsr(olsrMessage, &buffer[0], sizeof(buffer));
157 assert(transmitStringLength <= sizeof(buffer));
158 if (unlikely(transmitStringLength == 0)) {
162 sendToAllTxInterfaces(&buffer[0], transmitStringLength);
168 Called by OLSR core when a packet for the plugin is received from the downlink.
169 It unpacks the messages and distributes them into OLSR and on the LAN.
172 the socket file descriptor on which the packet is received
174 a pointer to the network interface structure on which the packet was received
178 static void packetReceivedFromDownlink(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
180 unsigned char rxBuffer[BUFFER_SIZE_RX_DOWNLINK];
184 /* Receive the captured Ethernet frame */
186 rxCount = recvfrom(skfd, &rxBuffer[0], (sizeof(rxBuffer) - 1), 0, NULL, NULL);
188 pudError(true, "Receive error in %s, ignoring message.", __func__);
192 while (rxIndex < rxCount) {
193 UplinkMessage * msg = (UplinkMessage *) &rxBuffer[rxIndex];
195 uint16_t uplinkMessageLength;
196 uint16_t olsrMessageLength;
198 union olsr_message * olsrMessage;
200 type = getUplinkMessageType(&msg->header);
201 olsrMessageLength = getUplinkMessageLength(&msg->header);
202 uplinkMessageLength = olsrMessageLength + sizeof(UplinkHeader);
204 if (unlikely((rxIndex + uplinkMessageLength) > rxCount)) {
205 pudError(false, "Received wrong length (%d) in %s,"
206 " ignoring the rest of the messages.", olsrMessageLength,
211 rxIndex += uplinkMessageLength;
213 if (type != POSITION) {
214 pudError(false, "Received wrong type (%d) in %s,"
215 " ignoring message.", type, __func__);
219 ipv6 = getUplinkMessageIPv6(&msg->header);
220 if (unlikely(!ipv6 && (olsr_cnf->ip_version == AF_INET6)) || unlikely(ipv6 && (olsr_cnf->ip_version == AF_INET))) {
221 pudError(false, "Received wrong IPv6 status (%s) in %s,"
222 " ignoring message.", (ipv6 ? "true" : "false"),
227 olsrMessage = &msg->msg.olsrMessage;
229 /* we now have a position update (olsrMessage) of a certain length
230 * (olsrMessageLength). this needs to be transmitted over OLSR and on the LAN */
232 /* send out over OLSR interfaces (only when the smart gateway system is enabled) */
233 if (olsr_cnf->smart_gw_active)
236 struct interface *ifn;
237 for (ifn = ifnet; ifn; ifn = ifn->int_next) {
238 /* force the pending buffer out if there's not enough space for our message */
239 if ((int)olsrMessageLength > net_outbuffer_bytes_left(ifn)) {
242 r = net_outbuffer_push(ifn, olsrMessage, olsrMessageLength);
243 if (r != (int) olsrMessageLength) {
246 "Could not send to OLSR interface %s: %s"
247 " (length=%u, r=%d)",
249 ((r == -1) ? "no buffer was found" :
250 (r == 0) ? "there was not enough room in the buffer" :
251 "unknown reason"), olsrMessageLength, r);
256 /* send out over tx interfaces */
257 (void) packetReceivedFromOlsr(olsrMessage, NULL, NULL);
263 Called by OLSR core when a packet for the plugin is received from the non-OLSR
264 network. It converts the packet into the internal OLSR wire format for a
265 position update and transmits it over all OLSR network interfaces.
268 the socket file descriptor on which the packet is received
270 a pointer to the network interface structure on which the packet was received
274 static void packetReceivedForOlsr(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
276 unsigned char rxBuffer[BUFFER_SIZE_RX_NMEA];
278 union olsr_sockaddr sender;
279 socklen_t senderSize = sizeof(sender);
281 assert(data != NULL);
283 /* Receive the captured Ethernet frame */
284 memset(&sender, 0, senderSize);
286 rxCount = recvfrom(skfd, &rxBuffer[0], (sizeof(rxBuffer) - 1), 0,
287 (struct sockaddr *)&sender, &senderSize);
289 pudError(true, "Receive error in %s, ignoring message.", __func__);
293 /* make sure the string is null-terminated */
294 rxBuffer[rxCount] = '\0';
296 /* only accept messages from configured IP addresses */
297 if (!isRxAllowedSourceIpAddress(&sender)) {
301 /* we have the received string in the rxBuffer now */
303 /* hand the NMEA information to the receiver */
304 (void) receiverUpdateGpsInformation(&rxBuffer[0], rxCount);
309 * Timer callback that reads the pud position file
311 static void pud_read_position_file(void *context __attribute__ ((unused))) {
312 updatePositionFromFile();
316 /** The timer cookie, used to trace back the originator in debug */
317 static struct olsr_cookie_info *pud_position_file_timer_cookie = NULL;
320 static struct timer_entry * pud_position_file_timer = NULL;
323 Initialise the plugin: check the configuration, initialise the NMEA parser,
324 create network interface sockets, hookup the plugin to OLSR and setup data
325 that can be setup in advance.
332 unsigned long long positionFilePeriod;
334 if (!checkConfig()) {
335 pudError(false, "Invalid configuration");
341 if (!initDeDupList(&deDupList, getDeDupDepth())) {
342 pudError(false, "Could not initialise de-duplication list");
346 if (!startPositionFile()) {
350 if (!startReceiver()) {
351 pudError(false, "Could not start receiver");
356 * Creates receive and transmit sockets and register the receive sockets
357 * with the OLSR stack
359 if (!createNetworkInterfaces(&packetReceivedForOlsr,
360 &packetReceivedFromDownlink)) {
361 pudError(false, "Could not create require network interfaces");
365 if (!checkRunSetup()) {
366 pudError(false, "Invalid configuration");
371 * Tell OLSR to call packetReceivedFromOlsr when the packets for this
372 * plugin arrive from the OLSR network
374 olsr_parser_add_function(&packetReceivedFromOlsr, PUD_OLSR_MSG_TYPE);
376 /* switch to syslog logging, load was succesful */
377 pudErrorUseSysLog = !olsr_cnf->no_fork;
379 positionFilePeriod = getPositionFilePeriod();
380 if (getPositionFile() && positionFilePeriod) {
381 if (pud_position_file_timer_cookie == NULL) {
382 pud_position_file_timer_cookie = olsr_alloc_cookie("pud position file", OLSR_COOKIE_TYPE_TIMER);
383 if (pud_position_file_timer_cookie == NULL) {
384 pudError(false, "Could not allocate pud position file cookie");
388 if (pud_position_file_timer == NULL) {
389 pud_position_file_timer = olsr_start_timer(positionFilePeriod, 0, OLSR_TIMER_PERIODIC, &pud_read_position_file,
390 NULL, pud_position_file_timer_cookie);
391 if (pud_position_file_timer == NULL) {
392 pudError(false, "Could not start pud position file timer");
405 Stop the plugin: shut down all created network interface sockets and destroy
408 void closePud(void) {
409 if (pud_position_file_timer != NULL) {
410 olsr_stop_timer(pud_position_file_timer);
411 pud_position_file_timer = NULL;
413 if (pud_position_file_timer_cookie != NULL) {
414 olsr_free_cookie(pud_position_file_timer_cookie);
415 pud_position_file_timer_cookie = NULL;
418 closeNetworkInterfaces();
420 destroyDeDupList(&deDupList);