What are the concepts of policies and attributes in generic netlink? - linux

I am new in netlink programming. I am writing a generic netlink program for creating a netlink protocol family. I have searched many documents on the internet and I found something "Attributes and Policies" like things
for defining a netlink family.
I am totally confused with these things.
I found something like bellow about attributes in linux/netlink.h
<------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+---------------------------+- - -+- - - - - - - - - -+- - -+
| Header | Pad | Payload | Pad |
| (struct nlattr) | ing | | ing |
+---------------------------+- - -+- - - - - - - - - -+- - -+
<-------------------- nlattr->nla_len -------------->
And policy is an array of nla_policy structures.
My questions are:
What is the relation between header and attribute? Please explain
"Attributes".
What is policy, what is need of it and why do we use an array for this?
I found something about policies like "it defines types of attributes",
what does this mean? I mean "what is the meaning of type of attribute?"
It may be a nonsense question, but I am totally confused. I have been trying to understand these things for more than three days, please help me.
Thanks..

When creating/using netlink protocols, netlink attributes are intended to give the protocol a clean self documenting layout that allows for future extensibility. Meaning if you were wanting to use a different data type in addition to the ones that already exist in your current protocol, the code would be compatible without breaking the operations that already exist.
The "attributes" are protocol dependent, and relate to a specific message
being sent using said protocol.
Using the taskstats interface as an example:
taskstat attributes:
enum {
TASKSTATS_CMD_ATTR_UNSPEC = 0,
TASKSTATS_CMD_ATTR_PID,
TASKSTATS_CMD_ATTR_TGID,
TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
__TASKSTATS_CMD_ATTR_MAX,
};
In these attributes you could easily "extend" them by adding in a custom attribute between UNSPEC and MAX mapping that attribute to a specific function or operation needed.
kernel-space taskstat policy:
static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
[TASKSTATS_CMD_ATTR_PID] = { .type = NLA_U32 },
[TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};
I believe you've already come across the definition for struct nlattr, an example of loading this struct's fields using the NETLINK_GENERIC protocol and the taskstats interface:
struct nlattr na;
na.nla_type = CTRL_ATTR_FAMILY_NAME; // defined in linux/genetlink.h
na.nla_len = strlen(TASKSTATS_GENL_NAME) + 1 // defined in linux/taskstats.h
// note: you will need to copy/access nlattr data in the same way the NLMSG_DATA
// macro operates.
Now on the kernel side when parsing these attributes the associated functions will be called and intended actions on how to proceed.
I'm not sure if the diagram you posted is throwing you off but, to zoom out a bit
to give you a larger perspective:
As per the kernel source v3.16 include/net/netlink.h:
/* ========================================================================
* Netlink Messages and Attributes Interface (As Seen On TV)
* ------------------------------------------------------------------------
* Messages Interface
* ------------------------------------------------------------------------
*
* Message Format:
* <--- nlmsg_total_size(payload) --->
* <-- nlmsg_msg_size(payload) ->
* +----------+- - -+-------------+- - -+-------- - -
* | nlmsghdr | Pad | Payload | Pad | nlmsghdr
* +----------+- - -+-------------+- - -+-------- - -
* nlmsg_data(nlh)---^ ^
* nlmsg_next(nlh)-----------------------+
*
* Payload Format:
* <---------------------- nlmsg_len(nlh) --------------------->
* <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) ->
* +----------------------+- - -+--------------------------------+
* | Family Header | Pad | Attributes |
* +----------------------+- - -+--------------------------------+
* nlmsg_attrdata(nlh, hdrlen)---^
Here you can see that the header and payload diagram you posted are but parts of a larger payload. That segment goes along with a struct nlmsghdr in the message format.
Now on policy, when sending netlink messages the sender needs to adhere to the protocol
format. The receiver of the message will use struct nla_policy to validate the attributes before the payload is accessed.
The "family" or identifier is used by the kernel to keep track of the appropriate protocol interface to be communicating with, whether standard protocol or custom as with Generic Netlink.
When you ask "Can we avoid this?", if you're extending netlink by writing your own custom generic netlink protocol these exist to allow that protocol to be easily adjusted and maintained without going through and changing/fixing all operations associated with it or flat-out having the protocol break down. How else would you suggest parsing through nested messages with different data-types without an associated length or type? The type and length are there to allow parsing of the message on the correct alignments and allow the desired actions to take place. Without the attributes type giving the payload a label how would you interpret it, "what is" the payload? Without the length how would you know "how large" the payload is? There could be multiple payloads all with different lengths without something to distinguish their sizes there is no way to be able to tell where one starts and the other ends.
Here is a link to the libnl (a library for working with netlink sockets, and is highly recommended) documentation attributes.

Related

Where is kernel machine_desc table information?

I'm trying to understand how devicetrees work.
According to the kernel documentation, they are used, in arm architecture, in the following manner:
In the majority of cases, the machine identity is irrelevant, and the kernel will instead select setup code based on the machine’s core CPU or SoC. On ARM for example, setup_arch() in arch/arm/kernel/setup.c will call setup_machine_fdt() in arch/arm/kernel/devtree.c which searches through the machine_desc table and selects the machine_desc which best matches the device tree data. It determines the best match by looking at the ‘compatible’ property in the root device tree node, and comparing it with the dt_compat list in struct machine_desc (which is defined in arch/arm/include/asm/mach/arch.h if you’re curious).
The ‘compatible’ property contains a sorted list of strings starting with the exact name of the machine, followed by an optional list of boards it is compatible with sorted from most compatible to least.
I found the source code related to the comparison of machine_desc to the compatible parameter set in the dts file:
const struct machine_desc * __init setup_machine_fdt(void *dt_virt)
{
const struct machine_desc *mdesc, *mdesc_best = NULL;
#if defined(CONFIG_ARCH_MULTIPLATFORM) || defined(CONFIG_ARM_SINGLE_ARMV7M)
DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
.l2c_aux_val = 0x0,
.l2c_aux_mask = ~0x0,
MACHINE_END
mdesc_best = &__mach_desc_GENERIC_DT;
#endif
if (!dt_virt || !early_init_dt_verify(dt_virt))
return NULL;
mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);
if (!mdesc) {
const char *prop;
int size;
unsigned long dt_root;
early_print("\nError: unrecognized/unsupported "
"device tree compatible list:\n[ ");
dt_root = of_get_flat_dt_root();
prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
while (size > 0) {
early_print("'%s' ", prop);
size -= strlen(prop) + 1;
prop += strlen(prop) + 1;
}
early_print("]\n\n");
dump_machine_table(); /* does not return */
}
/* We really don't want to do this, but sometimes firmware provides buggy data */
if (mdesc->dt_fixup)
mdesc->dt_fixup();
early_init_dt_scan_nodes();
/* Change machine number to match the mdesc we're using */
__machine_arch_type = mdesc->nr;
return mdesc;
}
However, I didn't find machine_desc table definition.
If I'd like to read all machine_desc, Where can I find it?
TL;DR - The machine description is built by building and linking different source files into the kernel. So each machine source file adds an entry into the table.
The table is based in arch/arm/kernel/vmlinux.lds.S (or relevant architecture linker file). It is built with the macros MACHINE_START and MACHINE_END. This places a structure in the 'arch.info.init' sections of the object file. All of these objects get globbed together by the linker. This forms the table. So, it is constructed by linking different source files with the MACHINE_START and MACHINE_END macros. Therefore, it doesn't exist in one place.
However, you can use git grep -A10 MACHINE_START to get a fairly good list. This command works well, as typically, it is the last thing in the file so only five or six lines may print. Or you could write init code to dump the table by printing the machine_desc entries.
That said, the table is not too interesting as it is just function pointers to call at different times. The majority will be NULL as it used designated initializers.
Related: Control to 'dt_machine_start' on Android

