PUD: make getNodeInfoFromOlsr a bit more flexible
[olsrd.git] / lib / pud / src / nodeIdConversion.c
1 #include "nodeIdConversion.h"
2
3 /* Plugin includes */
4 #include "pud.h"
5 #include "configuration.h"
6 #include "networkInterfaces.h"
7
8 /* OLSR includes */
9
10 /* System includes */
11 #include <assert.h>
12 #include <arpa/inet.h>
13 #include <nmea/util.h>
14 #include <net/if.h>
15
16 /* ************************************************************************
17  * Node Information
18  * ************************************************************************ */
19
20 /**
21  Convert the node information to the node information for an OLSR message and
22  put it in the PUD message in the OLSR message. Also updates the PUD message
23  smask.
24
25  @param olsrGpsMessage
26  A pointer to the PUD message in the OLSR message
27  @param olsrMessageSize
28  The maximum number of bytes available for the olsrMessage
29
30  @return
31  The number of bytes written in the PUD message in the OLSR message (for ALL
32  the node information)
33  */
34 size_t setupNodeInfoForOlsr(PudOlsrWireFormat * olsrGpsMessage,
35                 unsigned int olsrMessageSize) {
36         NodeIdType nodeIdTypeNumber = getNodeIdTypeNumber();
37         unsigned char * buffer;
38         unsigned int length = 0;
39
40         olsrGpsMessage->nodeInfo.nodeIdType = nodeIdTypeNumber;
41         switch (nodeIdTypeNumber) {
42                 case PUD_NODEIDTYPE_MAC: /* hardware address */
43                         /* handled when the message is actually sent into OLSR, in the
44                          * pre-transmit hook */
45                         length = IFHWADDRLEN;
46                         break;
47
48                 case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
49                 case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
50                 case PUD_NODEIDTYPE_192:
51                 case PUD_NODEIDTYPE_193:
52                 case PUD_NODEIDTYPE_194:
53                         getNodeIdNumberForOlsrCache(&buffer, &length);
54                         memcpy(&olsrGpsMessage->nodeInfo.nodeId, buffer, length);
55                         break;
56
57                 case PUD_NODEIDTYPE_DNS: /* DNS name */
58                 {
59                         size_t nodeIdLength;
60                         unsigned char * nodeId = getNodeIdWithLength(&nodeIdLength);
61                         long charsAvailable = olsrMessageSize - (PUD_OLSRWIREFORMATSIZE
62                                         + sizeof(NodeInfo)
63                                         - sizeof(olsrGpsMessage->nodeInfo.nodeId)) - 1;
64
65                         length = nodeIdLength + 1;
66                         if (unlikely((long) length > charsAvailable)) {
67                                 length = charsAvailable;
68                                 pudError(false,
69                                                 "nodeId too long, truncated after %ld characters",
70                                                 charsAvailable);
71                         }
72
73                         memcpy(&olsrGpsMessage->nodeInfo.nodeId, nodeId, length);
74                         (&olsrGpsMessage->nodeInfo.nodeId)[length] = '\0';
75                 }
76                         break;
77
78                 case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
79                 case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
80                         /* explicit return: no nodeId information in message */
81                         return 0;
82
83                 default: /* unsupported */
84                         pudError(false, "Configuration of unsupported %s %u, using %u",
85                                         PUD_NODE_ID_TYPE_NAME, nodeIdTypeNumber,
86                                         ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
87                                                         : PUD_NODEIDTYPE_IPV6));
88
89                         /* fallback to IP address */
90                         olsrGpsMessage->nodeInfo.nodeIdType = (olsr_cnf->ip_version
91                                         == AF_INET) ? PUD_NODEIDTYPE_IPV4 : PUD_NODEIDTYPE_IPV6;
92
93                         /* explicit return: no nodeId information in message */
94                         return 0;
95         }
96
97         olsrGpsMessage->smask |= PUD_FLAGS_ID;
98         return ((sizeof(NodeInfo)
99                         - (sizeof(olsrGpsMessage->nodeInfo.nodeId) /* nodeId placeholder */))
100                         + length);
101 }
102
103 /**
104  Get a nodeId number (in string representation), using a certain number of
105  bytes, from the message of an OLSR message.
106
107  @param olsrGpsMessage
108  A pointer to the OLSR message
109  @param bytes
110  The number of bytes used by the number
111  @param nodeIdBuffer
112  The buffer in which to place the nodeId number in string representation
113  @param nodeIdBufferSize
114  The size of the buffer
115
116  @return
117  A pointer to the nodeId string representation (&nodeIdBuffer[0])
118  */
119 static char *getNodeIdNumberFromOlsr(PudOlsrWireFormat * olsrGpsMessage,
120                 unsigned int bytes, char *nodeIdBuffer, socklen_t nodeIdBufferSize) {
121         unsigned char * nodeId = &(olsrGpsMessage->nodeInfo.nodeId);
122         unsigned long long val = 0;
123         unsigned int i = 0;
124         int chars;
125
126         while (i < bytes) {
127                 val <<= 8;
128                 val += nodeId[i];
129                 i++;
130         }
131
132         chars = snprintf(nodeIdBuffer, nodeIdBufferSize, "%llu", val);
133         if (likely(chars < (int) nodeIdBufferSize)) {
134                 nodeIdBuffer[chars] = '\0';
135         } else {
136                 nodeIdBuffer[nodeIdBufferSize] = '\0';
137         }
138         return &nodeIdBuffer[0];
139 }
140
141 /**
142  Convert the node information of an OLSR message to the node information for
143  internal use and set it up in the given buffers.
144
145  @param olsrMessage
146  A pointer to the OLSR message. Used to be able to retrieve the IP address of
147  the sender.
148  @param olsrGpsMessage
149  A pointer to the GPS message in the OLSR message
150  @param nodeIdBuffer
151  A pointer to the buffer in which the nodeId string representation can be
152  written. Not written to when nodeIdBuffer or nodeId is NULL or when
153  nodeIdBufferSize is zero.
154  @param nodeIdBufferSize
155  The size of the nodeIdBuffer. When zero then nodeIdBuffer and nodeId are not
156  written to.
157  @param nodeId
158  A pointer to a variable in which to store the pointer to the buffer in which
159  the nodeId string representation can be found. Not written to when nodeIdBuffer
160  or nodeId is NULL or when nodeIdBufferSize is zero.
161  @param nodeIdTypeString
162  A pointer to the buffer in which the nodeIdType string representation can be
163  written (the buffer needs to be at least PUD_TX_NODEIDTYPE_DIGITS + 1 bytes).
164  When NULL then the nodeIdType string is not written.
165  */
166 void getNodeInfoFromOlsr(const union olsr_message *olsrMessage,
167                 PudOlsrWireFormat *olsrGpsMessage, char *nodeIdBuffer,
168                 unsigned int nodeIdBufferSize, const char **nodeId,
169                 char *nodeIdTypeString) {
170         int chars;
171
172         if (olsrGpsMessage->smask & PUD_FLAGS_ID) {
173                 if (likely(nodeIdBuffer && (nodeIdBufferSize != 0) && nodeId)) {
174                         switch (olsrGpsMessage->nodeInfo.nodeIdType) {
175                                 case PUD_NODEIDTYPE_MAC: /* hardware address */
176                                 {
177                                         unsigned char * hwAddr = &olsrGpsMessage->nodeInfo.nodeId;
178
179                                         assert (IFHWADDRLEN == 6);
180
181                                         chars = snprintf(nodeIdBuffer, nodeIdBufferSize,
182                                                         "%02x:%02x:%02x:%02x:%02x:%02x", hwAddr[0], hwAddr[1],
183                                                         hwAddr[2], hwAddr[3], hwAddr[4], hwAddr[5]);
184                                         if (likely(chars < (int) nodeIdBufferSize)) {
185                                                 nodeIdBuffer[chars] = '\0';
186                                         } else {
187                                                 nodeIdBuffer[nodeIdBufferSize - 1] = '\0';
188                                         }
189                                         *nodeId = &nodeIdBuffer[0];
190                                 }
191                                         break;
192
193                                 case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
194                                         *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 7,
195                                                         nodeIdBuffer, nodeIdBufferSize);
196                                         break;
197
198                                 case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
199                                         *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 8,
200                                                         nodeIdBuffer, nodeIdBufferSize);
201                                         break;
202
203                                 case PUD_NODEIDTYPE_DNS: /* DNS name */
204                                         *nodeId = (char *) &olsrGpsMessage->nodeInfo.nodeId;
205                                         break;
206
207                                 case PUD_NODEIDTYPE_192:
208                                 case PUD_NODEIDTYPE_193:
209                                         *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 3,
210                                                         nodeIdBuffer, nodeIdBufferSize);
211                                         break;
212
213                                 case PUD_NODEIDTYPE_194:
214                                         *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 2,
215                                                         nodeIdBuffer, nodeIdBufferSize);
216                                         break;
217
218                                 case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
219                                 case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
220                                         goto noId;
221
222                                 default: /* unsupported */
223                                         pudError(false,
224                                                         "Reception of unsupported %s %u, using %u",
225                                                         PUD_NODE_ID_TYPE_NAME,
226                                                         olsrGpsMessage->nodeInfo.nodeIdType,
227                                                         ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
228                                                                         : PUD_NODEIDTYPE_IPV6));
229                                         olsrGpsMessage->smask &= ~PUD_FLAGS_ID;
230                                         goto noId;
231                         }
232                 }
233
234                 /* nodeIdType */
235                 if (nodeIdTypeString) {
236                         chars = snprintf(nodeIdTypeString, PUD_TX_NODEIDTYPE_DIGITS + 1, "%u",
237                                         olsrGpsMessage->nodeInfo.nodeIdType);
238                         if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
239                                 nodeIdTypeString[chars] = '\0';
240                         } else {
241                                 nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
242                         }
243                 }
244
245                 return;
246         }
247
248         /* message has NO nodeId information */
249         noId: {
250                 /* nodeIdType */
251                 if (nodeIdTypeString) {
252                         chars = snprintf(&nodeIdTypeString[0], PUD_TX_NODEIDTYPE_DIGITS + 1,
253                                         "%u",((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
254                                         : PUD_NODEIDTYPE_IPV6));
255                         if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
256                                 nodeIdTypeString[chars] = '\0';
257                         } else {
258                                 nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
259                         }
260                 }
261
262                 if (likely(nodeIdBuffer && (nodeIdBufferSize != 0) && nodeId)) {
263                         const void * addr;
264
265                         if (olsr_cnf->ip_version == AF_INET) {
266                                 addr = (const void *) &olsrMessage->v4.originator;
267                         } else {
268                                 addr = (const void *) &olsrMessage->v6.originator;
269                         }
270
271                         *nodeId = inet_ntop(olsr_cnf->ip_version, addr, nodeIdBuffer,
272                                         nodeIdBufferSize);
273                 }
274         }
275
276         return;
277 }