netlink.c 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. /*++
  2. Copyright (c) 2016 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. netlink.c
  9. Abstract:
  10. This module implements the netlink library functions.
  11. Author:
  12. Chris Stevens 24-Mar-2016
  13. Environment:
  14. User Mode
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "netlinkp.h"
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <errno.h>
  23. //
  24. // --------------------------------------------------------------------- Macros
  25. //
  26. //
  27. // This macro returns the aligned size of the netlink message buffer structure.
  28. //
  29. #define NL_MESSAGE_BUFFER_SIZE NETLINK_ALIGN(sizeof(NL_MESSAGE_BUFFER))
  30. //
  31. // ---------------------------------------------------------------- Definitions
  32. //
  33. //
  34. // ------------------------------------------------------ Data Type Definitions
  35. //
  36. //
  37. // ----------------------------------------------- Internal Function Prototypes
  38. //
  39. KSTATUS
  40. NetlinkpConvertToNetworkAddress (
  41. const struct sockaddr *Address,
  42. socklen_t AddressLength,
  43. PNETWORK_ADDRESS NetworkAddress
  44. );
  45. /*++
  46. Routine Description:
  47. This routine converts a sockaddr address structure into a network address
  48. structure.
  49. Arguments:
  50. Address - Supplies a pointer to the address structure.
  51. AddressLength - Supplies the length of the address structure in bytes.
  52. NetworkAddress - Supplies a pointer where the corresponding network address
  53. will be returned.
  54. Return Value:
  55. STATUS_SUCCESS on success.
  56. STATUS_INVALID_ADDRESS on failure.
  57. --*/
  58. KSTATUS
  59. NetlinkpConvertFromNetworkAddress (
  60. PNETWORK_ADDRESS NetworkAddress,
  61. struct sockaddr *Address,
  62. socklen_t *AddressLength
  63. );
  64. /*++
  65. Routine Description:
  66. This routine converts a network address structure into a sockaddr structure.
  67. Arguments:
  68. NetworkAddress - Supplies a pointer to the network address to convert.
  69. Address - Supplies a pointer where the address structure will be returned.
  70. AddressLength - Supplies a pointer that on input contains the length of the
  71. specified Address structure, and on output returns the length of the
  72. returned address. If the supplied buffer is not big enough to hold the
  73. address, the address is truncated, and the larger needed buffer size
  74. will be returned here.
  75. Return Value:
  76. STATUS_SUCCESS on success.
  77. STATUS_BUFFER_TOO_SMALL if the address buffer is not big enough.
  78. STATUS_INVALID_ADDRESS on failure.
  79. --*/
  80. //
  81. // -------------------------------------------------------------------- Globals
  82. //
  83. CL_NETWORK_CONVERSION_INTERFACE NetlinkAddressConversionInterface = {
  84. CL_NETWORK_CONVERSION_INTERFACE_VERSION,
  85. AF_NETLINK,
  86. NetDomainNetlink,
  87. NetlinkpConvertToNetworkAddress,
  88. NetlinkpConvertFromNetworkAddress
  89. };
  90. //
  91. // ------------------------------------------------------------------ Functions
  92. //
  93. //
  94. // TODO: Make this a constructor.
  95. //
  96. LIBNETLINK_API
  97. VOID
  98. NlInitialize (
  99. PVOID Environment
  100. )
  101. /*++
  102. Routine Description:
  103. This routine initializes the Minoca Netlink Library. This routine is
  104. normally called by statically linked assembly within a program, and unless
  105. developing outside the usual paradigm should not need to call this routine
  106. directly.
  107. Arguments:
  108. Environment - Supplies a pointer to the environment information.
  109. Return Value:
  110. None.
  111. --*/
  112. {
  113. ClRegisterTypeConversionInterface(ClConversionNetworkAddress,
  114. &NetlinkAddressConversionInterface,
  115. TRUE);
  116. return;
  117. }
  118. LIBNETLINK_API
  119. INT
  120. NlCreateSocket (
  121. ULONG Protocol,
  122. ULONG PortId,
  123. ULONG Flags,
  124. PNL_SOCKET *NewSocket
  125. )
  126. /*++
  127. Routine Description:
  128. This routine creates a netlink socket with the given protocol and port ID.
  129. Arguments:
  130. Protocol - Supplies the netlink protocol to use for the socket.
  131. PortId - Supplies a specific port ID to use for the socket, if available.
  132. Supply NL_ANY_PORT_ID to have the socket dynamically bind to an
  133. available port ID.
  134. Flags - Supplies a bitmask of netlink socket flags. See NL_SOCKET_FLAG_*
  135. for definitions.
  136. NewSocket - Supplies a pointer that receives a pointer to the newly created
  137. socket.
  138. Return Value:
  139. 0 on success.
  140. -1 on error, and the errno variable will be set to contain more information.
  141. --*/
  142. {
  143. socklen_t AddressLength;
  144. PNL_SOCKET Socket;
  145. INT Status;
  146. Socket = malloc(sizeof(NL_SOCKET));
  147. if (Socket == NULL) {
  148. errno = ENOMEM;
  149. return -1;
  150. }
  151. memset(Socket, 0, sizeof(NL_SOCKET));
  152. Status = NlAllocateBuffer(NETLINK_SCRATCH_BUFFER_SIZE,
  153. &(Socket->ReceiveBuffer));
  154. if (Status != 0) {
  155. goto CreateSocketEnd;
  156. }
  157. Socket->Protocol = Protocol;
  158. Socket->Flags = Flags;
  159. Socket->Socket = socket(AF_NETLINK, SOCK_DGRAM, Protocol);
  160. if (Socket->Socket == -1) {
  161. Status = -1;
  162. goto CreateSocketEnd;
  163. }
  164. //
  165. // Bind the socket. If the supplied port ID is NL_ANY_PORT_ID, then an
  166. // ephemeral port will be assign. Otherwise the socket will be bound to the
  167. // given port if it's available.
  168. //
  169. AddressLength = sizeof(struct sockaddr_nl);
  170. Socket->LocalAddress.nl_family = AF_NETLINK;
  171. Socket->LocalAddress.nl_pid = PortId;
  172. Status = bind(Socket->Socket,
  173. (struct sockaddr *)&(Socket->LocalAddress),
  174. AddressLength);
  175. if (Status != 0) {
  176. goto CreateSocketEnd;
  177. }
  178. Status = getsockname(Socket->Socket,
  179. (struct sockaddr *)&(Socket->LocalAddress),
  180. &AddressLength);
  181. if (Status != 0) {
  182. goto CreateSocketEnd;
  183. }
  184. ASSERT((Socket->LocalAddress.nl_pid != NL_ANY_PORT_ID) &&
  185. (Socket->LocalAddress.nl_pid != NETLINK_KERNEL_PORT_ID));
  186. CreateSocketEnd:
  187. if (Status != 0) {
  188. if (Socket != NULL) {
  189. NlDestroySocket(Socket);
  190. Socket = NULL;
  191. }
  192. }
  193. *NewSocket = Socket;
  194. return Status;
  195. }
  196. LIBNETLINK_API
  197. VOID
  198. NlDestroySocket (
  199. PNL_SOCKET Socket
  200. )
  201. /*++
  202. Routine Description:
  203. This routine destroys a netlink socket and all its resources.
  204. Arguments:
  205. Socket - Supplies a pointer to the netlink socket to destroy.
  206. Return Value:
  207. None.
  208. --*/
  209. {
  210. if (Socket->Socket != -1) {
  211. close(Socket->Socket);
  212. }
  213. if (Socket->ReceiveBuffer != NULL) {
  214. NlFreeBuffer(Socket->ReceiveBuffer);
  215. }
  216. free(Socket);
  217. return;
  218. }
  219. LIBNETLINK_API
  220. INT
  221. NlAllocateBuffer (
  222. ULONG Size,
  223. PNL_MESSAGE_BUFFER *NewBuffer
  224. )
  225. /*++
  226. Routine Description:
  227. This routine allocates a netlink message buffer. It always adds on space
  228. for the base netlink message header.
  229. Arguments:
  230. Size - Supplies the number of data bytes needed.
  231. NewBuffer - Supplies a pointer where a pointer to the new allocation will
  232. be returned on success.
  233. Return Value:
  234. 0 on success.
  235. -1 on error, and the errno variable will be set to contain more information.
  236. --*/
  237. {
  238. PNL_MESSAGE_BUFFER Buffer;
  239. INT Status;
  240. ULONG TotalSize;
  241. Buffer = NULL;
  242. Status = -1;
  243. if (Size != NETLINK_ALIGN(Size)) {
  244. errno = EINVAL;
  245. goto AllocateBufferEnd;
  246. }
  247. Size = NETLINK_ALIGN(Size);
  248. TotalSize = NETLINK_HEADER_LENGTH + Size;
  249. if (TotalSize < Size) {
  250. errno = EINVAL;
  251. goto AllocateBufferEnd;
  252. }
  253. Buffer = malloc(TotalSize + NL_MESSAGE_BUFFER_SIZE);
  254. if (Buffer == NULL) {
  255. errno = ENOMEM;
  256. goto AllocateBufferEnd;
  257. }
  258. Buffer->Buffer = (PVOID)Buffer + NL_MESSAGE_BUFFER_SIZE;
  259. Buffer->BufferSize = TotalSize;
  260. Buffer->DataSize = 0;
  261. Buffer->CurrentOffset = 0;
  262. Status = 0;
  263. AllocateBufferEnd:
  264. if (Status != 0) {
  265. if (Buffer != NULL) {
  266. free(Buffer);
  267. Buffer = NULL;
  268. }
  269. }
  270. *NewBuffer = Buffer;
  271. return Status;
  272. }
  273. LIBNETLINK_API
  274. VOID
  275. NlFreeBuffer (
  276. PNL_MESSAGE_BUFFER Buffer
  277. )
  278. /*++
  279. Routine Description:
  280. This routine frees a previously allocated netlink message buffer.
  281. Arguments:
  282. Buffer - Supplies a pointer to the buffer to be released.
  283. Return Value:
  284. None.
  285. --*/
  286. {
  287. free(Buffer);
  288. return;
  289. }
  290. LIBNETLINK_API
  291. INT
  292. NlAppendHeader (
  293. PNL_SOCKET Socket,
  294. PNL_MESSAGE_BUFFER Message,
  295. ULONG PayloadLength,
  296. ULONG SequenceNumber,
  297. USHORT Type,
  298. USHORT Flags
  299. )
  300. /*++
  301. Routine Description:
  302. This routine appends a base netlink header to the message. It will make
  303. sure there is enough room left in the supplied message buffer, add the
  304. header before at the current offset and update the offset and valid data
  305. size when complete. It always adds the ACK and REQUEST flags.
  306. Arguments:
  307. Socket - Supplies a pointer to the netlink socket that is sending the
  308. message.
  309. Message - Supplies a pointer to the netlink message buffer to which the
  310. header should be appended.
  311. PayloadLength - Supplies the length of the message data payload, in bytes.
  312. This does not include the base netlink header length.
  313. SequenceNumber - Supplies the sequence number for the message. This value
  314. is ignored unless NL_SOCKET_FLAG_NO_AUTO_SEQUENCE is set in the socket.
  315. Type - Supplies the netlink message type.
  316. Flags - Supplies a bitmask of netlink message flags. See
  317. NETLINK_HEADER_FLAG_* for definitions.
  318. Return Value:
  319. 0 on success.
  320. -1 on error, and the errno variable will be set to contain more information.
  321. --*/
  322. {
  323. PNETLINK_HEADER Header;
  324. ULONG MessageLength;
  325. PayloadLength += NETLINK_HEADER_LENGTH;
  326. MessageLength = Message->BufferSize - Message->CurrentOffset;
  327. if (MessageLength < PayloadLength) {
  328. errno = ENOBUFS;
  329. return -1;
  330. }
  331. Flags |= NETLINK_HEADER_FLAG_ACK | NETLINK_HEADER_FLAG_REQUEST;
  332. Header = Message->Buffer + Message->CurrentOffset;
  333. Header->Length = PayloadLength;
  334. Header->Type = Type;
  335. Header->Flags = Flags;
  336. if ((Socket->Flags & NL_SOCKET_FLAG_NO_AUTO_SEQUENCE) != 0) {
  337. Header->SequenceNumber = SequenceNumber;
  338. } else {
  339. Header->SequenceNumber = RtlAtomicAdd32(&(Socket->SendNextSequence), 1);
  340. }
  341. Header->PortId = Socket->LocalAddress.nl_pid;
  342. //
  343. // Move the offset and data size to the first byte after the header.
  344. //
  345. Message->CurrentOffset += NETLINK_HEADER_LENGTH;
  346. Message->DataSize += NETLINK_HEADER_LENGTH;
  347. return 0;
  348. }
  349. LIBNETLINK_API
  350. INT
  351. NlSendMessage (
  352. PNL_SOCKET Socket,
  353. PNL_MESSAGE_BUFFER Message,
  354. ULONG PortId,
  355. ULONG GroupMask,
  356. PULONG BytesSent
  357. )
  358. /*++
  359. Routine Description:
  360. This routine sends a netlink message for the given socket.
  361. Arguments:
  362. Socket - Supplies a pointer to the netlink socket over which to send the
  363. message.
  364. Message - Supplies a pointer to the message to be sent. The routine will
  365. attempt to send the entire message between the data offset and footer
  366. offset.
  367. PortId - Supplies the port ID of the recipient of the message.
  368. GroupMask - Supplies the group mask of the message recipients.
  369. BytesSent - Supplies an optional pointer the receives the number of bytes
  370. sent on success.
  371. Return Value:
  372. 0 on success.
  373. -1 on error, and the errno variable will be set to contain more information.
  374. --*/
  375. {
  376. struct sockaddr_nl Address;
  377. ssize_t LocalBytesSent;
  378. INT Status;
  379. memset(&Address, 0, sizeof(struct sockaddr_nl));
  380. Address.nl_family = AF_NETLINK;
  381. Address.nl_pid = PortId;
  382. Address.nl_groups = GroupMask;
  383. LocalBytesSent = sendto(Socket->Socket,
  384. Message->Buffer,
  385. Message->DataSize,
  386. 0,
  387. (struct sockaddr *)&Address,
  388. sizeof(struct sockaddr_nl));
  389. if (LocalBytesSent < 0) {
  390. Status = -1;
  391. } else {
  392. if (BytesSent != NULL) {
  393. *BytesSent = LocalBytesSent;
  394. }
  395. Status = 0;
  396. }
  397. return Status;
  398. }
  399. LIBNETLINK_API
  400. INT
  401. NlReceiveMessage (
  402. PNL_SOCKET Socket,
  403. PNL_RECEIVE_PARAMETERS Parameters
  404. )
  405. /*++
  406. Routine Description:
  407. This routine receives one or more netlink messages, does some simple
  408. validation, handles the default netlink message types, and calls the given
  409. receive routine callback for each protocol layer message.
  410. Arguments:
  411. Socket - Supplies a pointer to the netlink socket over which to receive the
  412. message.
  413. Parameters - Supplies a pointer to the receive message parameters.
  414. Return Value:
  415. 0 on success.
  416. -1 on error, and the errno variable will be set to contain more information.
  417. --*/
  418. {
  419. struct sockaddr_nl Address;
  420. socklen_t AddressLength;
  421. INTN BytesRemaining;
  422. PINT Error;
  423. ULONG ErrorLength;
  424. KSTATUS ErrorStatus;
  425. INT ErrorValue;
  426. ULONG Flags;
  427. BOOL GroupMatch;
  428. PNETLINK_HEADER Header;
  429. PNL_MESSAGE_BUFFER Message;
  430. BOOL Multipart;
  431. BOOL PortMatch;
  432. BOOL ReceiveMore;
  433. INT Status;
  434. Flags = Parameters->Flags;
  435. Parameters->Flags = 0;
  436. Message = Socket->ReceiveBuffer;
  437. Multipart = FALSE;
  438. ReceiveMore = TRUE;
  439. while ((ReceiveMore != FALSE) || (Multipart != FALSE)) {
  440. Message->CurrentOffset = 0;
  441. Message->DataSize = 0;
  442. AddressLength = sizeof(struct sockaddr_nl);
  443. BytesRemaining = recvfrom(Socket->Socket,
  444. Message->Buffer,
  445. Message->BufferSize,
  446. 0,
  447. (struct sockaddr *)&Address,
  448. &AddressLength);
  449. if (BytesRemaining < 0) {
  450. Status = -1;
  451. goto ReceiveMessageEnd;
  452. }
  453. Message->DataSize = BytesRemaining;
  454. if ((AddressLength != sizeof(struct sockaddr_nl)) ||
  455. (Address.nl_family != AF_NETLINK)) {
  456. errno = EAFNOSUPPORT;
  457. Status = -1;
  458. goto ReceiveMessageEnd;
  459. }
  460. //
  461. // If supplied, validate the port and/or group. Skipping any messages
  462. // that do not match at least one of them.
  463. //
  464. PortMatch = TRUE;
  465. GroupMatch = TRUE;
  466. if (((Flags & NL_RECEIVE_FLAG_PORT_ID) != 0) &&
  467. (Address.nl_pid != Parameters->PortId)) {
  468. PortMatch = FALSE;
  469. }
  470. if (((Flags & NL_RECEIVE_FLAG_GROUP_MASK) != 0) &&
  471. ((Address.nl_groups & Parameters->GroupMask) == 0)) {
  472. GroupMatch = FALSE;
  473. }
  474. if ((PortMatch == FALSE) && (GroupMatch == FALSE)) {
  475. continue;
  476. }
  477. //
  478. // If the caller is not expecting an ACK, then do not wait for one.
  479. //
  480. if ((Flags & NL_RECEIVE_FLAG_NO_ACK_WAIT) != 0) {
  481. ReceiveMore = FALSE;
  482. }
  483. //
  484. // Process each message in the buffer.
  485. //
  486. while (BytesRemaining > 0) {
  487. Header = Message->Buffer + Message->CurrentOffset;
  488. if ((BytesRemaining < NETLINK_HEADER_LENGTH) ||
  489. (BytesRemaining < Header->Length)) {
  490. break;
  491. }
  492. //
  493. // If there is no multi-part flag, then there shouldn't be a reason
  494. // to read another message.
  495. //
  496. if ((Header->Flags & NETLINK_HEADER_FLAG_MULTIPART) != 0) {
  497. Multipart = TRUE;
  498. }
  499. //
  500. // Validate the sequence number, but skip this on multicast
  501. // messages. Sequence numbers don't make much sense for out-of-band
  502. // multicast messages.
  503. //
  504. if (((Socket->Flags & NL_SOCKET_FLAG_NO_AUTO_SEQUENCE) == 0) &&
  505. (Address.nl_pid == Socket->LocalAddress.nl_pid) &&
  506. (Header->SequenceNumber != Socket->ReceiveNextSequence)) {
  507. errno = EILSEQ;
  508. Status = -1;
  509. goto ReceiveMessageEnd;
  510. }
  511. //
  512. // If an error is received, stop receiving. If an ACK is received,
  513. // finish processing this set of messages, but don't read any more.
  514. //
  515. if (Header->Type == NETLINK_MESSAGE_TYPE_ERROR) {
  516. if (((Socket->Flags & NL_SOCKET_FLAG_NO_AUTO_SEQUENCE) == 0) &&
  517. (Address.nl_pid == Socket->LocalAddress.nl_pid)) {
  518. RtlAtomicAdd32(&(Socket->ReceiveNextSequence), 1);
  519. }
  520. ErrorLength = NETLINK_HEADER_LENGTH +
  521. sizeof(NETLINK_ERROR_MESSAGE);
  522. if (Header->Length < ErrorLength) {
  523. errno = ENOMSG;
  524. Status = -1;
  525. goto ReceiveMessageEnd;
  526. }
  527. //
  528. // Convert from KSTATUS to the C library value for errno.
  529. //
  530. Error = NETLINK_DATA(Header);
  531. ErrorStatus = (KSTATUS)*Error;
  532. ErrorValue = ClConvertKstatusToErrorNumber(ErrorStatus);
  533. //
  534. // If the library consumer did not specifically ask for KSTATUS
  535. // errors, then all error messages need to be converted.
  536. //
  537. if ((Socket->Flags & NL_SOCKET_FLAG_REPORT_KSTATUS) == 0) {
  538. *Error = ErrorValue;
  539. }
  540. if (!KSUCCESS(ErrorStatus)) {
  541. errno = ErrorValue;
  542. Status = -1;
  543. goto ReceiveMessageEnd;
  544. }
  545. //
  546. // Receives should not exit until an ACK has been seen, unless
  547. // the caller specifically requested to not wait.
  548. //
  549. if ((Flags & NL_RECEIVE_FLAG_NO_ACK_WAIT) == 0) {
  550. ReceiveMore = FALSE;
  551. }
  552. Parameters->Flags |= NL_RECEIVE_FLAG_ACK_RECEIVED;
  553. //
  554. // If this is the last message in a multi-part message, then stop
  555. // receiving more data.
  556. //
  557. } else if (Header->Type == NETLINK_MESSAGE_TYPE_DONE) {
  558. Multipart = FALSE;
  559. //
  560. // For all protocol layer messages, invoke the given callback.
  561. //
  562. } else if ((Parameters->ReceiveRoutine != NULL) &&
  563. (Header->Type >=
  564. NETLINK_MESSAGE_TYPE_PROTOCOL_MINIMUM)) {
  565. Parameters->ReceiveRoutine(Socket,
  566. &(Parameters->ReceiveContext),
  567. Header);
  568. }
  569. //
  570. // Skip along to the next message.
  571. //
  572. Message->CurrentOffset += NETLINK_ALIGN(Header->Length);
  573. BytesRemaining -= NETLINK_ALIGN(Header->Length);
  574. }
  575. }
  576. Status = 0;
  577. ReceiveMessageEnd:
  578. return Status;
  579. }
  580. LIBNETLINK_API
  581. INT
  582. NlAppendAttribute (
  583. PNL_MESSAGE_BUFFER Message,
  584. USHORT Type,
  585. PVOID Data,
  586. USHORT DataLength
  587. )
  588. /*++
  589. Routine Description:
  590. This routine appends a netlink attribute to the given message. It validates
  591. that there is enough space for the attribute and moves the message buffer's
  592. offset to the first byte after the attribute. It also updates the buffer's
  593. valid data size. The exception to this rule is if a NULL data buffer is
  594. supplied; the buffer's data offset and size will only be updated for the
  595. attribute's header.
  596. Arguments:
  597. Message - Supplies a pointer to the netlink message buffer to which the
  598. attribute will be added.
  599. Type - Supplies the netlink attribute type.
  600. Data - Supplies an optional pointer to the attribute data to be stored in
  601. the buffer. Even if no data buffer is supplied, a data length may be
  602. supplied for the case of child attributes that are yet to be appended.
  603. DataLength - Supplies the length of the data, in bytes.
  604. Return Value:
  605. 0 on success.
  606. -1 on error, and the errno variable will be set to contain more information.
  607. --*/
  608. {
  609. PNETLINK_ATTRIBUTE Attribute;
  610. ULONG AttributeLength;
  611. ULONG MessageLength;
  612. AttributeLength = NETLINK_ATTRIBUTE_SIZE(DataLength);
  613. MessageLength = Message->BufferSize - Message->CurrentOffset;
  614. if (MessageLength < AttributeLength) {
  615. return ENOBUFS;
  616. }
  617. Attribute = Message->Buffer + Message->CurrentOffset;
  618. Attribute->Length = NETLINK_ATTRIBUTE_LENGTH(DataLength);
  619. Attribute->Type = Type;
  620. if (Data != NULL) {
  621. RtlCopyMemory(NETLINK_ATTRIBUTE_DATA(Attribute), Data, DataLength);
  622. Message->CurrentOffset += AttributeLength;
  623. Message->DataSize += AttributeLength;
  624. } else {
  625. Message->CurrentOffset += NETLINK_ATTRIBUTE_HEADER_LENGTH;
  626. Message->DataSize += NETLINK_ATTRIBUTE_HEADER_LENGTH;
  627. }
  628. return 0;
  629. }
  630. LIBNETLINK_API
  631. INT
  632. NlGetAttribute (
  633. PVOID Attributes,
  634. ULONG AttributesLength,
  635. USHORT Type,
  636. PVOID *Data,
  637. PUSHORT DataLength
  638. )
  639. /*++
  640. Routine Description:
  641. This routine parses the given attributes buffer and returns a pointer to
  642. the desired attribute.
  643. Arguments:
  644. Attributes - Supplies a pointer to the start of the generic command
  645. attributes.
  646. AttributesLength - Supplies the length of the attributes buffer, in bytes.
  647. Type - Supplies the netlink generic attribute type.
  648. Data - Supplies a pointer that receives a pointer to the data for the
  649. requested attribute type.
  650. DataLength - Supplies a pointer that receives the length of the requested
  651. attribute data.
  652. Return Value:
  653. 0 on success.
  654. -1 on error, and the errno variable will be set to contain more information.
  655. --*/
  656. {
  657. PNETLINK_ATTRIBUTE Attribute;
  658. ULONG AttributeSize;
  659. Attribute = (PNETLINK_ATTRIBUTE)Attributes;
  660. while (AttributesLength != 0) {
  661. if ((AttributesLength < NETLINK_ATTRIBUTE_HEADER_LENGTH) ||
  662. (AttributesLength < Attribute->Length)) {
  663. break;
  664. }
  665. if (Attribute->Type == Type) {
  666. *DataLength = Attribute->Length - NETLINK_ATTRIBUTE_HEADER_LENGTH;
  667. *Data = NETLINK_ATTRIBUTE_DATA(Attribute);
  668. return 0;
  669. }
  670. AttributeSize = NETLINK_ALIGN(Attribute->Length);
  671. Attribute = (PVOID)Attribute + AttributeSize;
  672. AttributesLength -= AttributeSize;
  673. }
  674. errno = ENOENT;
  675. return -1;
  676. }
  677. //
  678. // --------------------------------------------------------- Internal Functions
  679. //
  680. KSTATUS
  681. NetlinkpConvertToNetworkAddress (
  682. const struct sockaddr *Address,
  683. socklen_t AddressLength,
  684. PNETWORK_ADDRESS NetworkAddress
  685. )
  686. /*++
  687. Routine Description:
  688. This routine converts a sockaddr address structure into a network address
  689. structure.
  690. Arguments:
  691. Address - Supplies a pointer to the address structure.
  692. AddressLength - Supplies the length of the address structure in bytes.
  693. NetworkAddress - Supplies a pointer where the corresponding network address
  694. will be returned.
  695. Return Value:
  696. STATUS_SUCCESS on success.
  697. STATUS_INVALID_ADDRESS on failure.
  698. --*/
  699. {
  700. struct sockaddr_nl *NetlinkAddress;
  701. if ((AddressLength < sizeof(struct sockaddr_nl)) ||
  702. (Address->sa_family != AF_NETLINK)) {
  703. return STATUS_INVALID_ADDRESS;
  704. }
  705. NetlinkAddress = (struct sockaddr_nl *)Address;
  706. NetworkAddress->Domain = NetDomainNetlink;
  707. NetworkAddress->Port = NetlinkAddress->nl_pid;
  708. NetworkAddress->Address[0] = (UINTN)NetlinkAddress->nl_groups;
  709. return STATUS_SUCCESS;
  710. }
  711. KSTATUS
  712. NetlinkpConvertFromNetworkAddress (
  713. PNETWORK_ADDRESS NetworkAddress,
  714. struct sockaddr *Address,
  715. socklen_t *AddressLength
  716. )
  717. /*++
  718. Routine Description:
  719. This routine converts a network address structure into a sockaddr structure.
  720. Arguments:
  721. NetworkAddress - Supplies a pointer to the network address to convert.
  722. Address - Supplies a pointer where the address structure will be returned.
  723. AddressLength - Supplies a pointer that on input contains the length of the
  724. specified Address structure, and on output returns the length of the
  725. returned address. If the supplied buffer is not big enough to hold the
  726. address, the address is truncated, and the larger needed buffer size
  727. will be returned here.
  728. Return Value:
  729. STATUS_SUCCESS on success.
  730. STATUS_BUFFER_TOO_SMALL if the address buffer is not big enough.
  731. STATUS_INVALID_ADDRESS on failure.
  732. --*/
  733. {
  734. UINTN CopySize;
  735. struct sockaddr_nl NetlinkAddress;
  736. KSTATUS Status;
  737. if (NetworkAddress->Domain != NetDomainNetlink) {
  738. return STATUS_INVALID_ADDRESS;
  739. }
  740. Status = STATUS_SUCCESS;
  741. NetlinkAddress.nl_family = AF_NETLINK;
  742. NetlinkAddress.nl_pad = 0;
  743. NetlinkAddress.nl_pid = NetworkAddress->Port;
  744. NetlinkAddress.nl_groups = (ULONG)NetworkAddress->Address[0];
  745. CopySize = sizeof(NetlinkAddress);
  746. if (CopySize > *AddressLength) {
  747. CopySize = *AddressLength;
  748. Status = STATUS_BUFFER_TOO_SMALL;
  749. }
  750. RtlCopyMemory(Address, &NetlinkAddress, CopySize);
  751. *AddressLength = sizeof(NetlinkAddress);
  752. return Status;
  753. }