ab7f6affae46a80a9d6033481393b43aa7d0c802
[olsrd.git] / lib / pud / src / pud.c
1 #include "pud.h"
2
3 /* Plugin includes */
4 #include "dedup.h"
5 #include "networkInterfaces.h"
6 #include "configuration.h"
7 #include "gpsConversion.h"
8 #include "receiver.h"
9 #include "state.h"
10 #include "compiler.h"
11
12 /* OLSRD includes */
13 #include "olsr.h"
14 #include "ipcalc.h"
15 #include "net_olsr.h"
16 #include "parser.h"
17
18 /* System includes */
19
20 /** The size of the buffer in which the received NMEA string is stored */
21 #define BUFFER_SIZE_RX_NMEA             2048
22
23 /** The size of the buffer in which the received downlink message is stored */
24 #define BUFFER_SIZE_RX_DOWNLINK 2048
25
26 /** The size of the buffer in which the converted NMEA string is assembled for
27  * transmission over OSLR */
28 #define BUFFER_SIZE_TX_OLSR     512
29
30 /** The de-duplication list */
31 static DeDupList deDupList;
32
33 /**
34  Report a plugin error.
35
36  @param useErrno
37  when true then errno is used in the error message; the error reason is also
38  reported.
39  @param format
40  a pointer to the format string
41  @param ...
42  arguments to the format string
43  */
44 void pudError(bool useErrno, const char *format, ...) {
45         char strDesc[256];
46         char *stringErr = NULL;
47
48         if (useErrno) {
49                 stringErr = strerror(errno);
50         }
51
52         if ((format == NULL) || (*format == '\0')) {
53                 if (useErrno) {
54                         olsr_printf(0, "%s: %s\n", PUD_PLUGIN_ABBR, stringErr);
55                 } else {
56                         olsr_printf(0, "%s: Unknown error\n", PUD_PLUGIN_ABBR);
57                 }
58         } else {
59                 va_list arglist;
60
61                 va_start(arglist, format);
62                 vsnprintf(strDesc, sizeof(strDesc), format, arglist);
63                 va_end(arglist);
64
65                 strDesc[sizeof(strDesc) - 1] = '\0'; /* Ensures null termination */
66
67                 if (useErrno) {
68                         olsr_printf(0, "%s: %s: %s\n", PUD_PLUGIN_ABBR, strDesc, stringErr);
69                 } else {
70                         olsr_printf(0, "%s: %s\n", PUD_PLUGIN_ABBR, strDesc);
71                 }
72         }
73 }
74
75 /**
76  Sends a buffer out on all transmit interfaces
77
78  @param buffer
79  the buffer
80  @param bufferLength
81  the number of bytes in the buffer
82  */
83 static void sendToAllTxInterfaces(unsigned char *buffer,
84                 unsigned int bufferLength) {
85         union olsr_sockaddr * txAddress;
86         TRxTxNetworkInterface *txNetworkInterfaces = getTxNetworkInterfaces();
87         while (txNetworkInterfaces != NULL) {
88                 TRxTxNetworkInterface *networkInterface = txNetworkInterfaces;
89                 errno = 0;
90                 txAddress = getTxMcAddr();
91                 if (sendto(networkInterface->socketFd, buffer, bufferLength, 0,
92                                 (struct sockaddr *) &txAddress->in, sizeof(txAddress->in)) < 0) {
93                         pudError(true, "Transmit error on interface %s",
94                                         (char *) &networkInterface->name);
95                 }
96                 txNetworkInterfaces = networkInterface->next;
97         }
98 }
99
100 /**
101  Called by OLSR core when a packet for the plugin is received from the OLSR
102  network. It converts the packet into an NMEA string and transmits it over all
103  transmit non-OLSR network interfaces.
104
105  @param olsrMessage
106  a pointer to the received OLSR message
107  @param in_if
108  a pointer to the OLSR network interface on which the packet was received
109  @param ipaddr
110  a pointer to the IP address of the sender
111
112  @return
113  - true when the packet was processed
114  - false otherwise
115  */
116 bool packetReceivedFromOlsr(union olsr_message *olsrMessage,
117                 struct interface *in_if __attribute__ ((unused)), union olsr_ip_addr *ipaddr __attribute__ ((unused))) {
118         const union olsr_ip_addr * originator = getOlsrMessageOriginator(
119                         olsr_cnf->ip_version, olsrMessage);
120         unsigned int transmitStringLength;
121         unsigned char buffer[BUFFER_SIZE_TX_OLSR];
122
123         /* when we do not loopback then check if the message originated from this
124          * node: back off */
125         if (!getUseLoopback() && ipequal(originator, &olsr_cnf->main_addr)) {
126                 return false;
127         }
128
129         /* do deduplication: when we have already seen this message from the same
130          * originator then just back off */
131         if (likely(getUseDeDup())) {
132                 if (isInDeDupList(&deDupList, olsrMessage)) {
133                         return false;
134                 }
135
136                 addToDeDup(&deDupList, olsrMessage);
137         }
138
139         transmitStringLength = gpsFromOlsr(olsrMessage, &buffer[0], sizeof(buffer));
140         if (unlikely(transmitStringLength == 0)) {
141                 return false;
142         }
143
144         sendToAllTxInterfaces(&buffer[0], transmitStringLength);
145
146         return true;
147 }
148
149 /**
150  Called by OLSR core when a packet for the plugin is received from the downlink.
151  It unpacks the messages and distributes them into OLSR and on the LAN.
152
153  @param skfd
154  the socket file descriptor on which the packet is received
155  @param data
156  a pointer to the network interface structure on which the packet was received
157  @param flags
158  unused
159  */
160 static void packetReceivedFromDownlink(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
161         if (skfd >= 0) {
162                 unsigned char rxBuffer[BUFFER_SIZE_RX_DOWNLINK];
163                 ssize_t rxCount = 0;
164                 ssize_t rxIndex = 0;
165                 struct sockaddr sender;
166                 socklen_t senderSize = sizeof(sender);
167                 bool addedToDedup = false;
168
169                 /* Receive the captured Ethernet frame */
170                 memset(&sender, 0, senderSize);
171                 errno = 0;
172                 rxCount = recvfrom(skfd, &rxBuffer[0], (sizeof(rxBuffer) - 1), 0,
173                                 &sender, &senderSize);
174                 if (rxCount < 0) {
175                         pudError(true, "Receive error in %s, ignoring message.", __func__);
176                         return;
177                 }
178
179                 while (rxIndex < rxCount) {
180                         UplinkMessage * msg = (UplinkMessage *) &rxBuffer[rxIndex];
181                         uint8_t type;
182                         uint16_t uplinkMessageLength;
183                         uint16_t olsrMessageLength;
184                         bool ipv6;
185                         union olsr_message * olsrMessage;
186
187                         type = getUplinkMessageType(&msg->header);
188                         if (type != POSITION) {
189                                 pudError(false, "Received wrong type (%d) in %s,"
190                                                 " ignoring the rest of the messages.", type, __func__);
191                                 return;
192                         }
193
194                         olsrMessageLength = getUplinkMessageLength(&msg->header);
195                         uplinkMessageLength = olsrMessageLength + sizeof(UplinkHeader);
196
197                         if (unlikely((rxIndex + uplinkMessageLength) > rxCount)) {
198                                 pudError(false, "Received wrong length (%d) in %s,"
199                                                 " ignoring the rest of the messages.", olsrMessageLength,
200                                                 __func__);
201                                 return;
202                         }
203
204                         rxIndex += uplinkMessageLength;
205
206                         ipv6 = getUplinkMessageIPv6(&msg->header);
207                         if (unlikely(ipv6 && (olsr_cnf->ip_version != AF_INET6))) {
208                                 pudError(false, "Received wrong IPv6 status (%s) in %s,"
209                                                 " ignoring message.", (ipv6 ? "true" : "false"),
210                                                 __func__);
211                                 continue;
212                         }
213
214                         olsrMessage = &msg->msg.olsrMessage;
215
216                         /* we now have a position update (olsrMessage) of a certain length
217                          * (olsrMessageLength). this needs to be transmitted over OLSR and on the LAN */
218
219                         if (likely(getUseDeDup()) && !isInDeDupList(&deDupList, olsrMessage)) {
220                                 addToDeDup(&deDupList, olsrMessage);
221                                 addedToDedup = true;
222                         }
223
224                         if (likely(addedToDedup) || unlikely(!getUseDeDup())) {
225                                 /* send out over OLSR interfaces */
226                                 int r;
227                                 struct interface *ifn;
228                                 for (ifn = ifnet; ifn; ifn = ifn->int_next) {
229                                         r = net_outbuffer_push(ifn, olsrMessage, olsrMessageLength);
230                                         if (r != (int) olsrMessageLength) {
231                                                 pudError(
232                                                                 false,
233                                                                 "Could not send to OLSR interface %s: %s"
234                                                                                 " (length=%u, r=%d)",
235                                                                 ifn->int_name,
236                                                                 ((r == -1) ? "no buffer was found" :
237                                                                         (r == 0) ? "there was not enough room in the buffer" :
238                                                                                         "unknown reason"), olsrMessageLength, r);
239                                         }
240                                 }
241
242                                 /* send out over tx interfaces */
243                                 (void) packetReceivedFromOlsr(olsrMessage, NULL, NULL);
244                         }
245                 }
246         }
247 }
248
249 /**
250  Called by OLSR core when a packet for the plugin is received from the non-OLSR
251  network. It converts the packet into the internal OLSR wire format for a
252  position update and transmits it over all OLSR network interfaces.
253
254  @param skfd
255  the socket file descriptor on which the packet is received
256  @param data
257  a pointer to the network interface structure on which the packet was received
258  @param flags
259  unused
260  */
261 static void packetReceivedForOlsr(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
262         if (skfd >= 0) {
263                 unsigned char rxBuffer[BUFFER_SIZE_RX_NMEA];
264                 ssize_t rxCount;
265                 struct sockaddr sender;
266                 socklen_t senderSize = sizeof(sender);
267
268                 assert(data != NULL);
269
270                 /* Receive the captured Ethernet frame */
271                 memset(&sender, 0, senderSize);
272                 errno = 0;
273                 rxCount = recvfrom(skfd, &rxBuffer[0], (sizeof(rxBuffer) - 1), 0,
274                                 &sender, &senderSize);
275                 if (rxCount < 0) {
276                         pudError(true, "Receive error in %s, ignoring message.", __func__);
277                         return;
278                 }
279
280                 /* make sure the string is null-terminated */
281                 rxBuffer[rxCount] = '\0';
282
283                 /* only accept messages from configured IP addresses */
284                 if (!isRxAllowedSourceIpAddress(&sender)) {
285                         return;
286                 }
287
288                 /* we have the received string in the rxBuffer now */
289
290                 /* hand the NMEA information to the receiver */
291                 (void) receiverUpdateGpsInformation(&rxBuffer[0], rxCount);
292         }
293 }
294
295 /**
296  Initialise the plugin: check the configuration, initialise the NMEA parser,
297  create network interface sockets, hookup the plugin to OLSR and setup data
298  that can be setup in advance.
299
300  @return
301  - false upon failure
302  - true otherwise
303  */
304 bool initPud(void) {
305         if (!checkConfig()) {
306                 pudError(false, "Invalid configuration");
307                 goto error;
308         }
309
310         initState();
311
312         if (!initDeDupList(&deDupList, getDeDupDepth())) {
313                 pudError(false, "Could not initialise de-duplication list");
314                 goto error;
315         }
316
317         if (!startReceiver()) {
318                 pudError(false, "Could not start receiver");
319                 goto error;
320         }
321
322         /*
323          * Creates receive and transmit sockets and register the receive sockets
324          * with the OLSR stack
325          */
326         if (!createNetworkInterfaces(&packetReceivedForOlsr,
327                         &packetReceivedFromDownlink)) {
328                 pudError(false, "Could not create require network interfaces");
329                 goto error;
330         }
331
332         if (!checkRunSetup()) {
333                 pudError(false, "Invalid configuration");
334                 goto error;
335         }
336
337         /*
338          * Tell OLSR to call packetReceivedFromOlsr when the packets for this
339          * plugin arrive from the OLSR network
340          */
341         olsr_parser_add_function(&packetReceivedFromOlsr, PUD_OLSR_MSG_TYPE);
342
343         return true;
344
345         error: closePud();
346         return false;
347 }
348
349 /**
350  Stop the plugin: shut down all created network interface sockets and destroy
351  the NMEA parser.
352  */
353 void closePud(void) {
354         closeNetworkInterfaces();
355         stopReceiver();
356         destroyDeDupList(&deDupList);
357 }