datapath-windows: Move netlink files to a new directory.
[cascardo/ovs.git] / datapath-windows / ovsext / Netlink / Netlink.c
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "precomp.h"
18 #include "NetlinkProto.h"
19 #include "Netlink.h"
20
21 #ifdef OVS_DBG_MOD
22 #undef OVS_DBG_MOD
23 #endif
24 #define OVS_DBG_MOD OVS_DBG_NETLINK
25 #include "Debug.h"
26
27 /*
28  * ---------------------------------------------------------------------------
29  * Netlink message accessing the payload.
30  * ---------------------------------------------------------------------------
31  */
32 PVOID
33 NlMsgAt(const PNL_MSG_HDR nlh, UINT32 offset)
34 {
35     return ((PCHAR)nlh + offset);
36 }
37
38 /*
39  * ---------------------------------------------------------------------------
40  * Returns the size of netlink message.
41  * ---------------------------------------------------------------------------
42  */
43 UINT32
44 NlMsgSize(const PNL_MSG_HDR nlh)
45 {
46     return nlh->nlmsgLen;
47 }
48
49 /*
50  * ---------------------------------------------------------------------------
51  * Returns pointer to nlmsg payload.
52  * ---------------------------------------------------------------------------
53  */
54 PCHAR
55 NlMsgPayload(const PNL_MSG_HDR nlh)
56 {
57     return ((PCHAR)nlh + NLMSG_HDRLEN);
58 }
59
60 /*
61  * ---------------------------------------------------------------------------
62  * Returns length of nlmsg payload.
63  * ---------------------------------------------------------------------------
64  */
65 UINT32
66 NlMsgPayloadLen(const PNL_MSG_HDR nlh)
67 {
68     return nlh->nlmsgLen - NLMSG_HDRLEN;
69 }
70
71 /*
72  * ---------------------------------------------------------------------------
73  * Returns pointer to nlmsg attributes.
74  * ---------------------------------------------------------------------------
75  */
76 PNL_ATTR
77 NlMsgAttrs(const PNL_MSG_HDR nlh)
78 {
79     return (PNL_ATTR) (NlMsgPayload(nlh) + GENL_HDRLEN + OVS_HDRLEN);
80 }
81
82 /*
83  * ---------------------------------------------------------------------------
84  * Returns size of to nlmsg attributes.
85  * ---------------------------------------------------------------------------
86  */
87 INT
88 NlMsgAttrLen(const PNL_MSG_HDR nlh)
89 {
90     return NlMsgPayloadLen(nlh) - GENL_HDRLEN - OVS_HDRLEN;
91 }
92
93 /* Netlink message parse. */
94
95 /*
96  * ---------------------------------------------------------------------------
97  * Returns next netlink message in the stream.
98  * ---------------------------------------------------------------------------
99  */
100 PNL_MSG_HDR
101 NlMsgNext(const PNL_MSG_HDR nlh)
102 {
103     return (PNL_MSG_HDR)((PCHAR)nlh +
104             NLMSG_ALIGN(nlh->nlmsgLen));
105 }
106
107 /*
108  * ---------------------------------------------------------------------------
109  * Netlink Attr helper APIs.
110  * ---------------------------------------------------------------------------
111  */
112 INT
113 NlAttrIsValid(const PNL_ATTR nla, UINT32 maxlen)
114 {
115     return (maxlen >= sizeof *nla
116             && nla->nlaLen >= sizeof *nla
117             && nla->nlaLen <= maxlen);
118 }
119
120 /*
121  * ---------------------------------------------------------------------------
122  * Returns alligned length of the attribute.
123  * ---------------------------------------------------------------------------
124  */
125 UINT32
126 NlAttrLenPad(const PNL_ATTR nla, UINT32 maxlen)
127 {
128     UINT32 len = NLA_ALIGN(nla->nlaLen);
129
130     return len <= maxlen ? len : nla->nlaLen;
131 }
132
133 /*
134  * ---------------------------------------------------------------------------
135  * Default minimum payload size for each type of attribute.
136  * ---------------------------------------------------------------------------
137  */
138 UINT32
139 NlAttrMinLen(NL_ATTR_TYPE type)
140 {
141     switch (type) {
142     case NL_A_NO_ATTR: return 0;
143     case NL_A_UNSPEC: return 0;
144     case NL_A_U8: return 1;
145     case NL_A_U16: return 2;
146     case NL_A_U32: return 4;
147     case NL_A_U64: return 8;
148     case NL_A_STRING: return 1;
149     case NL_A_FLAG: return 0;
150     case NL_A_NESTED: return 0;
151     case N_NL_ATTR_TYPES:
152     default:
153     OVS_LOG_WARN("Unsupprted attribute type: %d", type);
154     ASSERT(0);
155     }
156
157     /* To keep compiler happy */
158     return 0;
159 }
160
161 /*
162  * ---------------------------------------------------------------------------
163  * Default maximum payload size for each type of attribute.
164  * ---------------------------------------------------------------------------
165  */
166 UINT32
167 NlAttrMaxLen(NL_ATTR_TYPE type)
168 {
169     switch (type) {
170     case NL_A_NO_ATTR: return SIZE_MAX;
171     case NL_A_UNSPEC: return SIZE_MAX;
172     case NL_A_U8: return 1;
173     case NL_A_U16: return 2;
174     case NL_A_U32: return 4;
175     case NL_A_U64: return 8;
176     case NL_A_STRING: return SIZE_MAX;
177     case NL_A_FLAG: return SIZE_MAX;
178     case NL_A_NESTED: return SIZE_MAX;
179     case N_NL_ATTR_TYPES:
180     default:
181     OVS_LOG_WARN("Unsupprted attribute type: %d", type);
182     ASSERT(0);
183     }
184
185     /* To keep compiler happy */
186     return 0;
187 }
188
189 /* Netlink attribute iteration. */
190
191 /*
192  * ---------------------------------------------------------------------------
193  * Returns the next attribute.
194  * ---------------------------------------------------------------------------
195  */
196 PNL_ATTR
197 NlAttrNext(const PNL_ATTR nla)
198 {
199     return (PNL_ATTR)((UINT8 *)nla + NLA_ALIGN(nla->nlaLen));
200 }
201
202 /*
203  * --------------------------------------------------------------------------
204  * Returns the bits of 'nla->nlaType' that are significant for determining
205  * its type.
206  * --------------------------------------------------------------------------
207  */
208 UINT16
209 NlAttrType(const PNL_ATTR nla)
210 {
211    return nla->nlaType & NLA_TYPE_MASK;
212 }
213
214 /*
215  * --------------------------------------------------------------------------
216  * Returns the netlink attribute data.
217  * --------------------------------------------------------------------------
218  */
219 PVOID
220 NlAttrData(const PNL_ATTR nla)
221 {
222     return ((PCHAR)nla + NLA_HDRLEN);
223 }
224
225 /*
226  * ---------------------------------------------------------------------------
227  * Returns the number of bytes in the payload of attribute 'nla'.
228  * ---------------------------------------------------------------------------
229  */
230 UINT32
231 NlAttrGetSize(const PNL_ATTR nla)
232 {
233     return nla->nlaLen - NLA_HDRLEN;
234 }
235
236 /*
237  * ---------------------------------------------------------------------------
238  * Returns the first byte in the payload of attribute 'nla'.
239  * ---------------------------------------------------------------------------
240  */
241 const PVOID
242 NlAttrGet(const PNL_ATTR nla)
243 {
244     ASSERT(nla->nlaLen >= NLA_HDRLEN);
245     return nla + 1;
246 }
247
248 /*
249  * ---------------------------------------------------------------------------
250  * Asserts that 'nla''s payload is at least 'size' bytes long, and returns the
251  * first byte of the payload.
252  * ---------------------------------------------------------------------------
253  */
254 const
255 PVOID NlAttrGetUnspec(const PNL_ATTR nla, UINT32 size)
256 {
257     UNREFERENCED_PARAMETER(size);
258     ASSERT(nla->nlaLen >= NLA_HDRLEN + size);
259     return nla + 1;
260 }
261
262 /*
263  * ---------------------------------------------------------------------------
264  * Returns the 64-bit network byte order value in 'nla''s payload.
265  *
266  * Asserts that 'nla''s payload is at least 8 bytes long.
267  * ---------------------------------------------------------------------------
268  */
269 BE64
270 NlAttrGetBe64(const PNL_ATTR nla)
271 {
272     return NL_ATTR_GET_AS(nla, BE64);
273 }
274
275 /*
276  * ---------------------------------------------------------------------------
277  * Returns the 32-bit network byte order value in 'nla''s payload.
278  *
279  * Asserts that 'nla''s payload is at least 4 bytes long.
280  * ---------------------------------------------------------------------------
281  */
282 BE32
283 NlAttrGetBe32(const PNL_ATTR nla)
284 {
285     return NL_ATTR_GET_AS(nla, BE32);
286 }
287
288 /*
289  * ---------------------------------------------------------------------------
290  * Returns the 8-bit value in 'nla''s payload.
291  * ---------------------------------------------------------------------------
292  */
293 UINT8
294 NlAttrGetU8(const PNL_ATTR nla)
295 {
296     return NL_ATTR_GET_AS(nla, UINT8);
297 }
298
299 /*
300  * ---------------------------------------------------------------------------
301  * Returns the 32-bit host byte order value in 'nla''s payload.
302  * Asserts that 'nla''s payload is at least 4 bytes long.
303  * ---------------------------------------------------------------------------
304  */
305 UINT32
306 NlAttrGetU32(const PNL_ATTR nla)
307 {
308     return NL_ATTR_GET_AS(nla, UINT32);
309 }
310
311 /*
312  * ---------------------------------------------------------------------------
313  * Validate the netlink attribute against the policy
314  * ---------------------------------------------------------------------------
315  */
316 BOOLEAN
317 NlAttrValidate(const PNL_ATTR nla, const PNL_POLICY policy)
318 {
319     UINT32 minLen;
320     UINT32 maxLen;
321     UINT32 len;
322     BOOLEAN ret = FALSE;
323
324     if (policy->type == NL_A_NO_ATTR) {
325         ret = TRUE;
326         goto done;
327     }
328
329     /* Figure out min and max length. */
330     minLen = policy->minLen;
331     if (!minLen) {
332         minLen = NlAttrMinLen(policy->type);
333     }
334     maxLen = policy->maxLen;
335     if (!maxLen) {
336         maxLen = NlAttrMaxLen(policy->type);
337     }
338
339     /* Verify length. */
340     len = NlAttrGetSize(nla);
341     if (len < minLen || len > maxLen) {
342         OVS_LOG_WARN("Attribute: %p, len: %d, not in valid range, "
343                      "min: %d, max: %d", nla, len, minLen, maxLen);
344         goto done;
345     }
346
347     /* Strings must be null terminated and must not have embedded nulls. */
348     if (policy->type == NL_A_STRING) {
349         if (((PCHAR) nla)[nla->nlaLen - 1]) {
350             OVS_LOG_WARN("Attributes %p lacks null at the end", nla);
351             goto done;
352         }
353
354         if (memchr(nla + 1, '\0', len - 1) != NULL) {
355             OVS_LOG_WARN("Attributes %p has bad length", nla);
356             goto done;
357         }
358     }
359
360 done:
361     return ret;
362 }
363
364 /*
365  * ---------------------------------------------------------------------------
366  * Returns an attribute of type 'type' from a series of
367  * attributes.
368  * ---------------------------------------------------------------------------
369  */
370 const PNL_ATTR
371 NlAttrFind__(const PNL_ATTR attrs, UINT32 size, UINT16 type)
372 {
373     PNL_ATTR iter = NULL;
374     PNL_ATTR ret = NULL;
375     UINT32 left;
376
377     NL_ATTR_FOR_EACH (iter, left, attrs, size) {
378         if (NlAttrType(iter) == type) {
379             ret = iter;
380             goto done;
381         }
382     }
383
384 done:
385     return ret;
386 }
387
388 /*
389  * ---------------------------------------------------------------------------
390  * Returns the first Netlink attribute within 'nla' with the specified
391  * 'type'.
392  *
393  * This function does not validate the attribute's length.
394  * ---------------------------------------------------------------------------
395  */
396 const PNL_ATTR
397 NlAttrFindNested(const PNL_ATTR nla, UINT16 type)
398 {
399     return NlAttrFind__((const PNL_ATTR)(NlAttrGet(nla)),
400                          NlAttrGetSize(nla), type);
401 }
402
403 /*
404  *----------------------------------------------------------------------------
405  * Parses the netlink message at a given offset (attrOffset)
406  * as a series of attributes. A pointer to the attribute with type
407  * 'type' is stored in attrs at index 'type'. policy is used to define the
408  * attribute type validation parameters.
409  * 'nla_offset' should be NLMSG_HDRLEN + GENL_HDRLEN + OVS_HEADER
410  *
411  * Returns NDIS_STATUS_SUCCESS normally.  Fails only if packet data cannot be accessed
412  * (e.g. if Pkt_CopyBytesOut() returns an error).
413  *----------------------------------------------------------------------------
414  */
415 BOOLEAN NlAttrParse(const PNL_MSG_HDR nlMsg, UINT32 attrOffset,
416                     const NL_POLICY policy[],
417                     PNL_ATTR attrs[], UINT32 n_attrs)
418 {
419     PNL_ATTR nla;
420     UINT32 left;
421     UINT32 iter;
422     BOOLEAN ret = FALSE;
423
424     memset(attrs, 0, n_attrs * sizeof *attrs);
425
426     if ((NlMsgSize(nlMsg) < attrOffset) || (!(NlMsgAttrLen(nlMsg)))) {
427         OVS_LOG_WARN("No attributes in nlMsg: %p at offset: %d",
428                      nlMsg, attrOffset);
429         goto done;
430     }
431
432     NL_ATTR_FOR_EACH (nla, left, NlMsgAt(nlMsg, attrOffset),
433                       NlMsgSize(nlMsg) - attrOffset)
434     {
435         UINT16 type = NlAttrType(nla);
436         if (type < n_attrs && policy[type].type != NL_A_NO_ATTR) {
437             /* Typecasting to keep the compiler happy */
438             const PNL_POLICY e = (const PNL_POLICY)(&policy[type]);
439             if (!NlAttrValidate(nla, e)) {
440                 goto done;
441             }
442
443             if (attrs[type]) {
444                 OVS_LOG_WARN("Duplicate attribute in nlMsg: %p, "
445                              "type: %u", nlMsg, type);
446             }
447
448             attrs[type] = nla;
449         }
450     }
451
452     if (left) {
453         OVS_LOG_ERROR("Attributes followed by garbage");
454         goto done;
455     }
456
457     for (iter = 0; iter < n_attrs; iter++) {
458         const PNL_POLICY e = (const PNL_POLICY)(&policy[iter]);
459         if (e->type != NL_A_NO_ATTR && !attrs[iter]) {
460             OVS_LOG_ERROR("Required attr:%d missing", iter);
461             goto done;
462         }
463     }
464
465     ret = TRUE;
466
467 done:
468     return ret;
469 }