PUD: push olsrMessagePayload determination down into getNodeInfoFromOlsr
[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 nodeIdBuffer
149  A pointer to the buffer in which the nodeId string representation can be
150  written. Not written to when nodeIdBuffer or nodeId is NULL or when
151  nodeIdBufferSize is zero.
152  @param nodeIdBufferSize
153  The size of the nodeIdBuffer. When zero then nodeIdBuffer and nodeId are not
154  written to.
155  @param nodeId
156  A pointer to a variable in which to store the pointer to the buffer in which
157  the nodeId string representation can be found. Not written to when nodeIdBuffer
158  or nodeId is NULL or when nodeIdBufferSize is zero.
159  @param nodeIdTypeString
160  A pointer to the buffer in which the nodeIdType string representation can be
161  written (the buffer needs to be at least PUD_TX_NODEIDTYPE_DIGITS + 1 bytes).
162  When NULL then the nodeIdType string is not written.
163  */
164 void getNodeInfoFromOlsr(union olsr_message *olsrMessage, char *nodeIdBuffer,
165                 unsigned int nodeIdBufferSize, const char **nodeId,
166                 char *nodeIdTypeString) {
167         int chars;
168
169         PudOlsrWireFormat *olsrGpsMessage;
170
171         /* determine the originator of the message */
172         if (olsr_cnf->ip_version == AF_INET) {
173                 olsrGpsMessage = (PudOlsrWireFormat *) &olsrMessage->v4.message;
174         } else {
175                 olsrGpsMessage = (PudOlsrWireFormat *) &olsrMessage->v6.message;
176         }
177
178         if (olsrGpsMessage->smask & PUD_FLAGS_ID) {
179                 if (likely(nodeIdBuffer && (nodeIdBufferSize != 0) && nodeId)) {
180                         switch (olsrGpsMessage->nodeInfo.nodeIdType) {
181                                 case PUD_NODEIDTYPE_MAC: /* hardware address */
182                                 {
183                                         unsigned char * hwAddr = &olsrGpsMessage->nodeInfo.nodeId;
184
185                                         assert (IFHWADDRLEN == 6);
186
187                                         chars = snprintf(nodeIdBuffer, nodeIdBufferSize,
188                                                         "%02x:%02x:%02x:%02x:%02x:%02x", hwAddr[0], hwAddr[1],
189                                                         hwAddr[2], hwAddr[3], hwAddr[4], hwAddr[5]);
190                                         if (likely(chars < (int) nodeIdBufferSize)) {
191                                                 nodeIdBuffer[chars] = '\0';
192                                         } else {
193                                                 nodeIdBuffer[nodeIdBufferSize - 1] = '\0';
194                                         }
195                                         *nodeId = &nodeIdBuffer[0];
196                                 }
197                                         break;
198
199                                 case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
200                                         *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 7,
201                                                         nodeIdBuffer, nodeIdBufferSize);
202                                         break;
203
204                                 case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
205                                         *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 8,
206                                                         nodeIdBuffer, nodeIdBufferSize);
207                                         break;
208
209                                 case PUD_NODEIDTYPE_DNS: /* DNS name */
210                                         *nodeId = (char *) &olsrGpsMessage->nodeInfo.nodeId;
211                                         break;
212
213                                 case PUD_NODEIDTYPE_192:
214                                 case PUD_NODEIDTYPE_193:
215                                         *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 3,
216                                                         nodeIdBuffer, nodeIdBufferSize);
217                                         break;
218
219                                 case PUD_NODEIDTYPE_194:
220                                         *nodeId = getNodeIdNumberFromOlsr(olsrGpsMessage, 2,
221                                                         nodeIdBuffer, nodeIdBufferSize);
222                                         break;
223
224                                 case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
225                                 case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
226                                         goto noId;
227
228                                 default: /* unsupported */
229                                         pudError(false,
230                                                         "Reception of unsupported %s %u, using %u",
231                                                         PUD_NODE_ID_TYPE_NAME,
232                                                         olsrGpsMessage->nodeInfo.nodeIdType,
233                                                         ((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
234                                                                         : PUD_NODEIDTYPE_IPV6));
235                                         olsrGpsMessage->smask &= ~PUD_FLAGS_ID;
236                                         goto noId;
237                         }
238                 }
239
240                 /* nodeIdType */
241                 if (nodeIdTypeString) {
242                         chars = snprintf(nodeIdTypeString, PUD_TX_NODEIDTYPE_DIGITS + 1, "%u",
243                                         olsrGpsMessage->nodeInfo.nodeIdType);
244                         if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
245                                 nodeIdTypeString[chars] = '\0';
246                         } else {
247                                 nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
248                         }
249                 }
250
251                 return;
252         }
253
254         /* message has NO nodeId information */
255         noId: {
256                 /* nodeIdType */
257                 if (nodeIdTypeString) {
258                         chars = snprintf(&nodeIdTypeString[0], PUD_TX_NODEIDTYPE_DIGITS + 1,
259                                         "%u",((olsr_cnf->ip_version == AF_INET) ? PUD_NODEIDTYPE_IPV4
260                                         : PUD_NODEIDTYPE_IPV6));
261                         if (likely(chars < PUD_TX_NODEIDTYPE_DIGITS)) {
262                                 nodeIdTypeString[chars] = '\0';
263                         } else {
264                                 nodeIdTypeString[PUD_TX_NODEIDTYPE_DIGITS] = '\0';
265                         }
266                 }
267
268                 if (likely(nodeIdBuffer && (nodeIdBufferSize != 0) && nodeId)) {
269                         const void * addr;
270
271                         if (olsr_cnf->ip_version == AF_INET) {
272                                 addr = (const void *) &olsrMessage->v4.originator;
273                         } else {
274                                 addr = (const void *) &olsrMessage->v6.originator;
275                         }
276
277                         *nodeId = inet_ntop(olsr_cnf->ip_version, addr, nodeIdBuffer,
278                                         nodeIdBufferSize);
279                 }
280         }
281
282         return;
283 }