genl.c revision b77d3d724945f38b39f3116e3aead4edcbd08a36
15bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/*
25bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Copyright (C) 2011 The Android Open Source Project
35bc087c573c70c84c6a39946457590b42d392a33Andreas Huber *
45bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
55bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * you may not use this file except in compliance with the License.
65bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * You may obtain a copy of the License at
75bc087c573c70c84c6a39946457590b42d392a33Andreas Huber *
85bc087c573c70c84c6a39946457590b42d392a33Andreas Huber *	http://www.apache.org/licenses/LICENSE-2.0
95bc087c573c70c84c6a39946457590b42d392a33Andreas Huber *
105bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Unless required by applicable law or agreed to in writing, software
115bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
125bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * See the License for the specific language governing permissions and
145bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * limitations under the License.
155bc087c573c70c84c6a39946457590b42d392a33Andreas Huber */
165bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
175bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/* NOTICE: This is a clean room re-implementation of libnl */
185bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
195bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <errno.h>
205bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <unistd.h>
215bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <stdio.h>
225bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <sys/time.h>
235bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <sys/socket.h>
245bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <linux/netlink.h>
255bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include "netlink-types.h"
265bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
275bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/* Get head of attribute data. */
285bc087c573c70c84c6a39946457590b42d392a33Andreas Huberstruct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
295bc087c573c70c84c6a39946457590b42d392a33Andreas Huber{
307314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber	return (struct nlattr *) \
317314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber		((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen));
327314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber
337314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber}
347314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber
355bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/* Get length of attribute data. */
3643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huberint genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
375bc087c573c70c84c6a39946457590b42d392a33Andreas Huber{
385bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	struct nlattr *nla;
3943c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber	struct nlmsghdr *nlh;
405bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
4143c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber	nla = genlmsg_attrdata(gnlh, hdrlen);
4243c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber	nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN);
4343c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber	return (char *) nlmsg_tail(nlh) - (char *) nla;
4443c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber}
4543c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber
4643c3e6ce02215ca99d506458f596cb1211639f29Andreas Huber/* Add generic netlink header to netlink message. */
475bc087c573c70c84c6a39946457590b42d392a33Andreas Hubervoid *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
485bc087c573c70c84c6a39946457590b42d392a33Andreas Huber		int hdrlen, int flags, uint8_t cmd, uint8_t version)
495bc087c573c70c84c6a39946457590b42d392a33Andreas Huber{
505bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	int new_size;
515bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	struct nlmsghdr *nlh;
525bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	struct timeval tv;
537314fa17093d514199fedcb55ac41136a1b31cb3Andreas Huber	struct genlmsghdr *gmh;
545bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
555bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	/* Make sure nl_msg has enough space */
565bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen;
575bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	if ((sizeof(struct nl_msg) + new_size) > msg->nm_size)
585bc087c573c70c84c6a39946457590b42d392a33Andreas Huber		goto fail;
595bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
605bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	/* Fill in netlink header */
615bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	nlh = msg->nm_nlh;
625bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	nlh->nlmsg_len = new_size;
635bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	nlh->nlmsg_type = family;
645bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	nlh->nlmsg_pid = getpid();
655bc087c573c70c84c6a39946457590b42d392a33Andreas Huber	nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK;
66
67	/* Get current time for sequence number */
68	if (gettimeofday(&tv, NULL))
69		nlh->nlmsg_seq = 1;
70	else
71		nlh->nlmsg_seq = (int) tv.tv_sec;
72
73	/* Setup genlmsghdr in new message */
74	gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN);
75	gmh->cmd = (__u8) cmd;
76	gmh->version = version;
77
78	return gmh;
79fail:
80	return NULL;
81
82}
83
84/* Socket has already been alloced to connect it to kernel? */
85int genl_connect(struct nl_sock *sk)
86{
87	return nl_connect(sk, NETLINK_GENERIC);
88
89}
90
91int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
92{
93	int rc = -1;
94	int nl80211_genl_id = -1;
95	char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)];
96	struct nlmsghdr nlmhdr;
97	struct genlmsghdr gmhhdr;
98	struct iovec sendmsg_iov;
99	struct msghdr msg;
100	int num_char;
101	const int RECV_BUF_SIZE = getpagesize();
102	char *recvbuf;
103	struct iovec recvmsg_iov;
104	int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0;
105	struct nlmsghdr *nlh;
106
107	/* REQUEST GENERIC NETLINK FAMILY ID */
108	/* Message buffer */
109	nlmhdr.nlmsg_len = sizeof(sendbuf);
110	nlmhdr.nlmsg_type = NETLINK_GENERIC;
111	nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
112	nlmhdr.nlmsg_seq = sock->s_seq_next;
113	nlmhdr.nlmsg_pid = sock->s_local.nl_pid;
114
115	/* Generic netlink header */
116	memset(&gmhhdr, 0, sizeof(gmhhdr));
117	gmhhdr.cmd = CTRL_CMD_GETFAMILY;
118	gmhhdr.version = CTRL_ATTR_FAMILY_ID;
119
120	/* Combine netlink and generic netlink headers */
121	memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr));
122	memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr));
123
124	/* Create IO vector with Netlink message */
125	sendmsg_iov.iov_base = &sendbuf;
126	sendmsg_iov.iov_len = sizeof(sendbuf);
127
128	/* Socket message */
129	msg.msg_name = (void *) &sock->s_peer;
130	msg.msg_namelen = sizeof(sock->s_peer);
131	msg.msg_iov = &sendmsg_iov;
132	msg.msg_iovlen = 1; /* Only sending one iov */
133	msg.msg_control = NULL;
134	msg.msg_controllen = 0;
135	msg.msg_flags = 0;
136
137	/* Send message and verify sent */
138	num_char = sendmsg(sock->s_fd, &msg, 0);
139	if (num_char == -1)
140		return -errno;
141
142	/* RECEIVE GENL CMD RESPONSE */
143
144	/* Create receive iov buffer */
145	recvbuf = (char *) malloc(RECV_BUF_SIZE);
146
147	/* Attach to iov */
148	recvmsg_iov.iov_base = recvbuf;
149	recvmsg_iov.iov_len = RECV_BUF_SIZE;
150
151	msg.msg_iov = &recvmsg_iov;
152	msg.msg_iovlen = 1;
153
154	/***************************************************************/
155	/* Receive message. If multipart message, keep receiving until */
156	/* message type is NLMSG_DONE				       */
157	/***************************************************************/
158
159	do {
160
161		int recvmsg_len, nlmsg_rem;
162
163		/* Receive message */
164		memset(recvbuf, 0, RECV_BUF_SIZE);
165		recvmsg_len = recvmsg(sock->s_fd, &msg, 0);
166
167		/* Make sure receive successful */
168		if (recvmsg_len < 0) {
169			rc = -errno;
170			goto error_recvbuf;
171		}
172
173		/* Parse nlmsghdr */
174		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \
175				recvmsg_len, nlmsg_rem) {
176			struct nlattr *nla;
177			int nla_rem;
178
179			/* Check type */
180			switch (nlh->nlmsg_type) {
181			case NLMSG_DONE:
182				goto return_genl_id;
183				break;
184			case NLMSG_ERROR:
185
186				/* Should check nlmsgerr struct received */
187				fprintf(stderr, "Receive message error\n");
188				goto error_recvbuf;
189			case NLMSG_OVERRUN:
190				fprintf(stderr, "Receive data partly lost\n");
191				goto error_recvbuf;
192			case NLMSG_MIN_TYPE:
193			case NLMSG_NOOP:
194				break;
195			default:
196				break;
197			}
198
199
200
201			/* Check flags */
202			if (nlh->nlmsg_flags & NLM_F_MULTI)
203				nlm_f_multi = 1;
204			else
205				nlm_f_multi = 0;
206
207			if (nlh->nlmsg_type & NLMSG_DONE)
208				nlmsg_done = 1;
209			else
210				nlmsg_done = 0;
211
212			/* Iteratve over attributes */
213			nla_for_each_attr(nla,
214					nlmsg_attrdata(nlh, GENL_HDRLEN),
215					nlmsg_attrlen(nlh, GENL_HDRLEN),
216					nla_rem){
217
218				/* If this family is nl80211 */
219				if (nla->nla_type == CTRL_ATTR_FAMILY_NAME &&
220					!strcmp((char *)nla_data(nla),
221						"nl80211"))
222					nl80211_flag = 1;
223
224				/* Save the family id */
225				else if (nl80211_flag &&
226					nla->nla_type == CTRL_ATTR_FAMILY_ID) {
227					nl80211_genl_id =
228						*((int *)nla_data(nla));
229					nl80211_flag = 0;
230				}
231
232			}
233
234		}
235
236	} while (nlm_f_multi && !nlmsg_done);
237
238return_genl_id:
239	/* Return family id as cache pointer */
240	*result = (struct nl_cache *) nl80211_genl_id;
241	rc = 0;
242error_recvbuf:
243	free(recvbuf);
244error:
245	return rc;
246}
247
248/* Checks the netlink cache to find family reference by name string */
249/* NOTE: Caller needs to call genl_family_put() when done with *
250 * returned object */
251struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \
252					const char *name)
253{
254	/* TODO: When will we release this memory ? */
255	struct genl_family *gf = (struct genl_family *) \
256		malloc(sizeof(struct genl_family));
257	if (!gf)
258		goto fail;
259	memset(gf, 0, sizeof(*gf));
260
261	/* Add ref */
262	gf->ce_refcnt++;
263
264	/* Overriding cache pointer as family id for now */
265	gf->gf_id = (uint16_t) ((uint32_t) cache);
266	strcpy(gf->gf_name, "nl80211");
267
268	return gf;
269fail:
270	return NULL;
271
272}
273
274int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
275{
276	/* Hack to support wpa_supplicant */
277	if (strcmp(name, "nlctrl") == 0)
278		return NETLINK_GENERIC;
279	else {
280		int errsv = errno;
281		fprintf(stderr, \
282			"Only nlctrl supported by genl_ctrl_resolve!\n");
283		return -errsv;
284	}
285
286}
287
288