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