How can I detect the device target type in an action script?

I want my "GetContent" script to detect whether the device is "watch" and pass along an instruction to filter out candidate answers from a content.json file whose text field has a length greater than a certain number of characters.
content.json format:
{tags: ["literature"], text: "At once it struck me what quality went to form a man of achievement, especially in literature, and which Shakespeare possessed so enormously -- I mean negative capability, that is, when a man is capable of being in uncertainties, mysteries, doubts, without any irritable reaching after fact and reason. Source: John Keats", image: {url: "images/Shakespeare.jpg"}},
So the logic would be
if (watch) content = short_quotes_only
I would recommend exploring the device property of $vivContext (Documentation)
The device property will allow you to see which type of device a user is using (bixby-mobile, bixby-tv, etc.) and provide the data you wish to show for the device being used.
This combination of snippets worked for me:
device = $vivContext.device
console.log('device', device)
if (device == 'bixby-watch' ) { maxlength = 100
console.log('maxlength is now', maxlength)
}
then later in the script
//filters entitled content by length of text field in characters
content = content.filter(function(i) { return i.text.length < maxlength;

How to add extra options to CoAP request?

I know that CoAP defines some options which can be included in the sending request and each option has their own number. The structure of the CoAP uri request looks like:
coap-URI = "coap:" "//" host [ ":" port ] path-abempty [ "?" query ]
where inside they include some options like: Uri-Host, Uri-Port, Uri-Path, and Uri-Query, and each of them has their own number, ex: 3 for Uri-Host, 11 for Uri Path.... . And I would like to add some more extra options to this CoAP request, for example some options number 256, 257...How can I do that?
Thank you in advanced
Son
I've managed to pass the Option Number 256.
CoapClient client = new CoapClient(...);
Request request = new Request(CoAP.Code.GET, CoAP.Type.NON);
OptionSet optionSet = new OptionSet();
optionSet.addOption(new Option(256, "admin:admin"));
request.setOptions(optionSet);
client.advanced(request); // or async version
client.shutdown();
At resource:
#Override
public void handleGET(CoapExchange exchange) {
OptionSet optionSet = exchange.advanced().getRequest().getOptions();
List<Option> options = optionSet.asSortedList();
options.stream()
.filter(o -> o.getNumber() == 256)
.findFirst()
.ifPresent(o -> System.err.println(o.getNumber() + " " + o.getStringValue()));
}
Output:
256 admin:admin
However, Option Number 256 may not be a proper choice in general:
RFC 7252 The Constrained Application Protocol (CoAP). 12.2. CoAP Option Numbers Registry
The IANA policy for future additions to this sub-registry is split
into three tiers as follows. The range of 0..255 is reserved for
options defined by the IETF (IETF Review or IESG Approval). The
range of 256..2047 is reserved for commonly used options with public
specifications (Specification Required). The range of 2048..64999 is
for all other options including private or vendor-specific ones,
which undergo a Designated Expert review to help ensure that the
option semantics are defined correctly. The option numbers between
65000 and 65535 inclusive are reserved for experiments. They are not
meant for vendor-specific use of any kind and MUST NOT be used in
operational deployments.

Zstack read attribute

I want to know how can I read some attribute on local and remote zigbee device using TI zstack and how to put its value to uart. I'm zstack beginner. I managed to use uart with usb to uart converter and can send data to my pc. So I need to know how to get the attribute data. I've read api manual but didn't anderstand how to use zcl_SendRead function. Thanks.
Follow section "3.3 Send Read" of the "Z-Stack ZCL API.pdf" this should contain enough info for getting the read attr to the correct destination device. The contents of the readCmd is an array of attribute ID's, specific to the attribute(s) you want to read. You will need to consult the ZCL specification or device documentation to determine the correct Attr ID and Cluster ID.
An example for sending a read attr is shown below. It reads the ATTRID_MS_TEMPERATURE_MEASURED_VALUE attribute (from the ZCL_CLUSTER_ID_MS_TEMPERATURE_MEASUREMENT cluster) from device with short address 0x1234 and endpoint 0x1.
afAddrType_t dstAddr;
dstAddr.addrMode = afAddr16Bit;
dstAddr.addr.shortAddr = 0x1234; //set this to correct address
dstAddr.addr.endPoint = 0x1; // set this to correct ep
zclReadCmd_t *cmd = osal_mem_alloc((sizeof zclReadCmd_t) + sizeof(uint16));
cmd->numAttr = 1;
cmd->attrID[0] = ATTRID_MS_TEMPERATURE_MEASURED_VALUE;
zcl_SendRead( SAMPLETHERMOSTAT_ENDPOINT, &dstAddr,
ZCL_CLUSTER_ID_MS_TEMPERATURE_MEASUREMENT,
&cmd, ZCL_FRAME_CLIENT_SERVER_DIR,
hdr->fc.disableDefaultRsp, hdr->transSeqNum );
Once this command is sent you need to process the received the response, you will notice that the functions are contained in the ZStack Sample Applications but not populated, for instance the SampleSwitch application has zclSampleSw_ProcessInReadRspCmd() function, this will be called to process the read attr response and you will need to populate it to do what you want to do with the response.
Regards,
TC.

how to order freeradius attributes

I am configuring Freeradius. Input message is Access-Request with Proxy-State = 3134
Freeradius succesfully performs authentication but he places Proxy-State at the bottom of Access-Accept. How can I canfigure that Freeradius places Framed-IP-Address at the bottom of the message?
It tried to configure "users" as:
381603854966 Auth-Type := Accept, User-Password == "123456"
Service-Type = Framed-User,
Framed-Protocol = PPP,
Framed-IP-Netmask = 255.255.255.0,
User-Name = 381603854966,
Framed-IP-Address = 10.10.40.22,
but without success - freeradius still puts Proxy-State and the bottom of Access-Accept. I also tried to configure policy.txt file like:
if (User-Name == "381603854966") {
reply .= {
Framed-IP-Address += "10.10.40.22"
}
}
I also tried this in policy.txt:
reply .= {
Framed-IP-Address = 10.10.40.22
}
didn't work. Anybody knows how can I place certain attribute at the bottom of the message?
Thank you, Mark
You can't. The server will add Proxy-State to the request before forwarding it upstream, and it'll always add it at the end of the list of attributes.
RFC 2865 section 5 states:
If multiple Attributes with the same Type are present, the order of
Attributes with the same Type MUST be preserved by any proxies. The
order of Attributes of different Types is not required to be
preserved. A RADIUS server or client MUST NOT have any dependencies
on the order of attributes of different types. A RADIUS server or
client MUST NOT require attributes of the same type to be contiguous.
If your application requires ordering of attributes of different types, it's not implementing the RADIUS protocol correctly and should be fixed.

Resources