127739b109f8213a7b362bf1f30750931b41fa70
[olsrd.git] / lib / pud / wireformat / src / wireFormat.c
1 #include <OlsrdPudWireFormat/wireFormat.h>
2
3 #include <time.h>
4
5 /* ************************************************************************
6  * Validity Time
7  * ************************************************************************ */
8
9 /* inline getValidityTime */
10
11 /**
12  Set the validity time of the position update message
13
14  @param validityTimeField
15  A pointer to the validity time field
16  @param validityTime
17  The validity time in seconds
18  */
19 void setValidityTime(uint8_t * validityTimeField,
20                 unsigned long long validityTime) {
21         unsigned int msn = 1;
22         unsigned long long lsn = 0;
23         unsigned long long upperBound;
24
25         upperBound = PUD_VALIDITY_TIME_FROM_OLSR(msn, 0);
26         while ((msn < 16) && (validityTime >= upperBound)) {
27                 msn++;
28                 upperBound = PUD_VALIDITY_TIME_FROM_OLSR(msn, 0);
29         }
30         msn--;
31
32         if (unlikely(validityTime >= upperBound)) {
33                 lsn = 15;
34         } else {
35                 unsigned long lowerBound = PUD_VALIDITY_TIME_FROM_OLSR(msn, 0);
36                 unsigned long resolution = (1 << msn);
37                 lsn = ((validityTime - lowerBound + (resolution >> 1)) / resolution);
38         }
39
40         assert(msn <= 15);
41         assert(lsn <= 15);
42
43         *validityTimeField = ((msn << 4) | lsn);
44 }
45
46 /* ************************************************************************
47  * UplinkPositionUpdate
48  * ************************************************************************ */
49
50 /* inline uint8_t getUplinkMessageType */
51 /* inline void setUplinkMessageType */
52
53 /* inline uint16_t getUplinkMessageLength */
54 /* inline void setUplinkMessageLength */
55
56 /* inline bool getUplinkMessageIPv6 */
57 /* inline void setUplinkMessageIPv6 */
58
59 /* inline void setUplinkMessagePadding */
60
61 /* ************************************************************************
62  * OLSR Header
63  * ************************************************************************ */
64
65 /* inline union olsr_ip_addr * getOlsrMessageOriginator */
66
67 /* inline PudOlsrPositionUpdate * getOlsrMessagePayload */
68
69 /* ************************************************************************
70  * PudOlsrPositionUpdate
71  * ************************************************************************ */
72
73 /* inline uint8_t getPositionUpdateVersion */
74 /* inline void setPositionUpdateVersion */
75
76 /* inline uint8_t getPositionUpdateSmask */
77 /* inline void setPositionUpdateSmask */
78
79 /* ************************************************************************
80  * GpsInfo
81  * ************************************************************************ */
82
83 /* inline void setPositionUpdateTime */
84
85 /**
86  Convert the time of an OLSR message (the number of seconds after midnight) to
87  a time structure, based on midnight of the current day.
88
89  @param olsrGpsMessage
90  A pointer to the position update message
91  @param baseDate
92  The base date from which to determine the time (number of seconds since Epoch,
93  UTC)
94  @param nowStruct
95  A pointer to the time structure into which to put the converted time
96  */
97 void getPositionUpdateTime(PudOlsrPositionUpdate * olsrGpsMessage,
98                 time_t baseDate, struct tm *nowStruct) {
99         uint32_t olsrTime = olsrGpsMessage->gpsInfo.time;
100         unsigned int secNow;
101
102         time_t now = baseDate;
103         gmtime_r(&now, nowStruct);
104
105         secNow = ((nowStruct->tm_hour * 60 * 60) + (nowStruct->tm_min * 60)
106                         + nowStruct->tm_sec);
107
108         if (secNow <= (12 * 60 * 60)) {
109                 /* we are now in the first 12h of the day */
110                 if (unlikely(olsrTime > (secNow + (12 * 60 * 60)))) {
111                         /* the message was sent more than 12h later in time:
112                          the message was sent yesterday: adjust the date by -1 day */
113                         now -= (24 * 60 * 60);
114                         gmtime_r(&now, nowStruct);
115                 }
116         } else {
117                 /* we are now in the last 12h of the day */
118                 if (unlikely(olsrTime < (secNow - (12 * 60 * 60)))) {
119                         /* the message was sent more than 12h earlier in time:
120                          the message was sent tomorrow: adjust the date by +1 day */
121                         now += (24 * 60 * 60);
122                         gmtime_r(&now, nowStruct);
123                 }
124         }
125
126         nowStruct->tm_hour = ((olsrTime % (24 * 60 * 60)) / 3600);
127         nowStruct->tm_min = ((olsrTime % (60 * 60)) / 60);
128         nowStruct->tm_sec = (olsrTime % 60);
129 }
130
131 /* inline double getPositionUpdateLatitude */
132 /* inline void setPositionUpdateLatitude */
133
134 /* inline double getPositionUpdateLongitude */
135 /* inline void setPositionUpdateLongitude */
136
137 /* inline long getPositionUpdateAltitude */
138 /* inline void setPositionUpdateAltitude */
139
140 /* inline unsigned long getPositionUpdateSpeed */
141 /* inline void setPositionUpdateSpeed */
142
143 /* inline unsigned long getPositionUpdateTrack */
144 /* inline void setPositionUpdateTrack */
145
146 /* inline double getPositionUpdateHdop */
147 /* inline void setPositionUpdateHdop */
148
149 /* ************************************************************************
150  * NodeInfo
151  * ************************************************************************ */
152
153 /* inline NodeIdType getPositionUpdateNodeIdType */
154 /* inline void setPositionUpdateNodeIdType */
155
156 /**
157  Get the nodeId and its size, accounting for nodeId presence
158
159  @param ipVersion
160  The IP version (AF_INET or AF_INET6)
161  @param olsrMessage
162  A pointer to the OLSR message
163  @param nodeId
164  A pointer to the location where a pointer to the nodeId (as contained in the
165  olsrMessage) can be stored
166  @param nodeIdSize
167  A pointer to the location where the number of bytes in the nodeId can be
168  stored
169  */
170 void getPositionUpdateNodeId(int ipVersion, union olsr_message * olsrMessage,
171                 unsigned char ** nodeId, unsigned int * nodeIdSize) {
172         PudOlsrPositionUpdate * olsrGpsMessage = getOlsrMessagePayload(ipVersion,
173                         olsrMessage);
174
175         *nodeId = &olsrGpsMessage->nodeInfo.nodeId;
176
177         switch (getPositionUpdateNodeIdType(ipVersion, olsrGpsMessage)) {
178         case PUD_NODEIDTYPE_MAC: /* hardware address */
179                 *nodeIdSize = PUD_NODEIDTYPE_MAC_BYTES;
180                 break;
181
182         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
183                 *nodeIdSize = PUD_NODEIDTYPE_MSISDN_BYTES;
184                 break;
185
186         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
187                 *nodeIdSize = PUD_NODEIDTYPE_TETRA_BYTES;
188                 break;
189
190         case PUD_NODEIDTYPE_DNS: /* DNS name */
191                 *nodeIdSize = strlen((char *) *nodeId);
192                 /* FIXME for no '\0' at the end, need to scan from the end until
193                  * encountering a non-zero byte: end of string address and
194                  * subtract the string start address */
195                 break;
196
197         case PUD_NODEIDTYPE_MMSI: /* an AIS MMSI number */
198                 *nodeIdSize = PUD_NODEIDTYPE_MMSI_BYTES;
199                 break;
200
201         case PUD_NODEIDTYPE_URN: /* a URN number */
202                 *nodeIdSize = PUD_NODEIDTYPE_URN_BYTES;
203                 break;
204
205         case PUD_NODEIDTYPE_192:
206                 *nodeIdSize = PUD_NODEIDTYPE_192_BYTES;
207                 break;
208
209         case PUD_NODEIDTYPE_193:
210                 *nodeIdSize = PUD_NODEIDTYPE_193_BYTES;
211                 break;
212
213         case PUD_NODEIDTYPE_194:
214                 *nodeIdSize = PUD_NODEIDTYPE_194_BYTES;
215                 break;
216
217         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
218         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
219         default: /* unsupported */
220         {
221                 *nodeId = (unsigned char *) getOlsrMessageOriginator(ipVersion,
222                                 olsrMessage);
223                 *nodeIdSize =
224                                 (ipVersion == AF_INET) ?
225                                                 PUD_NODEIDTYPE_IPV4_BYTES : PUD_NODEIDTYPE_IPV6_BYTES;
226         }
227                 break;
228         }
229
230         return;
231 }
232
233 /**
234  Convert the node information to the node information for an OLSR message and
235  put it in the PUD message in the OLSR message. Also updates the PUD message
236  smask.
237
238  @param ipVersion
239  The IP version (AF_INET or AF_INET6)
240  @param olsrGpsMessage
241  A pointer to the PUD message in the OLSR message
242  @param olsrMessageSize
243  The maximum number of bytes available for the olsrMessage
244  @param nodeIdType
245  The nodeIdType
246  @param nodeId
247  The (configured) nodeId in binary/wireformat representation
248  @param nodeIdLength
249  The number of bytes in the nodeId
250
251  @return
252  The number of bytes written in the PUD message in the OLSR message (for ALL
253  the node information)
254  */
255 size_t setPositionUpdateNodeInfo(int ipVersion,
256                 PudOlsrPositionUpdate * olsrGpsMessage, unsigned int olsrMessageSize,
257                 NodeIdType nodeIdType, unsigned char * nodeId, size_t nodeIdLength) {
258         unsigned int length = 0;
259
260         setPositionUpdateNodeIdType(olsrGpsMessage, nodeIdType);
261         switch (nodeIdType) {
262         case PUD_NODEIDTYPE_MAC: /* hardware address */
263         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
264         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
265         case PUD_NODEIDTYPE_MMSI: /* an AIS MMSI number */
266         case PUD_NODEIDTYPE_URN: /* a URN number */
267         case PUD_NODEIDTYPE_192:
268         case PUD_NODEIDTYPE_193:
269         case PUD_NODEIDTYPE_194:
270                 length = nodeIdLength;
271                 setPositionUpdateNodeId(olsrGpsMessage, nodeId, nodeIdLength, false);
272                 break;
273
274         case PUD_NODEIDTYPE_DNS: /* DNS name */
275         {
276                 long charsAvailable = olsrMessageSize
277                                 - (PUD_OLSRWIREFORMATSIZE + sizeof(NodeInfo)
278                                                 - sizeof(olsrGpsMessage->nodeInfo.nodeId)) - 1;
279
280                 length = nodeIdLength + 1;
281                 if (unlikely((long) length > charsAvailable)) {
282                         length = charsAvailable;
283                 }
284
285                 setPositionUpdateNodeId(olsrGpsMessage, nodeId, length, true);
286         }
287                 break;
288
289         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
290         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
291                 /* explicit return: no nodeId information in message */
292                 return 0;
293
294         default: /* unsupported */
295                 /* fallback to IP address */
296                 setPositionUpdateNodeIdType(olsrGpsMessage,
297                                 (ipVersion == AF_INET) ? PUD_NODEIDTYPE_IPV4 :
298                                 PUD_NODEIDTYPE_IPV6);
299
300                 /* explicit return: no nodeId information in message */
301                 return 0;
302         }
303
304         setPositionUpdateFlags(olsrGpsMessage,
305                         getPositionUpdateFlags(olsrGpsMessage) | PUD_FLAGS_ID);
306         return ((sizeof(NodeInfo)
307                         - (sizeof(olsrGpsMessage->nodeInfo.nodeId) /* nodeId placeholder */))
308                         + length);
309 }