7ec651f084cc9343d48f6bd4025c8eab885ad9b3
[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  * This file provides simple netlink get, put and validation APIs.
29  * Most of the code is on similar lines as userspace netlink implementation.
30  *
31  * TODO: Convert these methods to inline.
32  * ==========================================================================
33  */
34
35 /*
36  * ---------------------------------------------------------------------------
37  * Prepare netlink message headers. This API adds
38  * NL_MSG_HDR + GENL_HDR + OVS_HDR to the tail of input NLBuf.
39  * Attributes should be added by caller.
40  * ---------------------------------------------------------------------------
41  */
42 NTSTATUS
43 NlFillOvsMsg(PNL_BUFFER nlBuf, UINT16 nlmsgType,
44              UINT16 nlmsgFlags, UINT32 nlmsgSeq,
45              UINT32 nlmsgPid, UINT8 genlCmd,
46              UINT8 genlVer, UINT32 dpNo)
47 {
48     BOOLEAN writeOk;
49     OVS_MESSAGE msgOut;
50     UINT32 offset = NlBufSize(nlBuf);
51
52     /* To keep compiler happy for release build. */
53     UNREFERENCED_PARAMETER(offset);
54     ASSERT(NlBufAt(nlBuf, offset, sizeof(struct _OVS_MESSAGE)) != 0);
55
56     msgOut.nlMsg.nlmsgType = nlmsgType;
57     msgOut.nlMsg.nlmsgFlags = nlmsgFlags;
58     msgOut.nlMsg.nlmsgSeq = nlmsgSeq;
59     msgOut.nlMsg.nlmsgPid = nlmsgPid;
60     msgOut.nlMsg.nlmsgLen = sizeof(struct _OVS_MESSAGE);
61
62     msgOut.genlMsg.cmd = genlCmd;
63     msgOut.genlMsg.version = genlVer;
64     msgOut.genlMsg.reserved = 0;
65
66     msgOut.ovsHdr.dp_ifindex = dpNo;
67
68     writeOk = NlMsgPutTail(nlBuf, (PCHAR)(&msgOut),
69                            sizeof (struct _OVS_MESSAGE));
70
71     return writeOk ? STATUS_SUCCESS : STATUS_INVALID_BUFFER_SIZE;
72 }
73
74 /*
75  * ---------------------------------------------------------------------------
76  * Prepare NL_MSG_HDR only. This API appends a NL_MSG_HDR to the tail of
77  * input NlBuf.
78  * ---------------------------------------------------------------------------
79  */
80 NTSTATUS
81 NlFillNlHdr(PNL_BUFFER nlBuf, UINT16 nlmsgType,
82             UINT16 nlmsgFlags, UINT32 nlmsgSeq,
83             UINT32 nlmsgPid)
84 {
85     BOOLEAN writeOk;
86     NL_MSG_HDR msgOut;
87     UINT32 offset = NlBufSize(nlBuf);
88
89     /* To keep compiler happy for release build. */
90     UNREFERENCED_PARAMETER(offset);
91     ASSERT(NlBufAt(nlBuf, offset, sizeof(struct _NL_MSG_HDR)) != 0);
92
93     msgOut.nlmsgType = nlmsgType;
94     msgOut.nlmsgFlags = nlmsgFlags;
95     msgOut.nlmsgSeq = nlmsgSeq;
96     msgOut.nlmsgPid = nlmsgPid;
97     msgOut.nlmsgLen = sizeof(struct _NL_MSG_HDR);
98
99     writeOk = NlMsgPutTail(nlBuf, (PCHAR)(&msgOut),
100                            sizeof(struct _NL_MSG_HDR));
101
102     return writeOk ? STATUS_SUCCESS : STATUS_INVALID_BUFFER_SIZE;
103 }
104
105 /*
106  * ---------------------------------------------------------------------------
107  * Adds Netlink Header to the NL_BUF.
108  * ---------------------------------------------------------------------------
109  */
110 BOOLEAN
111 NlMsgPutNlHdr(PNL_BUFFER buf, PNL_MSG_HDR nlMsg)
112 {
113     if ((NlBufCopyAtOffset(buf, (PCHAR)nlMsg, NLMSG_HDRLEN, 0))) {
114         return TRUE;
115     }
116
117     return FALSE;
118 }
119
120 /*
121  * ---------------------------------------------------------------------------
122  * Adds Genl Header to the NL_BUF.
123  * ---------------------------------------------------------------------------
124  */
125 BOOLEAN
126 NlMsgPutGenlHdr(PNL_BUFFER buf, PGENL_MSG_HDR genlMsg)
127 {
128     if ((NlBufCopyAtOffset(buf, (PCHAR)genlMsg, GENL_HDRLEN, NLMSG_HDRLEN))) {
129         return TRUE;
130     }
131
132     return FALSE;
133 }
134
135 /*
136  * ---------------------------------------------------------------------------
137  * Adds OVS Header to the NL_BUF.
138  * ---------------------------------------------------------------------------
139  */
140 BOOLEAN
141 NlMsgPutOvsHdr(PNL_BUFFER buf, POVS_HDR ovsHdr)
142 {
143     if ((NlBufCopyAtOffset(buf, (PCHAR)ovsHdr, OVS_HDRLEN,
144                            GENL_HDRLEN + NLMSG_HDRLEN))) {
145         return TRUE;
146     }
147
148     return FALSE;
149 }
150
151 /*
152  * ---------------------------------------------------------------------------
153  * Adds data of length 'len' to the tail end of NL_BUF.
154  * Refer nl_msg_put for more details.
155  * ---------------------------------------------------------------------------
156  */
157 BOOLEAN
158 NlMsgPutTail(PNL_BUFFER buf, const PCHAR data, UINT32 len)
159 {
160     len = NLMSG_ALIGN(len);
161     if (NlBufCopyAtTail(buf, data, len)) {
162         return TRUE;
163     }
164
165     return FALSE;
166 }
167
168 /*
169  * ---------------------------------------------------------------------------
170  * memsets length 'len' at tail end of NL_BUF.
171  * Refer nl_msg_put_uninit for more details.
172  * ---------------------------------------------------------------------------
173  */
174 PCHAR
175 NlMsgPutTailUninit(PNL_BUFFER buf, UINT32 len)
176 {
177     len = NLMSG_ALIGN(len);
178     return NlBufCopyAtTailUninit(buf, len);
179 }
180
181 /*
182  * ---------------------------------------------------------------------------
183  * Adds an attribute to the tail end of buffer. It does
184  * not copy the attribute payload.
185  * Refer nl_msg_put_unspec_uninit for more details.
186  * ---------------------------------------------------------------------------
187  */
188 PCHAR
189 NlMsgPutTailUnspecUninit(PNL_BUFFER buf, UINT16 type, UINT16 len)
190 {
191     PCHAR ret = NULL;
192     UINT16 totalLen = NLA_HDRLEN + len;
193     PNL_ATTR nla = (PNL_ATTR)(NlMsgPutTailUninit(buf, totalLen));
194
195     if (!nla) {
196         goto done;
197     }
198
199     ret = (PCHAR)(nla + 1);
200     nla->nlaLen = totalLen;
201     nla->nlaType = type;
202
203 done:
204     return ret;
205 }
206
207 /*
208  * ---------------------------------------------------------------------------
209  * Adds an attribute to the tail end of buffer. It copies attribute
210  * payload as well.
211  * Refer nl_msg_put_unspec for more details.
212  * ---------------------------------------------------------------------------
213  */
214 BOOLEAN
215 NlMsgPutTailUnspec(PNL_BUFFER buf, UINT16 type, PCHAR data, UINT16 len)
216 {
217     BOOLEAN ret = TRUE;
218     PCHAR nlaData = NlMsgPutTailUnspecUninit(buf, type, len);
219
220     if (!nlaData) {
221         ret = FALSE;
222         goto done;
223     }
224
225     RtlCopyMemory(nlaData, data, len);
226
227 done:
228     return ret;
229 }
230
231 /*
232  * ---------------------------------------------------------------------------
233  * Adds an attribute of 'type' and no payload at the tail end of buffer.
234  * Refer nl_msg_put_flag for more details.
235  * ---------------------------------------------------------------------------
236  */
237 BOOLEAN
238 NlMsgPutTailFlag(PNL_BUFFER buf, UINT16 type)
239 {
240     BOOLEAN ret = TRUE;
241     PCHAR nlaData = NlMsgPutTailUnspecUninit(buf, type, 0);
242
243     if (!nlaData) {
244         ret = FALSE;
245     }
246
247     return ret;
248 }
249
250 /*
251  * ---------------------------------------------------------------------------
252  * Adds an attribute of 'type' and 8 bit payload at the tail end of buffer.
253  * Refer nl_msg_put_u8 for more details.
254  * ---------------------------------------------------------------------------
255  */
256 BOOLEAN
257 NlMsgPutTailU8(PNL_BUFFER buf, UINT16 type, UINT8 value)
258 {
259     return (NlMsgPutTailUnspec(buf, type, (PCHAR)(&value), sizeof(value)));
260 }
261
262 /*
263  * ---------------------------------------------------------------------------
264  * Adds an attribute of 'type' and 16 bit payload at the tail end of buffer.
265  * Refer nl_msg_put_u16 for more details.
266  * ---------------------------------------------------------------------------
267  */
268 BOOLEAN
269 NlMsgPutTailU16(PNL_BUFFER buf, UINT16 type, UINT16 value)
270 {
271     return (NlMsgPutTailUnspec(buf, type, (PCHAR)(&value), sizeof(value)));
272 }
273
274 /*
275  * ---------------------------------------------------------------------------
276  * Adds an attribute of 'type' and 32 bit payload at the tail end of buffer.
277  * Refer nl_msg_put_u32 for more details.
278  * ---------------------------------------------------------------------------
279  */
280 BOOLEAN
281 NlMsgPutTailU32(PNL_BUFFER buf, UINT16 type, UINT32 value)
282 {
283     return (NlMsgPutTailUnspec(buf, type, (PCHAR)(&value), sizeof(value)));
284 }
285
286 /*
287  * ---------------------------------------------------------------------------
288  * Adds an attribute of 'type' and 64 bit payload at the tail end of buffer.
289  * Refer nl_msg_put_u64 for more details.
290  * ---------------------------------------------------------------------------
291  */
292 BOOLEAN
293 NlMsgPutTailU64(PNL_BUFFER buf, UINT16 type, UINT64 value)
294 {
295     return (NlMsgPutTailUnspec(buf, type, (PCHAR)(&value), sizeof(value)));
296 }
297
298 /*
299  * ---------------------------------------------------------------------------
300  * Adds an attribute of 'type' and string payload.
301  * Refer nl_msg_put_string for more details.
302  * ---------------------------------------------------------------------------
303  */
304 BOOLEAN
305 NlMsgPutTailString(PNL_BUFFER buf, UINT16 type, PCHAR value)
306 {
307     size_t strLen = strlen(value) + 1;
308 #ifdef DBG
309     /* Attribute length should come within 16 bits (NL_ATTR).
310      * Not a likely case, hence validation only in debug mode. */
311     if ((strLen + PAD_SIZE(strLen, NLA_ALIGNTO)) > MAXUINT16) {
312         return FALSE;
313     }
314 #endif
315
316     /* typecast to keep compiler happy */
317     return (NlMsgPutTailUnspec(buf, type, value,
318                                (UINT16)strLen));
319 }
320
321 /*
322  * ---------------------------------------------------------------------------
323  * Adds data of length 'len' to the head of NL_BUF.
324  * Refer nl_msg_push for more details.
325  * ---------------------------------------------------------------------------
326  */
327 BOOLEAN
328 NlMsgPutHead(PNL_BUFFER buf, const PCHAR data, UINT32 len)
329 {
330     len = NLMSG_ALIGN(len);
331     if (NlBufCopyAtHead(buf, data, len)) {
332         return TRUE;
333     }
334
335     return FALSE;
336 }
337
338 /*
339  * ---------------------------------------------------------------------------
340  * memsets length 'len' at head of NL_BUF.
341  * Refer nl_msg_push_uninit for more details.
342  * ---------------------------------------------------------------------------
343  */
344 PCHAR
345 NlMsgPutHeadUninit(PNL_BUFFER buf, UINT32 len)
346 {
347     len = NLMSG_ALIGN(len);
348     return NlBufCopyAtHeadUninit(buf, len);
349 }
350
351 /*
352  * ---------------------------------------------------------------------------
353  * Adds an attribute to the head of buffer. It does
354  * not copy the attribute payload.
355  * Refer nl_msg_push_unspec_uninit for more details.
356  * ---------------------------------------------------------------------------
357  */
358 PCHAR
359 NlMsgPutHeadUnspecUninit(PNL_BUFFER buf, UINT16 type, UINT16 len)
360 {
361     PCHAR ret = NULL;
362     UINT16 totalLen = NLA_HDRLEN + len;
363     PNL_ATTR nla = (PNL_ATTR)(NlMsgPutHeadUninit(buf, totalLen));
364
365     if (!nla) {
366         goto done;
367     }
368
369     ret = (PCHAR)(nla + 1);
370     nla->nlaLen = totalLen;
371     nla->nlaType = type;
372
373 done:
374     return ret;
375 }
376
377 /*
378  * ---------------------------------------------------------------------------
379  * Adds an attribute to the head of buffer. It copies attribute
380  * payload as well.
381  * Refer nl_msg_push_unspec for more details.
382  * ---------------------------------------------------------------------------
383  */
384 BOOLEAN
385 NlMsgPutHeadUnspec(PNL_BUFFER buf, UINT16 type, PCHAR data, UINT16 len)
386 {
387     BOOLEAN ret = TRUE;
388     PCHAR nlaData = NlMsgPutHeadUnspecUninit(buf, type, len);
389
390     if (!nlaData) {
391         ret = FALSE;
392         goto done;
393     }
394
395     RtlCopyMemory(nlaData, data, len);
396
397 done:
398     return ret;
399 }
400
401 /*
402  * ---------------------------------------------------------------------------
403  * Adds an attribute of 'type' and no payload at the head of buffer.
404  * Refer nl_msg_push_flag for more details.
405  * ---------------------------------------------------------------------------
406  */
407 BOOLEAN
408 NlMsgPutHeadFlag(PNL_BUFFER buf, UINT16 type)
409 {
410     BOOLEAN ret = TRUE;
411     PCHAR nlaData = NlMsgPutHeadUnspecUninit(buf, type, 0);
412
413     if (!nlaData) {
414         ret = FALSE;
415     }
416
417     return ret;
418 }
419
420 /*
421  * ---------------------------------------------------------------------------
422  * Adds an attribute of 'type' and 8 bit payload at the head of buffer.
423  * Refer nl_msg_push_u8 for more details.
424  * ---------------------------------------------------------------------------
425  */
426 BOOLEAN
427 NlMsgPutHeadU8(PNL_BUFFER buf, UINT16 type, UINT8 value)
428 {
429     return (NlMsgPutHeadUnspec(buf, type, (PCHAR)(&value), sizeof(value)));
430 }
431
432 /*
433  * ---------------------------------------------------------------------------
434  * Adds an attribute of 'type' and 16 bit payload at the head of buffer.
435  * Refer nl_msg_push_u16 for more details.
436  * ---------------------------------------------------------------------------
437  */
438 BOOLEAN
439 NlMsgPutHeadU16(PNL_BUFFER buf, UINT16 type, UINT16 value)
440 {
441     return (NlMsgPutHeadUnspec(buf, type, (PCHAR)(&value), sizeof(value)));
442 }
443
444 /*
445  * ---------------------------------------------------------------------------
446  * Adds an attribute of 'type' and 32 bit payload at the head of buffer.
447  * Refer nl_msg_push_u32 for more details.
448  * ---------------------------------------------------------------------------
449  */
450 BOOLEAN
451 NlMsgPutHeadU32(PNL_BUFFER buf, UINT16 type, UINT32 value)
452 {
453     return (NlMsgPutHeadUnspec(buf, type, (PCHAR)(&value), sizeof(value)));
454 }
455
456 /*
457  * ---------------------------------------------------------------------------
458  * Adds an attribute of 'type' and 64 bit payload at the head of buffer.
459  * Refer nl_msg_push_u64 for more details.
460  * ---------------------------------------------------------------------------
461  */
462 BOOLEAN
463 NlMsgPutHeadU64(PNL_BUFFER buf, UINT16 type, UINT64 value)
464 {
465     return (NlMsgPutHeadUnspec(buf, type, (PCHAR)(&value), sizeof(value)));
466 }
467
468 /*
469  * ---------------------------------------------------------------------------
470  * Adds an attribute of 'type' and string payload.
471  * Refer nl_msg_push_string for more details.
472  * ---------------------------------------------------------------------------
473  */
474 BOOLEAN
475 NlMsgPutHeadString(PNL_BUFFER buf, UINT16 type, PCHAR value)
476 {
477     size_t strLen = strlen(value) + 1;
478 #ifdef DBG
479     /* Attribute length should come within 16 bits (NL_ATTR).
480      * Not a likely case, hence validation only in debug mode. */
481     if ((strLen + PAD_SIZE(strLen, NLA_ALIGNTO)) > MAXUINT16) {
482         return FALSE;
483     }
484 #endif
485
486     /* typecast to keep compiler happy */
487     return (NlMsgPutHeadUnspec(buf, type, value,
488                                (UINT16)strLen));
489 }
490
491 /*
492  * ---------------------------------------------------------------------------
493  * Adds the header for nested netlink attributes. It
494  * returns the offset of this header. If addition of header fails
495  * then returned value of offset will be zero.
496  * Refer nl_msg_start_nested for more details.
497  * ---------------------------------------------------------------------------
498  */
499 UINT32
500 NlMsgStartNested(PNL_BUFFER buf, UINT16 type)
501 {
502     UINT32 offset = NlBufSize(buf);
503     PCHAR nlaData = NULL;
504
505     nlaData = NlMsgPutTailUnspecUninit(buf, type, 0);
506
507     if (!nlaData) {
508         /* Value zero must be reated as error by the caller.
509          * This is because an attribute can never be added
510          * at offset zero, it will always come after NL_MSG_HDR,
511          * GENL_HDR and OVS_HEADER. */
512         offset = 0;
513     }
514
515     return offset;
516 }
517
518 /*
519  * ---------------------------------------------------------------------------
520  * Finalizes the nested netlink attribute by updating the nla_len.
521  * offset should be the one returned by NlMsgStartNested.
522  * Refer nl_msg_end_nested for more details.
523  * ---------------------------------------------------------------------------
524  */
525 VOID
526 NlMsgEndNested(PNL_BUFFER buf, UINT32 offset)
527 {
528     PNL_ATTR attr = (PNL_ATTR)(NlBufAt(buf, offset, sizeof *attr));
529
530     /* Typecast to keep compiler happy.
531      * Attribute length would never exceed MAX UINT16.*/
532     attr->nlaLen = (UINT16)(NlBufSize(buf) - offset);
533 }
534
535 /*
536  * --------------------------------------------------------------------------
537  * Appends a nested Netlink attribute of the given 'type', with the 'size'
538  * bytes of content starting at 'data', to 'msg'.
539  * Refer nl_msg_put_nested for more details.
540  * --------------------------------------------------------------------------
541  */
542 VOID
543 NlMsgPutNested(PNL_BUFFER buf, UINT16 type,
544                const PVOID data, UINT32 size)
545 {
546     UINT32 offset = NlMsgStartNested(buf, type);
547     BOOLEAN ret = FALSE;
548
549     ASSERT(offset);
550
551     ret = NlMsgPutTail(buf, data, size);
552
553     ASSERT(ret);
554
555     NlMsgEndNested(buf, offset);
556 }
557
558 /* Accessing netlink message payload */
559
560 /*
561  * ---------------------------------------------------------------------------
562  * Netlink message accessing the payload.
563  * ---------------------------------------------------------------------------
564  */
565 PVOID
566 NlMsgAt(const PNL_MSG_HDR nlh, UINT32 offset)
567 {
568     return ((PCHAR)nlh + offset);
569 }
570
571 /*
572  * ---------------------------------------------------------------------------
573  * Returns the size of netlink message.
574  * ---------------------------------------------------------------------------
575  */
576 UINT32
577 NlMsgSize(const PNL_MSG_HDR nlh)
578 {
579     return nlh->nlmsgLen;
580 }
581
582 /*
583  * ---------------------------------------------------------------------------
584  * Aligns the size of Netlink message.
585  * ---------------------------------------------------------------------------
586  */
587 VOID
588 NlMsgAlignSize(const PNL_MSG_HDR nlh)
589 {
590     nlh->nlmsgLen = NLMSG_ALIGN(nlh->nlmsgLen);
591     return;
592 }
593
594 /*
595  * ---------------------------------------------------------------------------
596  * Sets the size of Netlink message.
597  * ---------------------------------------------------------------------------
598  */
599 VOID
600 NlMsgSetSize(const PNL_MSG_HDR nlh, UINT32 msgLen)
601 {
602     nlh->nlmsgLen = msgLen;
603 }
604
605 /*
606  * ---------------------------------------------------------------------------
607  * Returns pointer to nlmsg payload.
608  * ---------------------------------------------------------------------------
609  */
610 PCHAR
611 NlHdrPayload(const PNL_MSG_HDR nlh)
612 {
613     return ((PCHAR)nlh + NLMSG_HDRLEN);
614 }
615
616 /*
617  * ---------------------------------------------------------------------------
618  * Returns length of nlmsg payload.
619  * ---------------------------------------------------------------------------
620  */
621 UINT32
622 NlHdrPayloadLen(const PNL_MSG_HDR nlh)
623 {
624     return nlh->nlmsgLen - NLMSG_HDRLEN;
625 }
626
627 /*
628  * ---------------------------------------------------------------------------
629  * Returns pointer to nlmsg attributes.
630  * ---------------------------------------------------------------------------
631  */
632 PNL_ATTR
633 NlMsgAttrs(const PNL_MSG_HDR nlh)
634 {
635     return (PNL_ATTR) (NlHdrPayload(nlh) + GENL_HDRLEN + OVS_HDRLEN);
636 }
637
638 /*
639  * ---------------------------------------------------------------------------
640  * Returns size of to nlmsg attributes.
641  * ---------------------------------------------------------------------------
642  */
643 UINT32
644 NlMsgAttrsLen(const PNL_MSG_HDR nlh)
645 {
646     return NlHdrPayloadLen(nlh) - GENL_HDRLEN - OVS_HDRLEN;
647 }
648
649 /* Netlink message parse. */
650
651 /*
652  * ---------------------------------------------------------------------------
653  * Returns next netlink message in the stream.
654  * ---------------------------------------------------------------------------
655  */
656 PNL_MSG_HDR
657 NlMsgNext(const PNL_MSG_HDR nlh)
658 {
659     return (PNL_MSG_HDR)((PCHAR)nlh +
660             NLMSG_ALIGN(nlh->nlmsgLen));
661 }
662
663 /*
664  * ---------------------------------------------------------------------------
665  * Netlink Attr helper APIs.
666  * ---------------------------------------------------------------------------
667  */
668 INT
669 NlAttrIsValid(const PNL_ATTR nla, UINT32 maxlen)
670 {
671     return (maxlen >= sizeof *nla
672             && nla->nlaLen >= sizeof *nla
673             && nla->nlaLen <= maxlen);
674 }
675
676 /*
677  * ---------------------------------------------------------------------------
678  * Returns alligned length of the attribute.
679  * ---------------------------------------------------------------------------
680  */
681 UINT32
682 NlAttrLenPad(const PNL_ATTR nla, UINT32 maxlen)
683 {
684     UINT32 len = NLA_ALIGN(nla->nlaLen);
685
686     return len <= maxlen ? len : nla->nlaLen;
687 }
688
689 /*
690  * ---------------------------------------------------------------------------
691  * Default minimum payload size for each type of attribute.
692  * ---------------------------------------------------------------------------
693  */
694 UINT32
695 NlAttrMinLen(NL_ATTR_TYPE type)
696 {
697     switch (type) {
698     case NL_A_NO_ATTR: return 0;
699     case NL_A_UNSPEC: return 0;
700     case NL_A_U8: return 1;
701     case NL_A_U16: return 2;
702     case NL_A_U32: return 4;
703     case NL_A_U64: return 8;
704     case NL_A_STRING: return 1;
705     case NL_A_FLAG: return 0;
706     case NL_A_NESTED: return 0;
707     case N_NL_ATTR_TYPES:
708     default:
709     OVS_LOG_WARN("Unsupprted attribute type: %d", type);
710     ASSERT(0);
711     }
712
713     /* To keep compiler happy */
714     return 0;
715 }
716
717 /*
718  * ---------------------------------------------------------------------------
719  * Default maximum payload size for each type of attribute.
720  * ---------------------------------------------------------------------------
721  */
722 UINT32
723 NlAttrMaxLen(NL_ATTR_TYPE type)
724 {
725     switch (type) {
726     case NL_A_NO_ATTR: return SIZE_MAX;
727     case NL_A_UNSPEC: return SIZE_MAX;
728     case NL_A_U8: return 1;
729     case NL_A_U16: return 2;
730     case NL_A_U32: return 4;
731     case NL_A_U64: return 8;
732     case NL_A_STRING: return MAXUINT16;
733     case NL_A_FLAG: return SIZE_MAX;
734     case NL_A_NESTED: return SIZE_MAX;
735     case N_NL_ATTR_TYPES:
736     default:
737     OVS_LOG_WARN("Unsupprted attribute type: %d", type);
738     ASSERT(0);
739     }
740
741     /* To keep compiler happy */
742     return 0;
743 }
744
745 /* Netlink attribute iteration. */
746
747 /*
748  * ---------------------------------------------------------------------------
749  * Returns the next attribute.
750  * ---------------------------------------------------------------------------
751  */
752 PNL_ATTR
753 NlAttrNext(const PNL_ATTR nla)
754 {
755     return (PNL_ATTR)((UINT8 *)nla + NLA_ALIGN(nla->nlaLen));
756 }
757
758 /*
759  * --------------------------------------------------------------------------
760  * Returns the bits of 'nla->nlaType' that are significant for determining
761  * its type.
762  * --------------------------------------------------------------------------
763  */
764 UINT16
765 NlAttrType(const PNL_ATTR nla)
766 {
767    return nla->nlaType & NLA_TYPE_MASK;
768 }
769
770 /*
771  * --------------------------------------------------------------------------
772  * Returns the netlink attribute data.
773  * --------------------------------------------------------------------------
774  */
775 PVOID
776 NlAttrData(const PNL_ATTR nla)
777 {
778     return ((PCHAR)nla + NLA_HDRLEN);
779 }
780
781 /*
782  * ---------------------------------------------------------------------------
783  * Returns the number of bytes in the payload of attribute 'nla'.
784  * ---------------------------------------------------------------------------
785  */
786 UINT32
787 NlAttrGetSize(const PNL_ATTR nla)
788 {
789     return nla->nlaLen - NLA_HDRLEN;
790 }
791
792 /*
793  * ---------------------------------------------------------------------------
794  * Returns the first byte in the payload of attribute 'nla'.
795  * ---------------------------------------------------------------------------
796  */
797 const PVOID
798 NlAttrGet(const PNL_ATTR nla)
799 {
800     ASSERT(nla->nlaLen >= NLA_HDRLEN);
801     return nla + 1;
802 }
803
804 /*
805  * ---------------------------------------------------------------------------
806  * Asserts that 'nla''s payload is at least 'size' bytes long, and returns the
807  * first byte of the payload.
808  * ---------------------------------------------------------------------------
809  */
810 const
811 PVOID NlAttrGetUnspec(const PNL_ATTR nla, UINT32 size)
812 {
813     UNREFERENCED_PARAMETER(size);
814     ASSERT(nla->nlaLen >= NLA_HDRLEN + size);
815     return nla + 1;
816 }
817
818 /*
819  * ---------------------------------------------------------------------------
820  * Returns the 64-bit network byte order value in 'nla''s payload.
821  *
822  * Asserts that 'nla''s payload is at least 8 bytes long.
823  * ---------------------------------------------------------------------------
824  */
825 BE64
826 NlAttrGetBe64(const PNL_ATTR nla)
827 {
828     return NL_ATTR_GET_AS(nla, BE64);
829 }
830
831 /*
832  * ---------------------------------------------------------------------------
833  * Returns the 32-bit network byte order value in 'nla''s payload.
834  *
835  * Asserts that 'nla''s payload is at least 4 bytes long.
836  * ---------------------------------------------------------------------------
837  */
838 BE32
839 NlAttrGetBe32(const PNL_ATTR nla)
840 {
841     return NL_ATTR_GET_AS(nla, BE32);
842 }
843
844 /*
845  * ---------------------------------------------------------------------------
846  * Returns the 16-bit network byte order value in 'nla''s payload.
847  *
848  * Asserts that 'nla''s payload is at least 2 bytes long.
849  * ---------------------------------------------------------------------------
850  */
851 BE16
852 NlAttrGetBe16(const PNL_ATTR nla)
853 {
854     return NL_ATTR_GET_AS(nla, BE16);
855 }
856
857 /*
858  * ---------------------------------------------------------------------------
859  * Returns the 8-bit network byte order value in 'nla''s payload.
860  *
861  * Asserts that 'nla''s payload is at least 1 byte long.
862  * ---------------------------------------------------------------------------
863  */
864 BE8
865 NlAttrGetBe8(const PNL_ATTR nla)
866 {
867     return NL_ATTR_GET_AS(nla, BE8);
868 }
869
870 /*
871  * ---------------------------------------------------------------------------
872  * Returns the 8-bit value in 'nla''s payload.
873  * ---------------------------------------------------------------------------
874  */
875 UINT8
876 NlAttrGetU8(const PNL_ATTR nla)
877 {
878     return NL_ATTR_GET_AS(nla, UINT8);
879 }
880
881 /*
882  * ---------------------------------------------------------------------------
883  * Returns the 16-bit host byte order value in 'nla''s payload.
884  * Asserts that 'nla''s payload is at least 2 bytes long.
885  * ---------------------------------------------------------------------------
886  */
887 UINT16
888 NlAttrGetU16(const PNL_ATTR nla)
889 {
890     return NL_ATTR_GET_AS(nla, UINT16);
891 }
892
893 /*
894  * ---------------------------------------------------------------------------
895  * Returns the 32-bit host byte order value in 'nla''s payload.
896  * Asserts that 'nla''s payload is at least 4 bytes long.
897  * ---------------------------------------------------------------------------
898  */
899 UINT32
900 NlAttrGetU32(const PNL_ATTR nla)
901 {
902     return NL_ATTR_GET_AS(nla, UINT32);
903 }
904
905 /*
906  * ---------------------------------------------------------------------------
907  * Returns the 64-bit host byte order value in 'nla''s payload.
908  * Asserts that 'nla''s payload is at least 8 bytes long.
909  * ---------------------------------------------------------------------------
910  */
911 UINT64
912 NlAttrGetU64(const PNL_ATTR nla)
913 {
914     return NL_ATTR_GET_AS(nla, UINT64);
915 }
916
917 /*
918  * ---------------------------------------------------------------------------
919  * Validate the netlink attribute against the policy
920  * ---------------------------------------------------------------------------
921  */
922 BOOLEAN
923 NlAttrValidate(const PNL_ATTR nla, const PNL_POLICY policy)
924 {
925     UINT32 minLen;
926     UINT32 maxLen;
927     UINT32 len;
928     BOOLEAN ret = FALSE;
929
930     if ((policy->type == NL_A_NO_ATTR) ||
931         (policy->type == NL_A_VAR_LEN) ||
932         (policy->type == NL_A_NESTED)) {
933         /* Do not validate anything for attributes of type var length */
934         ret = TRUE;
935         goto done;
936     }
937
938     /* Figure out min and max length. */
939     minLen = policy->minLen;
940     if (!minLen) {
941         minLen = NlAttrMinLen(policy->type);
942     }
943     maxLen = policy->maxLen;
944     if (!maxLen) {
945         maxLen = NlAttrMaxLen(policy->type);
946     }
947
948     /* Verify length. */
949     len = NlAttrGetSize(nla);
950     if (len < minLen || len > maxLen) {
951         OVS_LOG_WARN("Attribute: %p, len: %d, not in valid range, "
952                      "min: %d, max: %d", nla, len, minLen, maxLen);
953         goto done;
954     }
955
956     /* Strings must be null terminated and must not have embedded nulls. */
957     if (policy->type == NL_A_STRING) {
958         if (((PCHAR) nla)[nla->nlaLen - 1]) {
959             OVS_LOG_WARN("Attributes %p lacks null at the end", nla);
960             goto done;
961         }
962
963         if (memchr(nla + 1, '\0', len - 1) != NULL) {
964             OVS_LOG_WARN("Attributes %p has bad length", nla);
965             goto done;
966         }
967     }
968
969     ret = TRUE;
970
971 done:
972     return ret;
973 }
974
975 /*
976  * ---------------------------------------------------------------------------
977  * Returns an attribute of type 'type' from a series of
978  * attributes.
979  * ---------------------------------------------------------------------------
980  */
981 const PNL_ATTR
982 NlAttrFind__(const PNL_ATTR attrs, UINT32 size, UINT16 type)
983 {
984     PNL_ATTR iter = NULL;
985     PNL_ATTR ret = NULL;
986     UINT32 left;
987
988     NL_ATTR_FOR_EACH (iter, left, attrs, size) {
989         if (NlAttrType(iter) == type) {
990             ret = iter;
991             goto done;
992         }
993     }
994
995 done:
996     return ret;
997 }
998
999 /*
1000  * ---------------------------------------------------------------------------
1001  * Returns the first Netlink attribute within 'nla' with the specified
1002  * 'type'.
1003  *
1004  * This function does not validate the attribute's length.
1005  * ---------------------------------------------------------------------------
1006  */
1007 const PNL_ATTR
1008 NlAttrFindNested(const PNL_ATTR nla, UINT16 type)
1009 {
1010     return NlAttrFind__((const PNL_ATTR)(NlAttrGet(nla)),
1011                          NlAttrGetSize(nla), type);
1012 }
1013
1014 /*
1015  *----------------------------------------------------------------------------
1016  * Parses the netlink message at a given offset (attrOffset)
1017  * as a series of attributes. A pointer to the attribute with type
1018  * 'type' is stored in attrs at index 'type'. policy is used to define the
1019  * attribute type validation parameters.
1020  * 'nla_offset' should be NLMSG_HDRLEN + GENL_HDRLEN + OVS_HEADER
1021  *
1022  * Returns BOOLEAN to indicate success/failure.
1023  *----------------------------------------------------------------------------
1024  */
1025 BOOLEAN
1026 NlAttrParse(const PNL_MSG_HDR nlMsg, UINT32 attrOffset,
1027             UINT32 totalAttrLen,
1028             const NL_POLICY policy[],
1029             PNL_ATTR attrs[], UINT32 n_attrs)
1030 {
1031     PNL_ATTR nla;
1032     UINT32 left;
1033     UINT32 iter;
1034     BOOLEAN ret = FALSE;
1035
1036     RtlZeroMemory(attrs, n_attrs * sizeof *attrs);
1037
1038
1039     /* There is nothing to parse */
1040     if (!(NlMsgAttrsLen(nlMsg))) {
1041         ret = TRUE;
1042         goto done;
1043     }
1044
1045     if ((NlMsgSize(nlMsg) < attrOffset)) {
1046         OVS_LOG_WARN("No attributes in nlMsg: %p at offset: %d",
1047                      nlMsg, attrOffset);
1048         goto done;
1049     }
1050
1051     NL_ATTR_FOR_EACH (nla, left, NlMsgAt(nlMsg, attrOffset),
1052                       totalAttrLen)
1053     {
1054         UINT16 type = NlAttrType(nla);
1055         if (type < n_attrs && policy[type].type != NL_A_NO_ATTR) {
1056             /* Typecasting to keep the compiler happy */
1057             const PNL_POLICY e = (const PNL_POLICY)(&policy[type]);
1058             if (!NlAttrValidate(nla, e)) {
1059                 goto done;
1060             }
1061
1062             if (attrs[type]) {
1063                 OVS_LOG_WARN("Duplicate attribute in nlMsg: %p, "
1064                              "type: %u", nlMsg, type);
1065             }
1066
1067             attrs[type] = nla;
1068         }
1069     }
1070
1071     if (left) {
1072         OVS_LOG_ERROR("Attributes followed by garbage");
1073         goto done;
1074     }
1075
1076     for (iter = 0; iter < n_attrs; iter++) {
1077         const PNL_POLICY e = (const PNL_POLICY)(&policy[iter]);
1078         if (!e->optional && e->type != NL_A_NO_ATTR && !attrs[iter]) {
1079             OVS_LOG_ERROR("Required attr:%d missing", iter);
1080             goto done;
1081         }
1082     }
1083
1084     ret = TRUE;
1085
1086 done:
1087     return ret;
1088 }
1089
1090 /*
1091  *----------------------------------------------------------------------------
1092  * Parses the netlink message for nested attributes. attrOffset must be the
1093  * offset of nla which is the header of the nested attribute series.
1094  * Refer nl_parse_nested for more details.
1095  *
1096  * Returns BOOLEAN to indicate success/failure.
1097  *----------------------------------------------------------------------------
1098  */
1099 BOOLEAN
1100 NlAttrParseNested(const PNL_MSG_HDR nlMsg, UINT32 attrOffset,
1101                   UINT32 totalAttrLen,
1102                   const NL_POLICY policy[],
1103                   PNL_ATTR attrs[], UINT32 n_attrs)
1104 {
1105     return NlAttrParse(nlMsg, attrOffset + NLA_HDRLEN,
1106                        totalAttrLen - NLA_HDRLEN, policy, attrs, n_attrs);
1107 }