PUD: add wireformat libraries
[olsrd.git] / lib / pud / wireformat / src / wireFormat.c
1 #include <OlsrdPudWireFormat/wireFormat.h>
2 #include <OlsrdPudWireFormat/compiler.h>
3
4 /* ************************************************************************
5  * VALIDITY TIME CACHE
6  * ************************************************************************ */
7
8 static unsigned long long cachedValidityTimeMsn[16];
9
10 static bool cachedValidityTimeMsnValid = false;
11
12 /**
13  Setup of cache of calculated most significant nibble results of the validity
14  time calculation to speed up run-time calculations. This method has to be
15  called once upon first use of ValidityTime functions.
16  */
17 static void setupCachedValidityTimeMsn(void) {
18         unsigned int msn;
19         for (msn = 0; msn < 16; msn++) {
20                 cachedValidityTimeMsn[msn] = PUD_VALIDITY_TIME_FROM_OLSR(msn, 0);
21         }
22         cachedValidityTimeMsnValid = true;
23 }
24
25 /* ************************************************************************
26  * NODEID CACHE
27  * ************************************************************************ */
28
29 /** The size of the cached nodeId buffer */
30 #define PUD_CACHED_NODEID_BUFFER_SIZE 16
31
32 /** The cached nodeId buffer: contains a pre-processed version of the nodeId
33  in order to improve performance. It is currently used for nodeIdTypes
34  PUD_NODEIDTYPE_MSISDN, PUD_NODEIDTYPE_TETRA, PUD_NODEIDTYPE_192,
35  PUD_NODEIDTYPE_193 (so basically for numbers that will not change) */
36 static unsigned char cachedNodeIdBuffer[PUD_CACHED_NODEID_BUFFER_SIZE];
37
38 /** The number of bytes stored in cachedNodeIdBuffer */
39 static unsigned int cachedNodeIdBufferLength = 0;
40
41 /**
42  @param nodeId
43  A pointer to the location in which to store a pointer to the nodeId cache
44  buffer
45  @param nodeIdSize
46  A pointer to the location in which to store the number of bytes in the buffer
47  */
48 static inline void getNodeIdNumberForOlsrCache(unsigned char ** nodeId,
49                 unsigned int * nodeIdSize) {
50         *nodeId = &cachedNodeIdBuffer[0];
51         *nodeIdSize = cachedNodeIdBufferLength;
52 }
53
54 /**
55  Check a nodeId number for validity and if valid set it up in the
56  cachedNodeIdBuffer. The valid range for the number is [min, max].
57
58  @param val
59  The value to setup in the cache
60  @param min
61  The lower bound for a valid number
62  @param max
63  The upper bound for a valid number
64  @param bytes
65  The number of bytes used by the number in the wire format
66
67  @return
68  - true when the number is valid
69  - false otherwise
70  */
71 bool setupNodeIdNumberForOlsrCache(unsigned long long val,
72                 unsigned long long min, unsigned long long max, unsigned int bytes) {
73         assert(bytes <= PUD_CACHED_NODEID_BUFFER_SIZE);
74
75         if ((val >= min) && (val <= max)) {
76                 int i = bytes - 1;
77                 while (i >= 0) {
78                         cachedNodeIdBuffer[i] = val & 0xff;
79                         val >>= 8;
80                         i--;
81                 }
82
83                 assert(val == 0);
84
85                 cachedNodeIdBufferLength = bytes;
86                 return true;
87         }
88
89         return false;
90 }
91
92 /* ************************************************************************
93  * Validity Time
94  * ************************************************************************ */
95
96 /* inline getValidityTime */
97
98 /**
99  Set the validity time of the position update message
100
101  @param validityTimeField
102  A pointer to the validity time field
103  @param validityTime
104  The validity time in seconds
105  */
106 void setValidityTime(uint8_t * validityTimeField,
107                 unsigned long long validityTime) {
108         unsigned int msn = 1;
109         unsigned long long lsn = 0;
110         unsigned long long upperBound;
111
112         if (!cachedValidityTimeMsnValid) {
113                 setupCachedValidityTimeMsn();
114         }
115         upperBound = cachedValidityTimeMsn[msn];
116         while ((msn < 16) && (validityTime >= upperBound)) {
117                 msn++;
118                 upperBound = cachedValidityTimeMsn[msn];
119         }
120         msn--;
121
122         if (unlikely(validityTime >= upperBound)) {
123                 lsn = 15;
124         } else {
125                 unsigned long lowerBound = PUD_VALIDITY_TIME_FROM_OLSR(msn, 0);
126                 unsigned long resolution = (1 << msn);
127                 lsn = ((validityTime - lowerBound + (resolution >> 1)) / resolution);
128         }
129
130         assert(msn <= 15);
131         assert(lsn <= 15);
132
133         *validityTimeField = ((msn << 4) | lsn);
134 }
135
136 /* ************************************************************************
137  * UplinkPositionUpdate
138  * ************************************************************************ */
139
140 /* inline uint8_t getUplinkMessageType */
141 /* inline void setUplinkMessageType */
142
143 /* inline uint16_t getUplinkMessageLength */
144 /* inline void setUplinkMessageLength */
145
146 /* inline bool getUplinkMessageIPv6 */
147 /* inline void setUplinkMessageIPv6 */
148
149 /* inline void setUplinkMessagePadding */
150
151 /* ************************************************************************
152  * OLSR Header
153  * ************************************************************************ */
154
155 /* inline union olsr_ip_addr * getOlsrMessageOriginator */
156
157 /* inline PudOlsrPositionUpdate * getOlsrMessagePayload */
158
159 /* ************************************************************************
160  * PudOlsrPositionUpdate
161  * ************************************************************************ */
162
163 /* inline uint8_t getPositionUpdateVersion */
164 /* inline void setPositionUpdateVersion */
165
166 /* inline uint8_t getPositionUpdateSmask */
167 /* inline void setPositionUpdateSmask */
168
169 /* ************************************************************************
170  * GpsInfo
171  * ************************************************************************ */
172
173 /* inline void setPositionUpdateTime */
174
175 /**
176  Convert the time of an OLSR message (the number of seconds after midnight) to
177  a time structure, based on midnight of the current day.
178
179  @param olsrGpsMessage
180  A pointer to the position update message
181  @param baseDate
182  The base date from which to determine the time (number of seconds since Epoch)
183  @param nowStruct
184  A pointer to the time structure into which to put the converted time
185  */
186 void getPositionUpdateTime(PudOlsrPositionUpdate * olsrGpsMessage,
187                 time_t baseDate, struct tm *nowStruct) {
188         uint32_t olsrTime = olsrGpsMessage->gpsInfo.time;
189         unsigned int secNow;
190
191         time_t now = baseDate;
192         gmtime_r(&now, nowStruct);
193
194         secNow = ((nowStruct->tm_hour * 60 * 60) + (nowStruct->tm_min * 60)
195                         + nowStruct->tm_sec);
196
197         if (secNow <= (12 * 60 * 60)) {
198                 /* we are now in the first 12h of the day */
199                 if (unlikely(olsrTime > (secNow + (12 * 60 * 60)))) {
200                         /* the message was sent more than 12h later in time:
201                          the message was sent yesterday: adjust the date by -1 day */
202                         now -= (24 * 60 * 60);
203                         gmtime_r(&now, nowStruct);
204                 }
205         } else {
206                 /* we are now in the last 12h of the day */
207                 if (unlikely(olsrTime < (secNow - (12 * 60 * 60)))) {
208                         /* the message was sent more than 12h earlier in time:
209                          the message was sent tomorrow: adjust the date by +1 day */
210                         now += (24 * 60 * 60);
211                         gmtime_r(&now, nowStruct);
212                 }
213         }
214
215         nowStruct->tm_hour = ((olsrTime % (24 * 60 * 60)) / 3600);
216         nowStruct->tm_min = ((olsrTime % (60 * 60)) / 60);
217         nowStruct->tm_sec = (olsrTime % 60);
218 }
219
220 /* inline double getPositionUpdateLatitude */
221 /* inline void setPositionUpdateLatitude */
222
223 /* inline double getPositionUpdateLongitude */
224 /* inline void setPositionUpdateLongitude */
225
226 /* inline long getPositionUpdateAltitude */
227 /* inline void setPositionUpdateAltitude */
228
229 /* inline unsigned long getPositionUpdateSpeed */
230 /* inline void setPositionUpdateSpeed */
231
232 /* inline unsigned long getPositionUpdateTrack */
233 /* inline void setPositionUpdateTrack */
234
235 /* inline double getPositionUpdateHdop */
236 /* inline void setPositionUpdateHdop */
237
238 /* ************************************************************************
239  * NodeInfo
240  * ************************************************************************ */
241
242 /* inline NodeIdType getPositionUpdateNodeIdType */
243 /* inline void setPositionUpdateNodeIdType */
244
245 /**
246  Get the nodeId and its size, accounting for nodeId presence
247
248  @param ipVersion
249  The IP version (AF_INET or AF_INET6)
250  @param olsrMessage
251  A pointer to the OLSR message
252  @param nodeId
253  A pointer to the location where a pointer to the nodeId (as contained in the
254  olsrMessage) can be stored
255  @param nodeIdSize
256  A pointer to the location where the number of bytes in the nodeId can be
257  stored
258  */
259 void getPositionUpdateNodeId(int ipVersion, union olsr_message * olsrMessage,
260                 unsigned char ** nodeId, unsigned int * nodeIdSize) {
261         PudOlsrPositionUpdate * olsrGpsMessage = getOlsrMessagePayload(ipVersion,
262                         olsrMessage);
263
264         *nodeId = &olsrGpsMessage->nodeInfo.nodeId;
265
266         switch (getPositionUpdateNodeIdType(ipVersion, olsrGpsMessage)) {
267         case PUD_NODEIDTYPE_MAC: /* hardware address */
268                 *nodeIdSize = PUD_NODEIDTYPE_MAC_BYTES;
269                 break;
270
271         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
272                 *nodeIdSize = PUD_NODEIDTYPE_MSISDN_BYTES;
273                 break;
274
275         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
276                 *nodeIdSize = PUD_NODEIDTYPE_TETRA_BYTES;
277                 break;
278
279         case PUD_NODEIDTYPE_DNS: /* DNS name */
280                 *nodeIdSize = strlen((char *) *nodeId);
281                 /* FIXME for no '\0' at the end, need to scan from the end until
282                  * encountering a non-zero byte: end of string address and
283                  * subtract the string start address */
284                 break;
285
286         case PUD_NODEIDTYPE_192:
287                 *nodeIdSize = PUD_NODEIDTYPE_192_BYTES;
288                 break;
289
290         case PUD_NODEIDTYPE_193:
291                 *nodeIdSize = PUD_NODEIDTYPE_193_BYTES;
292                 break;
293
294         case PUD_NODEIDTYPE_194:
295                 *nodeIdSize = PUD_NODEIDTYPE_194_BYTES;
296                 break;
297
298         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
299         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
300         default: /* unsupported */
301         {
302                 *nodeId = (unsigned char *) getOlsrMessageOriginator(ipVersion,
303                                 olsrMessage);
304                 *nodeIdSize =
305                                 (ipVersion == AF_INET) ?
306                                                 PUD_NODEIDTYPE_IPV4_BYTES : PUD_NODEIDTYPE_IPV6_BYTES;
307         }
308                 break;
309         }
310
311         return;
312 }
313
314 /**
315  Convert the node information to the node information for an OLSR message and
316  put it in the PUD message in the OLSR message. Also updates the PUD message
317  smask.
318
319  @param ipVersion
320  The IP version (AF_INET or AF_INET6)
321  @param olsrGpsMessage
322  A pointer to the PUD message in the OLSR message
323  @param olsrMessageSize
324  The maximum number of bytes available for the olsrMessage
325  @param nodeIdType
326  The nodeIdType
327  @param nodeId
328  The (configured) nodeId
329  @param nodeIdLength
330  The number of bytes in the nodeId
331
332  @return
333  The number of bytes written in the PUD message in the OLSR message (for ALL
334  the node information)
335  */
336 size_t setPositionUpdateNodeInfo(int ipVersion,
337                 PudOlsrPositionUpdate * olsrGpsMessage, unsigned int olsrMessageSize,
338                 NodeIdType nodeIdType, unsigned char * nodeId, size_t nodeIdLength) {
339         unsigned char * buffer;
340         unsigned int length = 0;
341
342         setPositionUpdateNodeIdType(olsrGpsMessage, nodeIdType);
343         switch (nodeIdType) {
344         case PUD_NODEIDTYPE_MAC: /* hardware address */
345                 /* handled when the message is actually sent into OLSR, in the
346                  * pre-transmit hook */
347                 length = PUD_NODEIDTYPE_MAC_BYTES;
348                 break;
349
350         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
351         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
352         case PUD_NODEIDTYPE_192:
353         case PUD_NODEIDTYPE_193:
354         case PUD_NODEIDTYPE_194:
355                 getNodeIdNumberForOlsrCache(&buffer, &length);
356                 setPositionUpdateNodeId(olsrGpsMessage, buffer, length, false);
357                 break;
358
359         case PUD_NODEIDTYPE_DNS: /* DNS name */
360         {
361                 long charsAvailable = olsrMessageSize
362                                 - (PUD_OLSRWIREFORMATSIZE + sizeof(NodeInfo)
363                                                 - sizeof(olsrGpsMessage->nodeInfo.nodeId)) - 1;
364
365                 length = nodeIdLength + 1;
366                 if (unlikely((long) length > charsAvailable)) {
367                         length = charsAvailable;
368                 }
369
370                 setPositionUpdateNodeId(olsrGpsMessage, nodeId, length, true);
371         }
372                 break;
373
374         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
375         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
376                 /* explicit return: no nodeId information in message */
377                 return 0;
378
379         default: /* unsupported */
380                 /* fallback to IP address */
381                 setPositionUpdateNodeIdType(olsrGpsMessage,
382                                 (ipVersion == AF_INET) ? PUD_NODEIDTYPE_IPV4 :
383                                 PUD_NODEIDTYPE_IPV6);
384
385                 /* explicit return: no nodeId information in message */
386                 return 0;
387         }
388
389         setPositionUpdateSmask(olsrGpsMessage,
390                         getPositionUpdateSmask(olsrGpsMessage) | PUD_FLAGS_ID);
391         return ((sizeof(NodeInfo)
392                         - (sizeof(olsrGpsMessage->nodeInfo.nodeId) /* nodeId placeholder */))
393                         + length);
394 }