PUD: make all variables static
[olsrd.git] / lib / pud / src / nodeIdConversion.c
1 #include "nodeIdConversion.h"
2
3 /* Plugin includes */
4 #include "pud.h"
5 #include "nmeaTools.h"
6 #include "configuration.h"
7 #include "networkInterfaces.h"
8
9 /* OLSR includes */
10
11 /* System includes */
12 #include <assert.h>
13 #include <string.h>
14 #include <arpa/inet.h>
15
16 /* ************************************************************************
17  * Node Information
18  * ************************************************************************ */
19
20 /** The size of the cached nodeId buffer */
21 #define PUD_CACHED_NODEID_BUFFER_SIZE 16
22
23 /** The cached nodeId buffer: contains a pre-processed version of the nodeId
24  in order to improve performance. It is currently used for nodeIdTypes
25  PUD_NODEIDTYPE_MSISDN, PUD_NODEIDTYPE_TETRA, PUD_NODEIDTYPE_192,
26  PUD_NODEIDTYPE_193 (so basically for numbers that will not change) */
27 static unsigned char cachedNodeIdBuffer[PUD_CACHED_NODEID_BUFFER_SIZE];
28
29 /** The number of bytes stored in cachedNodeIdBuffer */
30 static unsigned char cachedNodeIdBufferLength = 0;
31
32 /**
33  Check a nodeId number for validity and if valid set it up in the
34  cachedNodeIdBuffer. The valid range for the number is [min, max].
35
36  @param min
37  The lower bound for a valid number
38  @param max
39  The upper bound for a valid number
40  @param bytes
41  The number of bytes used by the number in the wire format
42
43  @return
44  - true when the number is valid
45  - false otherwise
46  */
47 static bool setupNodeIdNumberForOlsr(unsigned long long min,
48                 unsigned long long max, unsigned int bytes) {
49         unsigned long long val;
50
51         assert (bytes <= PUD_CACHED_NODEID_BUFFER_SIZE);
52
53         if (!readULL(PUD_NODE_ID_NAME, (char *) getNodeId(), &val)) {
54                 return false;
55         }
56
57         if ((val >= min) && (val <= max)) {
58                 int i = bytes - 1;
59                 while (i >= 0) {
60                         cachedNodeIdBuffer[i] = val & 0xff;
61                         val >>= 8;
62                         i--;
63                 }
64
65                 assert(val == 0);
66
67                 cachedNodeIdBufferLength = bytes;
68                 return true;
69         }
70
71         pudError(false, "%s value %llu is out of range [%llu,%llu]",
72                         PUD_NODE_ID_NAME, val, min, max);
73         return false;
74 }
75
76 /**
77  Validate whether the configured nodeId is valid w.r.t. the configured
78  nodeIdType
79
80  @return
81  - true when ok
82  - false on failure
83  */
84 bool validateNodeId(NodeIdType nodeIdTypeNumber) {
85         switch (nodeIdTypeNumber) {
86                 case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
87                 case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
88                 case PUD_NODEIDTYPE_MAC: /* hardware address */
89                         /* explicit return: configured nodeId is not relevant */
90                         return true;
91
92                 case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
93                         return setupNodeIdNumberForOlsr(0LL, 999999999999999LL, 7);
94
95                 case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
96                         return setupNodeIdNumberForOlsr(0LL, 99999999999999999LL, 8);
97
98                 case PUD_NODEIDTYPE_DNS: /* DNS name */
99                         return !hasInvalidNmeaChars((char *) getNodeId(), PUD_NODE_ID_NAME);
100
101                 case PUD_NODEIDTYPE_192:
102                         return setupNodeIdNumberForOlsr(0LL, 9999999LL, 3);
103
104                 case PUD_NODEIDTYPE_193:
105                         return setupNodeIdNumberForOlsr(0LL, 999999LL, 3);
106
107                 case PUD_NODEIDTYPE_194:
108                         return setupNodeIdNumberForOlsr(1LL, 8191LL, 2);
109
110                 default: /* unsupported */
111                         /* explicit return: configured nodeId is not relevant, will
112                          * fallback to IP addresses */
113                         return true;
114         }
115
116         return false;
117 }
118
119 /**
120  Convert the node information to the node information for an OLSR message and
121  put it in the PUD message in the OLSR message. Also updates the PUD message
122  smask.
123
124  @param olsrGpsMessage
125  A pointer to the PUD message in the OLSR message
126  @param olsrMessageSize
127  The maximum number of bytes available for the olsrMessage
128
129  @return
130  The number of bytes written in the PUD message in the OLSR message (for ALL
131  the node information)
132  */
133 size_t setupNodeInfoForOlsr(PudOlsrWireFormat * olsrGpsMessage,
134                 unsigned int olsrMessageSize) {
135         NodeIdType nodeIdTypeNumber = getNodeIdTypeNumber();
136         size_t length = 0;
137
138         olsrGpsMessage->nodeInfo.nodeIdType = nodeIdTypeNumber;
139         switch (nodeIdTypeNumber) {
140                 case PUD_NODEIDTYPE_MAC: /* hardware address */
141                         /* handled when the message is actually sent into OLSR, in the
142                          * pre-transmit hook */
143                         length = PUD_HWADDR_SIZE;
144                         break;
145
146                 case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
147                 case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
148                 case PUD_NODEIDTYPE_192:
149                 case PUD_NODEIDTYPE_193:
150                 case PUD_NODEIDTYPE_194:
151                         length = cachedNodeIdBufferLength;
152                         memcpy(&olsrGpsMessage->nodeInfo.nodeId, &cachedNodeIdBuffer[0],
153                                         length);
154                         break;
155
156                 case PUD_NODEIDTYPE_DNS: /* DNS name */
157                 {
158                         size_t nodeIdLength;
159                         unsigned char * nodeId = getNodeIdWithLength(&nodeIdLength);
160                         long charsAvailable = olsrMessageSize - (PUD_OLSRWIREFORMATSIZE
161                                         + sizeof(NodeInfo)
162                                         - sizeof(olsrGpsMessage->nodeInfo.nodeId)) - 1;
163
164                         length = nodeIdLength + 1;
165                         if (unlikely((long) length > charsAvailable)) {
166                                 length = charsAvailable;
167                                 pudError(false,
168                                                 "nodeId too long, truncated after %ld characters",
169                                                 charsAvailable);
170                         }
171
172                         memcpy(&olsrGpsMessage->nodeInfo.nodeId, nodeId, length);
173                         (&olsrGpsMessage->nodeInfo.nodeId)[length] = '\0';
174                 }
175                         break;
176
177                 case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
178                 case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
179                         /* explicit return: no nodeId information in message */
180                         return 0;
181
182                 default: /* unsupported */
183                         pudError(false, "Configuration of unsupported %s %u, using %u",
184                                         PUD_NODE_ID_TYPE_NAME, nodeIdTypeNumber,
185                                         ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
186                                                         : PUD_NODEIDTYPE_IPV6));
187
188                         /* fallback to IP address */
189                         olsrGpsMessage->nodeInfo.nodeIdType = (olsr_cnf->ip_version
190                                         == AF_INET) ? PUD_NODEIDTYPE_IPV4 : PUD_NODEIDTYPE_IPV6;
191
192                         /* explicit return: no nodeId information in message */
193                         return 0;
194         }
195
196         olsrGpsMessage->smask |= PUD_FLAGS_ID;
197         return ((sizeof(NodeInfo)
198                         - (sizeof(olsrGpsMessage->nodeInfo.nodeId) /* nodeId placeholder */))
199                         + length);
200 }
201
202 /**
203  Get a nodeId number (in string representation), using a certain number of
204  bytes, from the message of an OLSR message.
205
206  @param olsrGpsMessage
207  A pointer to the OLSR message
208  @param bytes
209  The number of bytes used by the number
210  @param nodeIdBuffer
211  The buffer in which to place the nodeId number in string representation
212  @param nodeIdBufferSize
213  The size of the buffer
214
215  @return
216  A pointer to the nodeId string representation (&nodeIdBuffer[0])
217  */
218 static char *getNodeIdNumberFromOlsr(PudOlsrWireFormat * olsrGpsMessage,
219                 unsigned int bytes, char *nodeIdBuffer, socklen_t nodeIdBufferSize) {
220         unsigned char * nodeId = &(olsrGpsMessage->nodeInfo.nodeId);
221         unsigned long long val = 0;
222         unsigned int i = 0;
223         int chars;
224
225         while (i < bytes) {
226                 val <<= 8;
227                 val += nodeId[i];
228                 i++;
229         }
230
231         chars = snprintf(nodeIdBuffer, nodeIdBufferSize, "%llu", val);
232         if (likely(chars < (int) nodeIdBufferSize)) {
233                 nodeIdBuffer[chars] = '\0';
234         } else {
235                 nodeIdBuffer[nodeIdBufferSize] = '\0';
236         }
237         return &nodeIdBuffer[0];
238 }
239
240 /**
241  Convert the node information of an OLSR message to the node information for
242  internal use and set it up in the given buffers.
243
244  @param olsrMessage
245  A pointer to the OLSR message. Used to be able to retrieve the IP address of
246  the sender.
247  @param olsrGpsMessage
248  A pointer to the GPS message in the OLSR message
249  @param nodeId
250  A pointer a variable in which to store the pointer to the buffer in which the
251  nodeId string representation can be found
252  @param nodeIdBuffer
253  A pointer to the buffer in which the nodeId string representation can be
254  written
255  @param nodeIdBufferSize
256  The size of the nodeIdBuffer
257  @param nodeIdTypeString
258  A pointer to the buffer in which the nodeIdType string representation can be
259  written
260  */
261 void getNodeInfoFromOlsr(const union olsr_message *olsrMessage,
262                 PudOlsrWireFormat *olsrGpsMessage, char *nodeIdBuffer,
263                 unsigned int nodeIdBufferSize, const char **nodeId,
264                 char *nodeIdTypeString) {
265         int chars;
266
267         if (olsrGpsMessage->smask & PUD_FLAGS_ID) {
268                 switch (olsrGpsMessage->nodeInfo.nodeIdType) {
269                         case PUD_NODEIDTYPE_MAC: /* hardware address */
270                         {
271                                 unsigned char * hwAddr = &olsrGpsMessage->nodeInfo.nodeId;
272
273                                 assert (PUD_HWADDR_SIZE == 6);
274
275                                 chars = snprintf(nodeIdBuffer, nodeIdBufferSize,
276                                                 "%02x:%02x:%02x:%02x:%02x:%02x", hwAddr[0], hwAddr[1],
277                                                 hwAddr[2], hwAddr[3], hwAddr[4], hwAddr[5]);
278                                 if (likely(chars < (int) nodeIdBufferSize)) {
279                                         nodeIdBuffer[chars] = '\0';
280                                 } else {
281                                         nodeIdBuffer[nodeIdBufferSize - 1] = '\0';
282                                 }
283                                 *nodeId = &nodeIdBuffer[0];
284                         }
285                                 break;
286
287                         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
288                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 7,
289                                                 nodeIdBuffer, nodeIdBufferSize);
290                                 break;
291
292                         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
293                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 8,
294                                                 nodeIdBuffer, nodeIdBufferSize);
295                                 break;
296
297                         case PUD_NODEIDTYPE_DNS: /* DNS name */
298                                 *nodeId = (char *) &olsrGpsMessage->nodeInfo.nodeId;
299                                 break;
300
301                         case PUD_NODEIDTYPE_192:
302                         case PUD_NODEIDTYPE_193:
303                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 3,
304                                                 nodeIdBuffer, nodeIdBufferSize);
305                                 break;
306
307                         case PUD_NODEIDTYPE_194:
308                                 *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 2,
309                                                 nodeIdBuffer, nodeIdBufferSize);
310                                 break;
311
312                         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
313                         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
314                                 goto noId;
315
316                         default: /* unsupported */
317                                 pudError(false,
318                                                 "Reception of unsupported %s %u, using %u",
319                                                 PUD_NODE_ID_TYPE_NAME,
320                                                 olsrGpsMessage->nodeInfo.nodeIdType,
321                                                 ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
322                                                                 : PUD_NODEIDTYPE_IPV6));
323                                 olsrGpsMessage->smask &= ~PUD_FLAGS_ID;
324                                 goto noId;
325                 }
326
327                 /* nodeIdType */
328                 chars = snprintf(nodeIdTypeString, PUD_TX_NODEIDTYPE_DIGITS + 1, "%u",
329                                 olsrGpsMessage->nodeInfo.nodeIdType);
330                 if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
331                         nodeIdTypeString[chars] = '\0';
332                 } else {
333                         nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
334                 }
335
336                 return;
337         }
338
339         /* message has NO nodeId information */
340         noId: {
341                 const void * addr;
342
343                 /* nodeIdType */
344                 chars = snprintf(&nodeIdTypeString[0], PUD_TX_NODEIDTYPE_DIGITS + 1,
345                                 "%u", ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
346                                 : PUD_NODEIDTYPE_IPV6));
347                 if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
348                         nodeIdTypeString[chars] = '\0';
349                 } else {
350                         nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
351                 }
352
353                 if (olsr_cnf->ip_version == AF_INET) {
354                         addr = (const void *) &olsrMessage->v4.originator;
355                 } else {
356                         addr = (const void *) &olsrMessage->v6.originator;
357                 }
358
359                 *nodeId = inet_ntop(olsr_cnf->ip_version, addr, nodeIdBuffer,
360                                 nodeIdBufferSize);
361         }
362
363         return;
364 }