123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- /*++
- Copyright (c) 2016 Minoca Corp. All Rights Reserved
- Module Name:
- genctrl.c
- Abstract:
- This module implements the generic netlink control family message handling.
- Author:
- Chris Stevens 10-Feb-2016
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- //
- // Typically, generic netlink families are supposed to be able to stand on
- // their own (i.e. be able to be implemented outside the core net library). For
- // the built-in ones, avoid including netcore.h, but still redefine those
- // functions that would otherwise generate imports. This, however, needs to
- // include generic.h to get access to the tree of families.
- //
- #define NET_API __DLLEXPORT
- #include <minoca/kernel/driver.h>
- #include <minoca/net/netdrv.h>
- #include <minoca/net/netlink.h>
- #include "generic.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the multicast group indices. These must match the order of the
- // multicast group array below.
- //
- #define NETLINK_GENERIC_CONTROL_MULTICAST_NOTIFY 0
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- NetlinkpGenericControlGetFamily (
- PNET_SOCKET Socket,
- PNET_PACKET_BUFFER Packet,
- PNETLINK_GENERIC_COMMAND_INFORMATION Command
- );
- KSTATUS
- NetlinkpGenericControlSendCommand (
- PNETLINK_GENERIC_FAMILY Family,
- PNETLINK_GENERIC_COMMAND_INFORMATION Command,
- PNETLINK_GENERIC_MULTICAST_GROUP Group
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- NETLINK_GENERIC_COMMAND NetlinkGenericControlCommands[] = {
- {
- NETLINK_CONTROL_COMMAND_GET_FAMILY,
- 0,
- NetlinkpGenericControlGetFamily
- },
- };
- NETLINK_GENERIC_MULTICAST_GROUP NetlinkGenericControlMulticastGroups[] = {
- {
- NETLINK_GENERIC_CONTROL_MULTICAST_NOTIFY,
- sizeof(NETLINK_CONTROL_MULTICAST_NOTIFY_NAME),
- NETLINK_CONTROL_MULTICAST_NOTIFY_NAME
- },
- };
- NETLINK_GENERIC_FAMILY_PROPERTIES NetlinkGenericControlFamilyProperties = {
- NETLINK_GENERIC_FAMILY_PROPERTIES_VERSION,
- NETLINK_GENERIC_ID_CONTROL,
- sizeof(NETLINK_GENERIC_CONTROL_NAME),
- NETLINK_GENERIC_CONTROL_NAME,
- NetlinkGenericControlCommands,
- sizeof(NetlinkGenericControlCommands) /
- sizeof(NetlinkGenericControlCommands[0]),
- NetlinkGenericControlMulticastGroups,
- sizeof(NetlinkGenericControlMulticastGroups) /
- sizeof(NetlinkGenericControlMulticastGroups[0]),
- };
- //
- // Store a pointer to the netlink generic control family for easy access to
- // its multicast groups.
- //
- PNETLINK_GENERIC_FAMILY NetlinkGenericControlFamily = NULL;
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID
- NetlinkpGenericControlInitialize (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes the built in generic netlink control family.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- KSTATUS Status;
- Status = NetlinkGenericRegisterFamily(
- &NetlinkGenericControlFamilyProperties,
- &NetlinkGenericControlFamily);
- if (!KSUCCESS(Status)) {
- ASSERT(KSUCCESS(Status));
- }
- return;
- }
- KSTATUS
- NetlinkpGenericControlSendNotification (
- PNETLINK_GENERIC_FAMILY Family,
- UCHAR Command,
- PNETLINK_GENERIC_MULTICAST_GROUP Group
- )
- /*++
- Routine Description:
- This routine sends a generic netlink control command based on the family
- and or group information.
- Arguments:
- Family - Supplies a pointer to the generic netlink family for which the
- command is being sent.
- Command - Supplies the generic netlink control command to be sent.
- Group - Supplies an optional pointers to the multicast group that has
- just arrived or is being deleted.
- Return Value:
- Status code.
- --*/
- {
- NETLINK_ADDRESS Destination;
- NETLINK_GENERIC_COMMAND_INFORMATION SendCommand;
- NETLINK_ADDRESS Source;
- KSTATUS Status;
- if (NetlinkGenericControlFamily == NULL) {
- return STATUS_TOO_EARLY;
- }
- //
- // The notifications always come from the kernel.
- //
- Source.Domain = NetDomainNetlink;
- Source.Port = 0;
- Source.Group = 0;
- //
- // Notifications are always sent to the generic netlink control
- // notification multicast group. This is the first multicast group for the
- // control family. As the generic control family has access to the family
- // structure, just do the multicast group offset conversion here so that
- // the same helper routine can send notifications and reply to family
- // information requests.
- //
- Destination.Domain = NetDomainNetlink;
- Destination.Port = 0;
- Destination.Group = NetlinkGenericControlFamily->MulticastGroupOffset +
- NETLINK_GENERIC_CONTROL_MULTICAST_NOTIFY;
- //
- // Fill out the command information and send out the notification.
- //
- SendCommand.Message.SourceAddress = (PNETWORK_ADDRESS)&Source;
- SendCommand.Message.DestinationAddress = (PNETWORK_ADDRESS)&Destination;
- SendCommand.Message.SequenceNumber = 0;
- SendCommand.Command = Command;
- SendCommand.Version = 0;
- Status = NetlinkpGenericControlSendCommand(Family, &SendCommand, Group);
- if (!KSUCCESS(Status)) {
- goto SendNotificationEnd;
- }
- SendNotificationEnd:
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- NetlinkpGenericControlGetFamily (
- PNET_SOCKET Socket,
- PNET_PACKET_BUFFER Packet,
- PNETLINK_GENERIC_COMMAND_INFORMATION Command
- )
- /*++
- Routine Description:
- This routine is called to process a received generic netlink control packet.
- Arguments:
- Socket - Supplies a pointer to the network socket that received the packet.
- Packet - Supplies a pointer to a structure describing the incoming packet.
- This structure may be used as a scratch space while this routine
- executes and the packet travels up the stack, but will not be accessed
- after this routine returns.
- Command - Supplies a pointer to the command information.
- Return Value:
- None. When the function returns, the memory associated with the packet may
- be reclaimed and reused.
- --*/
- {
- PVOID Attributes;
- ULONG AttributesLength;
- PVOID Data;
- USHORT DataLength;
- PNETLINK_GENERIC_FAMILY Family;
- NETLINK_GENERIC_COMMAND_INFORMATION SendCommand;
- KSTATUS Status;
- Family = NULL;
- //
- // Search the packet for an attribute that identifies the family.
- //
- AttributesLength = Packet->FooterOffset - Packet->DataOffset;
- Attributes = Packet->Buffer + Packet->DataOffset;
- Status = NetlinkGetAttribute(Attributes,
- AttributesLength,
- NETLINK_CONTROL_ATTRIBUTE_FAMILY_NAME,
- &Data,
- &DataLength);
- if (KSUCCESS(Status)) {
- Family = NetlinkpGenericLookupFamilyByName((PSTR)Data);
- }
- if (Family == NULL) {
- Status = NetlinkGetAttribute(Attributes,
- AttributesLength,
- NETLINK_CONTROL_ATTRIBUTE_FAMILY_ID,
- &Data,
- &DataLength);
- if (KSUCCESS(Status)) {
- if (DataLength != sizeof(USHORT)) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto GetFamilyEnd;
- }
- Family = NetlinkpGenericLookupFamilyById(*((PUSHORT)Data));
- }
- }
- if (Family == NULL) {
- Status = STATUS_NOT_SUPPORTED;
- goto GetFamilyEnd;
- }
- //
- // A family was found. Send it to the general processing command that
- // handles all family oriented control commands.
- //
- SendCommand.Message.SourceAddress = &(Socket->LocalAddress);
- SendCommand.Message.DestinationAddress = Command->Message.SourceAddress;
- SendCommand.Message.SequenceNumber = Command->Message.SequenceNumber;
- SendCommand.Command = NETLINK_CONTROL_COMMAND_NEW_FAMILY;
- SendCommand.Version = 0;
- Status = NetlinkpGenericControlSendCommand(Family, &SendCommand, NULL);
- if (!KSUCCESS(Status)) {
- goto GetFamilyEnd;
- }
- GetFamilyEnd:
- if (Family != NULL) {
- NetlinkpGenericFamilyReleaseReference(Family);
- }
- return Status;
- }
- KSTATUS
- NetlinkpGenericControlSendCommand (
- PNETLINK_GENERIC_FAMILY Family,
- PNETLINK_GENERIC_COMMAND_INFORMATION Command,
- PNETLINK_GENERIC_MULTICAST_GROUP Group
- )
- /*++
- Routine Description:
- This routine sends a generic netlink control command based on the family
- and or group information.
- Arguments:
- Family - Supplies a pointer to the generic netlink family for which the
- command is being sent.
- Command - Supplies a pointer to the command information.
- Group - Supplies an optional pointers to the multicast group that has
- just arrived or is being deleted.
- Return Value:
- Status code.
- --*/
- {
- USHORT Attribute;
- ULONG GroupCount;
- PNETLINK_GENERIC_MULTICAST_GROUP Groups;
- ULONG GroupsLength;
- ULONG HeaderLength;
- ULONG IdSize;
- ULONG Index;
- ULONG NameSize;
- PNET_PACKET_BUFFER Packet;
- ULONG PacketLength;
- UINTN PayloadLength;
- KSTATUS Status;
- //
- // Determine the size of the command payload.
- //
- PayloadLength = 0;
- switch (Command->Command) {
- case NETLINK_CONTROL_COMMAND_NEW_FAMILY:
- case NETLINK_CONTROL_COMMAND_DELETE_FAMILY:
- GroupCount = Family->Properties.MulticastGroupCount;
- Groups = Family->Properties.MulticastGroups;
- break;
- case NETLINK_CONTROL_COMMAND_NEW_MULTICAST_GROUP:
- case NETLINK_CONTROL_COMMAND_DELETE_MULTICAST_GROUP:
- if ((Group == NULL) || (Group->Id == 0)) {
- Status = STATUS_INVALID_PARAMETER;
- goto SendCommandEnd;
- }
- GroupCount = 1;
- Groups = Group;
- break;
- default:
- Status = STATUS_NOT_SUPPORTED;
- goto SendCommandEnd;
- }
- //
- // All commands get the family ID and name attributes.
- //
- PayloadLength += NETLINK_ATTRIBUTE_SIZE(sizeof(USHORT)) +
- NETLINK_ATTRIBUTE_SIZE(Family->Properties.NameLength);
- //
- // Add the size for the multicast groups based on the information
- // determined above. These take advantage of nested attributes.
- //
- if (GroupCount != 0) {
- PayloadLength += NETLINK_ATTRIBUTE_SIZE(0);
- GroupsLength = NETLINK_ATTRIBUTE_SIZE(0) * GroupCount;
- GroupsLength += NETLINK_ATTRIBUTE_SIZE(sizeof(ULONG)) * GroupCount;
- for (Index = 0; Index < GroupCount; Index += 1) {
- Group = &(Groups[Index]);
- GroupsLength += NETLINK_ATTRIBUTE_SIZE(Group->NameLength);
- }
- PayloadLength += GroupsLength;
- }
- HeaderLength = NETLINK_HEADER_LENGTH + NETLINK_GENERIC_HEADER_LENGTH;
- PacketLength = HeaderLength + PayloadLength;
- Status = NetAllocateBuffer(0,
- PacketLength,
- 0,
- NULL,
- 0,
- &Packet);
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- Status = NetlinkGenericAppendHeaders(NetlinkGenericControlFamily,
- Packet,
- PayloadLength,
- Command->Message.SequenceNumber,
- 0,
- Command->Command,
- Command->Version);
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- //
- // Append the family ID and family name attributes to the packet.
- //
- Status = NetlinkAppendAttribute(Packet,
- NETLINK_CONTROL_ATTRIBUTE_FAMILY_ID,
- &(Family->Properties.Id),
- sizeof(USHORT));
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- Status = NetlinkAppendAttribute(Packet,
- NETLINK_CONTROL_ATTRIBUTE_FAMILY_NAME,
- Family->Properties.Name,
- Family->Properties.NameLength);
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- //
- // Append the multicast groups if present.
- //
- if (GroupCount != 0) {
- Attribute = NETLINK_CONTROL_ATTRIBUTE_MULTICAST_GROUPS;
- Status = NetlinkAppendAttribute(Packet, Attribute, NULL, GroupsLength);
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- IdSize = NETLINK_ATTRIBUTE_SIZE(sizeof(ULONG));
- for (Index = 0; Index < GroupCount; Index += 1) {
- Group = &(Groups[Index]);
- ASSERT((Group->Id != 0) && (Group->NameLength != 0));
- NameSize = NETLINK_ATTRIBUTE_SIZE(Group->NameLength);
- Status = NetlinkAppendAttribute(Packet,
- Index + 1,
- NULL,
- IdSize + NameSize);
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- Attribute = NETLINK_CONTROL_MULTICAST_GROUP_ATTRIBUTE_ID;
- Status = NetlinkAppendAttribute(Packet,
- Attribute,
- &(Group->Id),
- sizeof(ULONG));
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- Attribute = NETLINK_CONTROL_MULTICAST_GROUP_ATTRIBUTE_NAME;
- Status = NetlinkAppendAttribute(Packet,
- Attribute,
- Group->Name,
- Group->NameLength);
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- }
- }
- //
- // Actually send the packet out to the address specified in the given
- // parameters.
- //
- Status = NetlinkGenericSendCommand(NetlinkGenericControlFamily,
- Packet,
- Command->Message.DestinationAddress);
- if (!KSUCCESS(Status)) {
- goto SendCommandEnd;
- }
- SendCommandEnd:
- if (Packet != NULL) {
- NetFreeBuffer(Packet);
- }
- return Status;
- }
|