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