1ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/*
2ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Copyright (C) 2011 The Android Open Source Project
3ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *
4ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Licensed under the Apache License, Version 2.0 (the "License");
5ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * you may not use this file except in compliance with the License.
6ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * You may obtain a copy of the License at
7ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *
8ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *	http://www.apache.org/licenses/LICENSE-2.0
9ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *
10ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Unless required by applicable law or agreed to in writing, software
11ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * distributed under the License is distributed on an "AS IS" BASIS,
12ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * See the License for the specific language governing permissions and
14ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * limitations under the License.
15ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker */
16ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
17ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* NOTICE: This is a clean room re-implementation of libnl */
18ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
19ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <errno.h>
20ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <unistd.h>
21ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <stdio.h>
22ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <sys/time.h>
23b77d3d724945f38b39f3116e3aead4edcbd08a36Elliott Hughes#include <sys/socket.h>
24ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <linux/netlink.h>
252d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt#include <netlink/genl/ctrl.h>
262d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt#include <netlink/genl/family.h>
27ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include "netlink-types.h"
28ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
29ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Get head of attribute data. */
30ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerstruct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
31ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
32ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return (struct nlattr *) \
33ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen));
34ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
35ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
36ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
37ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Get length of attribute data. */
38ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
39ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
40ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct nlattr *nla;
41ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct nlmsghdr *nlh;
42ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
43ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nla = genlmsg_attrdata(gnlh, hdrlen);
44ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN);
45ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return (char *) nlmsg_tail(nlh) - (char *) nla;
46ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
47ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
48ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Add generic netlink header to netlink message. */
49ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makervoid *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
50ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		int hdrlen, int flags, uint8_t cmd, uint8_t version)
51ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
52ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int new_size;
53ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct nlmsghdr *nlh;
54ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct timeval tv;
55ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct genlmsghdr *gmh;
56ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
57ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Make sure nl_msg has enough space */
58ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen;
59ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if ((sizeof(struct nl_msg) + new_size) > msg->nm_size)
60ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		goto fail;
61ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
62ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Fill in netlink header */
63ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlh = msg->nm_nlh;
64ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlh->nlmsg_len = new_size;
65ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlh->nlmsg_type = family;
66ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlh->nlmsg_pid = getpid();
67ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK;
68ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
69ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Get current time for sequence number */
70ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (gettimeofday(&tv, NULL))
71ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		nlh->nlmsg_seq = 1;
72ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	else
73ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		nlh->nlmsg_seq = (int) tv.tv_sec;
74ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
75ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Setup genlmsghdr in new message */
76ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN);
77ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	gmh->cmd = (__u8) cmd;
78ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	gmh->version = version;
79ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
80ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return gmh;
81ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerfail:
82ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return NULL;
83ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
84ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
85ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
86ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Socket has already been alloced to connect it to kernel? */
87ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint genl_connect(struct nl_sock *sk)
88ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
89ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return nl_connect(sk, NETLINK_GENERIC);
90ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
91ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
92ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
93ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
94ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
95ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int rc = -1;
96ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int nl80211_genl_id = -1;
97ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)];
98ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct nlmsghdr nlmhdr;
99ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct genlmsghdr gmhhdr;
100ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct iovec sendmsg_iov;
101ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct msghdr msg;
102ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int num_char;
103ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	const int RECV_BUF_SIZE = getpagesize();
104ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	char *recvbuf;
105ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct iovec recvmsg_iov;
106ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0;
107ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct nlmsghdr *nlh;
108ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
109ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* REQUEST GENERIC NETLINK FAMILY ID */
110ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Message buffer */
111ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlmhdr.nlmsg_len = sizeof(sendbuf);
112ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlmhdr.nlmsg_type = NETLINK_GENERIC;
113ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
114ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlmhdr.nlmsg_seq = sock->s_seq_next;
115ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlmhdr.nlmsg_pid = sock->s_local.nl_pid;
116ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
117ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Generic netlink header */
118e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt	memset(&gmhhdr, 0, sizeof(gmhhdr));
119ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	gmhhdr.cmd = CTRL_CMD_GETFAMILY;
120ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	gmhhdr.version = CTRL_ATTR_FAMILY_ID;
121ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
122ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Combine netlink and generic netlink headers */
123ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr));
124ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr));
125ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
126ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Create IO vector with Netlink message */
127ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sendmsg_iov.iov_base = &sendbuf;
128ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sendmsg_iov.iov_len = sizeof(sendbuf);
129ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
130ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Socket message */
131ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_name = (void *) &sock->s_peer;
132ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_namelen = sizeof(sock->s_peer);
133ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_iov = &sendmsg_iov;
134ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_iovlen = 1; /* Only sending one iov */
135ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_control = NULL;
136ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_controllen = 0;
137ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_flags = 0;
138ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
139ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Send message and verify sent */
140ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	num_char = sendmsg(sock->s_fd, &msg, 0);
141ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (num_char == -1)
142ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		return -errno;
143ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
144ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* RECEIVE GENL CMD RESPONSE */
145ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
146ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Create receive iov buffer */
147ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	recvbuf = (char *) malloc(RECV_BUF_SIZE);
148ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
149ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Attach to iov */
150ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	recvmsg_iov.iov_base = recvbuf;
151ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	recvmsg_iov.iov_len = RECV_BUF_SIZE;
152ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
153ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_iov = &recvmsg_iov;
154ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_iovlen = 1;
155ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
156ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/***************************************************************/
157ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Receive message. If multipart message, keep receiving until */
158ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* message type is NLMSG_DONE				       */
159ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/***************************************************************/
160ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
161ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	do {
162ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
163ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		int recvmsg_len, nlmsg_rem;
164ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
165ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		/* Receive message */
166ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		memset(recvbuf, 0, RECV_BUF_SIZE);
167ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		recvmsg_len = recvmsg(sock->s_fd, &msg, 0);
168ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
169ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		/* Make sure receive successful */
170ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		if (recvmsg_len < 0) {
171ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			rc = -errno;
172ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			goto error_recvbuf;
173ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		}
174ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
175ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		/* Parse nlmsghdr */
176ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \
177ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				recvmsg_len, nlmsg_rem) {
178ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			struct nlattr *nla;
179ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			int nla_rem;
180ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
181ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			/* Check type */
182ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			switch (nlh->nlmsg_type) {
183ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			case NLMSG_DONE:
184ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				goto return_genl_id;
185ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				break;
186ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			case NLMSG_ERROR:
187ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
188ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				/* Should check nlmsgerr struct received */
189ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				fprintf(stderr, "Receive message error\n");
190ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				goto error_recvbuf;
191ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			case NLMSG_OVERRUN:
192ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				fprintf(stderr, "Receive data partly lost\n");
193ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				goto error_recvbuf;
194ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			case NLMSG_MIN_TYPE:
195ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			case NLMSG_NOOP:
196ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				break;
197ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			default:
198ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				break;
199ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			}
200ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
201ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
202ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
203ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			/* Check flags */
204ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			if (nlh->nlmsg_flags & NLM_F_MULTI)
205ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				nlm_f_multi = 1;
206ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			else
207ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				nlm_f_multi = 0;
208ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
209ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			if (nlh->nlmsg_type & NLMSG_DONE)
210ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				nlmsg_done = 1;
211ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			else
212ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				nlmsg_done = 0;
213ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
214ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			/* Iteratve over attributes */
215ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			nla_for_each_attr(nla,
216ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					nlmsg_attrdata(nlh, GENL_HDRLEN),
217ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					nlmsg_attrlen(nlh, GENL_HDRLEN),
218ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					nla_rem){
219ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
220ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				/* If this family is nl80211 */
221ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				if (nla->nla_type == CTRL_ATTR_FAMILY_NAME &&
222ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					!strcmp((char *)nla_data(nla),
223ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker						"nl80211"))
224ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					nl80211_flag = 1;
225ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
226ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				/* Save the family id */
227ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				else if (nl80211_flag &&
228e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt					nla->nla_type == CTRL_ATTR_FAMILY_ID) {
229e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt					nl80211_genl_id =
230ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker						*((int *)nla_data(nla));
231e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt					nl80211_flag = 0;
232e5de9ee4915bafd7f31a96260613d8b93aba8351Dmitry Shmidt				}
233ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
234ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			}
235ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
236ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		}
237ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
238ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	} while (nlm_f_multi && !nlmsg_done);
239ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
240ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerreturn_genl_id:
241ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Return family id as cache pointer */
242ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	*result = (struct nl_cache *) nl80211_genl_id;
243ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	rc = 0;
244ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makererror_recvbuf:
245ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	free(recvbuf);
246ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makererror:
247ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return rc;
248ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
249ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
250ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Checks the netlink cache to find family reference by name string */
251ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* NOTE: Caller needs to call genl_family_put() when done with *
252ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * returned object */
253ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerstruct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \
254ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					const char *name)
255ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
256ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct genl_family *gf = (struct genl_family *) \
257ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		malloc(sizeof(struct genl_family));
258ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (!gf)
259ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		goto fail;
260ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	memset(gf, 0, sizeof(*gf));
261ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
262ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Add ref */
263ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	gf->ce_refcnt++;
264ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
265ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Overriding cache pointer as family id for now */
266ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	gf->gf_id = (uint16_t) ((uint32_t) cache);
2672d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	strncpy(gf->gf_name, name, GENL_NAMSIZ);
268ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
269ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return gf;
270ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerfail:
271ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return NULL;
272ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
273ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
274ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
275ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint genl_ctrl_resolve(struct nl_sock *sk, const char *name)
276ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
2772d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	struct nl_cache *cache = NULL;
2782d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	struct genl_family *gf = NULL;
2792d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	int id = -1;
2802d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt
281ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Hack to support wpa_supplicant */
282ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (strcmp(name, "nlctrl") == 0)
283ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		return NETLINK_GENERIC;
2842d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt
2852d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	if (strcmp(name, "nl80211") != 0) {
2862d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt		fprintf(stderr, "%s is not supported\n", name);
2872d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt		return id;
288ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	}
289ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
2902d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	if (!genl_ctrl_alloc_cache(sk, &cache)) {
2912d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt		gf = genl_ctrl_search_by_name(cache, name);
2922d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt		if (gf)
2932d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt			id = genl_family_get_id(gf);
2942d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	}
2952d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt
2962d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	if (gf)
2972d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt		genl_family_put(gf);
2982d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	if (cache)
2992d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt		nl_cache_free(cache);
300ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
3012d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt	return id;
3022d9a6281ca4fdacd88098f3b135b89b9d0c65226Dmitry Shmidt}
303