• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. */
nlmsg_alloc(void)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. */
nlmsg_data(const struct nlmsghdr * nlh)62 void *nlmsg_data(const struct nlmsghdr *nlh)
63 {
64 	return (char *) nlh + NLMSG_HDRLEN;
65 }
66 
67 /* Add reference count to nl_msg */
nlmsg_get(struct nl_msg * nm)68 void nlmsg_get(struct nl_msg *nm)
69 {
70 	nm->nm_refcnt++;
71 }
72 
73 /* Release a reference from an netlink message. */
nlmsg_free(struct nl_msg * nm)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. */
nlmsg_hdr(struct nl_msg * n)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 */
nlmsg_attrdata(const struct nlmsghdr * nlh,int hdrlen)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 */
nlmsg_tail(const struct nlmsghdr * nlh)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 */
nlmsg_next(struct nlmsghdr * nlh,int * remaining)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 
nlmsg_datalen(const struct nlmsghdr * nlh)120 int nlmsg_datalen(const struct nlmsghdr *nlh)
121 {
122 	return nlh->nlmsg_len - NLMSG_HDRLEN;
123 }
124 
125 /* Length of attributes data */
nlmsg_attrlen(const struct nlmsghdr * nlh,int hdrlen)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 */
nlmsg_len(const struct nlmsghdr * nlh)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 */
nlmsg_ok(const struct nlmsghdr * nlh,int rem)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 
nlmsg_padlen(int payload)146 int nlmsg_padlen(int payload)
147 {
148 	return NLMSG_ALIGN(payload) - payload;
149 }
150