genctrl.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /*++
  2. Copyright (c) 2016 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. genctrl.c
  5. Abstract:
  6. This module implements the generic netlink control family message handling.
  7. Author:
  8. Chris Stevens 10-Feb-2016
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. //
  16. // Typically, generic netlink families are supposed to be able to stand on
  17. // their own (i.e. be able to be implemented outside the core net library). For
  18. // the built-in ones, avoid including netcore.h, but still redefine those
  19. // functions that would otherwise generate imports. This, however, needs to
  20. // include generic.h to get access to the tree of families.
  21. //
  22. #define NET_API __DLLEXPORT
  23. #include <minoca/kernel/driver.h>
  24. #include <minoca/net/netdrv.h>
  25. #include <minoca/net/netlink.h>
  26. #include "generic.h"
  27. //
  28. // ---------------------------------------------------------------- Definitions
  29. //
  30. //
  31. // Define the multicast group indices. These must match the order of the
  32. // multicast group array below.
  33. //
  34. #define NETLINK_GENERIC_CONTROL_MULTICAST_NOTIFY 0
  35. //
  36. // ------------------------------------------------------ Data Type Definitions
  37. //
  38. //
  39. // ----------------------------------------------- Internal Function Prototypes
  40. //
  41. KSTATUS
  42. NetlinkpGenericControlGetFamily (
  43. PNET_SOCKET Socket,
  44. PNET_PACKET_BUFFER Packet,
  45. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  46. );
  47. KSTATUS
  48. NetlinkpGenericControlSendCommand (
  49. PNETLINK_GENERIC_FAMILY Family,
  50. PNETLINK_GENERIC_COMMAND_INFORMATION Command,
  51. PNETLINK_GENERIC_MULTICAST_GROUP Group
  52. );
  53. //
  54. // -------------------------------------------------------------------- Globals
  55. //
  56. NETLINK_GENERIC_COMMAND NetlinkGenericControlCommands[] = {
  57. {
  58. NETLINK_CONTROL_COMMAND_GET_FAMILY,
  59. 0,
  60. NetlinkpGenericControlGetFamily
  61. },
  62. };
  63. NETLINK_GENERIC_MULTICAST_GROUP NetlinkGenericControlMulticastGroups[] = {
  64. {
  65. NETLINK_GENERIC_CONTROL_MULTICAST_NOTIFY,
  66. sizeof(NETLINK_CONTROL_MULTICAST_NOTIFY_NAME),
  67. NETLINK_CONTROL_MULTICAST_NOTIFY_NAME
  68. },
  69. };
  70. NETLINK_GENERIC_FAMILY_PROPERTIES NetlinkGenericControlFamilyProperties = {
  71. NETLINK_GENERIC_FAMILY_PROPERTIES_VERSION,
  72. NETLINK_GENERIC_ID_CONTROL,
  73. sizeof(NETLINK_GENERIC_CONTROL_NAME),
  74. NETLINK_GENERIC_CONTROL_NAME,
  75. NetlinkGenericControlCommands,
  76. sizeof(NetlinkGenericControlCommands) /
  77. sizeof(NetlinkGenericControlCommands[0]),
  78. NetlinkGenericControlMulticastGroups,
  79. sizeof(NetlinkGenericControlMulticastGroups) /
  80. sizeof(NetlinkGenericControlMulticastGroups[0]),
  81. };
  82. //
  83. // Store a pointer to the netlink generic control family for easy access to
  84. // its multicast groups.
  85. //
  86. PNETLINK_GENERIC_FAMILY NetlinkGenericControlFamily = NULL;
  87. //
  88. // ------------------------------------------------------------------ Functions
  89. //
  90. VOID
  91. NetlinkpGenericControlInitialize (
  92. VOID
  93. )
  94. /*++
  95. Routine Description:
  96. This routine initializes the built in generic netlink control family.
  97. Arguments:
  98. None.
  99. Return Value:
  100. None.
  101. --*/
  102. {
  103. KSTATUS Status;
  104. Status = NetlinkGenericRegisterFamily(
  105. &NetlinkGenericControlFamilyProperties,
  106. &NetlinkGenericControlFamily);
  107. if (!KSUCCESS(Status)) {
  108. ASSERT(KSUCCESS(Status));
  109. }
  110. return;
  111. }
  112. KSTATUS
  113. NetlinkpGenericControlSendNotification (
  114. PNETLINK_GENERIC_FAMILY Family,
  115. UCHAR Command,
  116. PNETLINK_GENERIC_MULTICAST_GROUP Group
  117. )
  118. /*++
  119. Routine Description:
  120. This routine sends a generic netlink control command based on the family
  121. and or group information.
  122. Arguments:
  123. Family - Supplies a pointer to the generic netlink family for which the
  124. command is being sent.
  125. Command - Supplies the generic netlink control command to be sent.
  126. Group - Supplies an optional pointers to the multicast group that has
  127. just arrived or is being deleted.
  128. Return Value:
  129. Status code.
  130. --*/
  131. {
  132. NETLINK_ADDRESS Destination;
  133. NETLINK_GENERIC_COMMAND_INFORMATION SendCommand;
  134. NETLINK_ADDRESS Source;
  135. KSTATUS Status;
  136. if (NetlinkGenericControlFamily == NULL) {
  137. return STATUS_TOO_EARLY;
  138. }
  139. //
  140. // The notifications always come from the kernel.
  141. //
  142. Source.Domain = NetDomainNetlink;
  143. Source.Port = 0;
  144. Source.Group = 0;
  145. //
  146. // Notifications are always sent to the generic netlink control
  147. // notification multicast group. This is the first multicast group for the
  148. // control family. As the generic control family has access to the family
  149. // structure, just do the multicast group offset conversion here so that
  150. // the same helper routine can send notifications and reply to family
  151. // information requests.
  152. //
  153. Destination.Domain = NetDomainNetlink;
  154. Destination.Port = 0;
  155. Destination.Group = NetlinkGenericControlFamily->MulticastGroupOffset +
  156. NETLINK_GENERIC_CONTROL_MULTICAST_NOTIFY;
  157. //
  158. // Fill out the command information and send out the notification.
  159. //
  160. SendCommand.Message.SourceAddress = (PNETWORK_ADDRESS)&Source;
  161. SendCommand.Message.DestinationAddress = (PNETWORK_ADDRESS)&Destination;
  162. SendCommand.Message.SequenceNumber = 0;
  163. SendCommand.Command = Command;
  164. SendCommand.Version = 0;
  165. Status = NetlinkpGenericControlSendCommand(Family, &SendCommand, Group);
  166. if (!KSUCCESS(Status)) {
  167. goto SendNotificationEnd;
  168. }
  169. SendNotificationEnd:
  170. return Status;
  171. }
  172. //
  173. // --------------------------------------------------------- Internal Functions
  174. //
  175. KSTATUS
  176. NetlinkpGenericControlGetFamily (
  177. PNET_SOCKET Socket,
  178. PNET_PACKET_BUFFER Packet,
  179. PNETLINK_GENERIC_COMMAND_INFORMATION Command
  180. )
  181. /*++
  182. Routine Description:
  183. This routine is called to process a received generic netlink control packet.
  184. Arguments:
  185. Socket - Supplies a pointer to the network socket that received the packet.
  186. Packet - Supplies a pointer to a structure describing the incoming packet.
  187. This structure may be used as a scratch space while this routine
  188. executes and the packet travels up the stack, but will not be accessed
  189. after this routine returns.
  190. Command - Supplies a pointer to the command information.
  191. Return Value:
  192. None. When the function returns, the memory associated with the packet may
  193. be reclaimed and reused.
  194. --*/
  195. {
  196. PVOID Attributes;
  197. ULONG AttributesLength;
  198. PVOID Data;
  199. USHORT DataLength;
  200. PNETLINK_GENERIC_FAMILY Family;
  201. NETLINK_GENERIC_COMMAND_INFORMATION SendCommand;
  202. KSTATUS Status;
  203. Family = NULL;
  204. //
  205. // Search the packet for an attribute that identifies the family.
  206. //
  207. AttributesLength = Packet->FooterOffset - Packet->DataOffset;
  208. Attributes = Packet->Buffer + Packet->DataOffset;
  209. Status = NetlinkGetAttribute(Attributes,
  210. AttributesLength,
  211. NETLINK_CONTROL_ATTRIBUTE_FAMILY_NAME,
  212. &Data,
  213. &DataLength);
  214. if (KSUCCESS(Status)) {
  215. Family = NetlinkpGenericLookupFamilyByName((PSTR)Data);
  216. }
  217. if (Family == NULL) {
  218. Status = NetlinkGetAttribute(Attributes,
  219. AttributesLength,
  220. NETLINK_CONTROL_ATTRIBUTE_FAMILY_ID,
  221. &Data,
  222. &DataLength);
  223. if (KSUCCESS(Status)) {
  224. if (DataLength != sizeof(USHORT)) {
  225. Status = STATUS_DATA_LENGTH_MISMATCH;
  226. goto GetFamilyEnd;
  227. }
  228. Family = NetlinkpGenericLookupFamilyById(*((PUSHORT)Data));
  229. }
  230. }
  231. if (Family == NULL) {
  232. Status = STATUS_NOT_SUPPORTED;
  233. goto GetFamilyEnd;
  234. }
  235. //
  236. // A family was found. Send it to the general processing command that
  237. // handles all family oriented control commands.
  238. //
  239. SendCommand.Message.SourceAddress = &(Socket->LocalAddress);
  240. SendCommand.Message.DestinationAddress = Command->Message.SourceAddress;
  241. SendCommand.Message.SequenceNumber = Command->Message.SequenceNumber;
  242. SendCommand.Command = NETLINK_CONTROL_COMMAND_NEW_FAMILY;
  243. SendCommand.Version = 0;
  244. Status = NetlinkpGenericControlSendCommand(Family, &SendCommand, NULL);
  245. if (!KSUCCESS(Status)) {
  246. goto GetFamilyEnd;
  247. }
  248. GetFamilyEnd:
  249. if (Family != NULL) {
  250. NetlinkpGenericFamilyReleaseReference(Family);
  251. }
  252. return Status;
  253. }
  254. KSTATUS
  255. NetlinkpGenericControlSendCommand (
  256. PNETLINK_GENERIC_FAMILY Family,
  257. PNETLINK_GENERIC_COMMAND_INFORMATION Command,
  258. PNETLINK_GENERIC_MULTICAST_GROUP Group
  259. )
  260. /*++
  261. Routine Description:
  262. This routine sends a generic netlink control command based on the family
  263. and or group information.
  264. Arguments:
  265. Family - Supplies a pointer to the generic netlink family for which the
  266. command is being sent.
  267. Command - Supplies a pointer to the command information.
  268. Group - Supplies an optional pointers to the multicast group that has
  269. just arrived or is being deleted.
  270. Return Value:
  271. Status code.
  272. --*/
  273. {
  274. USHORT Attribute;
  275. ULONG GroupCount;
  276. PNETLINK_GENERIC_MULTICAST_GROUP Groups;
  277. ULONG GroupsLength;
  278. ULONG HeaderLength;
  279. ULONG IdSize;
  280. ULONG Index;
  281. ULONG NameSize;
  282. PNET_PACKET_BUFFER Packet;
  283. ULONG PacketLength;
  284. UINTN PayloadLength;
  285. KSTATUS Status;
  286. //
  287. // Determine the size of the command payload.
  288. //
  289. PayloadLength = 0;
  290. switch (Command->Command) {
  291. case NETLINK_CONTROL_COMMAND_NEW_FAMILY:
  292. case NETLINK_CONTROL_COMMAND_DELETE_FAMILY:
  293. GroupCount = Family->Properties.MulticastGroupCount;
  294. Groups = Family->Properties.MulticastGroups;
  295. break;
  296. case NETLINK_CONTROL_COMMAND_NEW_MULTICAST_GROUP:
  297. case NETLINK_CONTROL_COMMAND_DELETE_MULTICAST_GROUP:
  298. if ((Group == NULL) || (Group->Id == 0)) {
  299. Status = STATUS_INVALID_PARAMETER;
  300. goto SendCommandEnd;
  301. }
  302. GroupCount = 1;
  303. Groups = Group;
  304. break;
  305. default:
  306. Status = STATUS_NOT_SUPPORTED;
  307. goto SendCommandEnd;
  308. }
  309. //
  310. // All commands get the family ID and name attributes.
  311. //
  312. PayloadLength += NETLINK_ATTRIBUTE_SIZE(sizeof(USHORT)) +
  313. NETLINK_ATTRIBUTE_SIZE(Family->Properties.NameLength);
  314. //
  315. // Add the size for the multicast groups based on the information
  316. // determined above. These take advantage of nested attributes.
  317. //
  318. if (GroupCount != 0) {
  319. PayloadLength += NETLINK_ATTRIBUTE_SIZE(0);
  320. GroupsLength = NETLINK_ATTRIBUTE_SIZE(0) * GroupCount;
  321. GroupsLength += NETLINK_ATTRIBUTE_SIZE(sizeof(ULONG)) * GroupCount;
  322. for (Index = 0; Index < GroupCount; Index += 1) {
  323. Group = &(Groups[Index]);
  324. GroupsLength += NETLINK_ATTRIBUTE_SIZE(Group->NameLength);
  325. }
  326. PayloadLength += GroupsLength;
  327. }
  328. HeaderLength = NETLINK_HEADER_LENGTH + NETLINK_GENERIC_HEADER_LENGTH;
  329. PacketLength = HeaderLength + PayloadLength;
  330. Status = NetAllocateBuffer(0,
  331. PacketLength,
  332. 0,
  333. NULL,
  334. 0,
  335. &Packet);
  336. if (!KSUCCESS(Status)) {
  337. goto SendCommandEnd;
  338. }
  339. Status = NetlinkGenericAppendHeaders(NetlinkGenericControlFamily,
  340. Packet,
  341. PayloadLength,
  342. Command->Message.SequenceNumber,
  343. 0,
  344. Command->Command,
  345. Command->Version);
  346. if (!KSUCCESS(Status)) {
  347. goto SendCommandEnd;
  348. }
  349. //
  350. // Append the family ID and family name attributes to the packet.
  351. //
  352. Status = NetlinkAppendAttribute(Packet,
  353. NETLINK_CONTROL_ATTRIBUTE_FAMILY_ID,
  354. &(Family->Properties.Id),
  355. sizeof(USHORT));
  356. if (!KSUCCESS(Status)) {
  357. goto SendCommandEnd;
  358. }
  359. Status = NetlinkAppendAttribute(Packet,
  360. NETLINK_CONTROL_ATTRIBUTE_FAMILY_NAME,
  361. Family->Properties.Name,
  362. Family->Properties.NameLength);
  363. if (!KSUCCESS(Status)) {
  364. goto SendCommandEnd;
  365. }
  366. //
  367. // Append the multicast groups if present.
  368. //
  369. if (GroupCount != 0) {
  370. Attribute = NETLINK_CONTROL_ATTRIBUTE_MULTICAST_GROUPS;
  371. Status = NetlinkAppendAttribute(Packet, Attribute, NULL, GroupsLength);
  372. if (!KSUCCESS(Status)) {
  373. goto SendCommandEnd;
  374. }
  375. IdSize = NETLINK_ATTRIBUTE_SIZE(sizeof(ULONG));
  376. for (Index = 0; Index < GroupCount; Index += 1) {
  377. Group = &(Groups[Index]);
  378. ASSERT((Group->Id != 0) && (Group->NameLength != 0));
  379. NameSize = NETLINK_ATTRIBUTE_SIZE(Group->NameLength);
  380. Status = NetlinkAppendAttribute(Packet,
  381. Index + 1,
  382. NULL,
  383. IdSize + NameSize);
  384. if (!KSUCCESS(Status)) {
  385. goto SendCommandEnd;
  386. }
  387. Attribute = NETLINK_CONTROL_MULTICAST_GROUP_ATTRIBUTE_ID;
  388. Status = NetlinkAppendAttribute(Packet,
  389. Attribute,
  390. &(Group->Id),
  391. sizeof(ULONG));
  392. if (!KSUCCESS(Status)) {
  393. goto SendCommandEnd;
  394. }
  395. Attribute = NETLINK_CONTROL_MULTICAST_GROUP_ATTRIBUTE_NAME;
  396. Status = NetlinkAppendAttribute(Packet,
  397. Attribute,
  398. Group->Name,
  399. Group->NameLength);
  400. if (!KSUCCESS(Status)) {
  401. goto SendCommandEnd;
  402. }
  403. }
  404. }
  405. //
  406. // Actually send the packet out to the address specified in the given
  407. // parameters.
  408. //
  409. Status = NetlinkGenericSendCommand(NetlinkGenericControlFamily,
  410. Packet,
  411. Command->Message.DestinationAddress);
  412. if (!KSUCCESS(Status)) {
  413. goto SendCommandEnd;
  414. }
  415. SendCommandEnd:
  416. if (Packet != NULL) {
  417. NetFreeBuffer(Packet);
  418. }
  419. return Status;
  420. }