Home | History | Annotate | Download | only in libnl_2
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      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 /* NOTICE: This is a clean room re-implementation of libnl */
     18 
     19 #include <malloc.h>
     20 #include <unistd.h>
     21 #include <linux/netlink.h>
     22 #include "netlink-types.h"
     23 
     24 /* Allocate a new netlink message with the default maximum payload size. */
     25 struct nl_msg *nlmsg_alloc(void)
     26 {
     27 	/* Whole page will store nl_msg + nlmsghdr + genlmsghdr + payload */
     28 	const int page_sz = getpagesize();
     29 	struct nl_msg *nm;
     30 	struct nlmsghdr *nlh;
     31 
     32 	/* Netlink message */
     33 	nm = (struct nl_msg *) malloc(page_sz);
     34 	if (!nm)
     35 		goto fail;
     36 
     37 	/* Netlink message header pointer */
     38 	nlh = (struct nlmsghdr *) ((char *) nm + sizeof(struct nl_msg));
     39 
     40 	/* Initialize */
     41 	memset(nm, 0, page_sz);
     42 	nm->nm_size = page_sz;
     43 
     44 	nm->nm_src.nl_family = AF_NETLINK;
     45 	nm->nm_src.nl_pid = getpid();
     46 
     47 	nm->nm_dst.nl_family = AF_NETLINK;
     48 	nm->nm_dst.nl_pid = 0; /* Kernel */
     49 
     50 	/* Initialize and add to netlink message */
     51 	nlh->nlmsg_len = NLMSG_HDRLEN;
     52 	nm->nm_nlh = nlh;
     53 
     54 	/* Add to reference count and return nl_msg */
     55 	nlmsg_get(nm);
     56 	return nm;
     57 fail:
     58 	return NULL;
     59 }
     60 
     61 /* Return pointer to message payload. */
     62 void *nlmsg_data(const struct nlmsghdr *nlh)
     63 {
     64 	return (char *) nlh + NLMSG_HDRLEN;
     65 }
     66 
     67 /* Add reference count to nl_msg */
     68 void nlmsg_get(struct nl_msg *nm)
     69 {
     70 	nm->nm_refcnt++;
     71 }
     72 
     73 /* Release a reference from an netlink message. */
     74 void nlmsg_free(struct nl_msg *nm)
     75 {
     76 	if (nm) {
     77 		nm->nm_refcnt--;
     78 		if (nm->nm_refcnt <= 0)
     79 			free(nm);
     80 	}
     81 
     82 }
     83 
     84 /* Return actual netlink message. */
     85 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
     86 {
     87 	return n->nm_nlh;
     88 }
     89 
     90 /* Return head of attributes data / payload section */
     91 struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
     92 {
     93 	unsigned char *data = nlmsg_data(nlh);
     94 	return (struct nlattr *)(data + NLMSG_ALIGN(hdrlen));
     95 }
     96 
     97 /* Returns pointer to end of netlink message */
     98 void *nlmsg_tail(const struct nlmsghdr *nlh)
     99 {
    100 	return (void *)((char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len));
    101 }
    102 
    103 /* Next netlink message in message stream */
    104 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
    105 {
    106 	struct nlmsghdr *next_nlh = NULL;
    107 	int len = nlmsg_len(nlh);
    108 
    109 	len = NLMSG_ALIGN(len);
    110 	if (*remaining > 0 &&
    111 	    len <= *remaining &&
    112 	    len >= (int) sizeof(struct nlmsghdr)) {
    113 		next_nlh = (struct nlmsghdr *)((char *)nlh + len);
    114 		*remaining -= len;
    115 	}
    116 
    117 	return next_nlh;
    118 }
    119 
    120 int nlmsg_datalen(const struct nlmsghdr *nlh)
    121 {
    122 	return nlh->nlmsg_len - NLMSG_HDRLEN;
    123 }
    124 
    125 /* Length of attributes data */
    126 int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
    127 {
    128 	return nlmsg_datalen(nlh) - NLMSG_ALIGN(hdrlen);
    129 }
    130 
    131 /* Length of netlink message */
    132 int nlmsg_len(const struct nlmsghdr *nlh)
    133 {
    134 	return nlh->nlmsg_len;
    135 }
    136 
    137 /* Check if the netlink message fits into the remaining bytes */
    138 int nlmsg_ok(const struct nlmsghdr *nlh, int rem)
    139 {
    140 	return rem >= (int)sizeof(struct nlmsghdr) &&
    141 		rem >= nlmsg_len(nlh) &&
    142 		nlmsg_len(nlh) >= (int) sizeof(struct nlmsghdr) &&
    143 		nlmsg_len(nlh) <= (rem);
    144 }
    145 
    146 int nlmsg_padlen(int payload)
    147 {
    148 	return NLMSG_ALIGN(payload) - payload;
    149 }
    150