1/*
2 * Copyright (c) 2013 The Linux Foundation. All rights reserved.
3 * Permission to use, copy, modify, and/or distribute this software for
4 * any purpose with or without fee is hereby granted, provided that the
5 * above copyright notice and this permission notice appear in all copies.
6 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
7 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
8 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
9 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
10 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
11 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
12 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
13 */
14
15#include <netlink/genl/genl.h>
16#include <netlink/genl/ctrl.h>
17#include <errno.h>
18#include <stdio.h>
19#include <arpa/inet.h>
20
21#include <fast-classifier.h>
22
23static struct nl_sock *sock;
24static struct nl_sock *sock_event;
25static int family;
26static int grp_id;
27
28static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = {
29	[FAST_CLASSIFIER_A_TUPLE] = { .type = NLA_UNSPEC },
30};
31
32void dump_fc_tuple(struct fast_classifier_tuple *fc_msg) {
33	char src_str[INET_ADDRSTRLEN];
34	char dst_str[INET_ADDRSTRLEN];
35
36	printf("TUPLE: %d, %s, %s, %d, %d"
37			" SMAC=%02x:%02x:%02x:%02x:%02x:%02x",
38			" DMAC=%02x:%02x:%02x:%02x:%02x:%02x\n",
39				fc_msg->proto,
40				inet_ntop(AF_INET, &(fc_msg->src_saddr),  src_str, INET_ADDRSTRLEN),
41				inet_ntop(AF_INET, &(fc_msg->dst_saddr),  dst_str, INET_ADDRSTRLEN),
42				fc_msg->sport, fc_msg->dport,
43				fc_msg->smac[0], fc_msg->smac[1], fc_msg->smac[2],
44				fc_msg->smac[3], fc_msg->smac[4], fc_msg->smac[5],
45				fc_msg->dmac[0], fc_msg->dmac[1], fc_msg->dmac[2],
46				fc_msg->dmac[3], fc_msg->dmac[4], fc_msg->dmac[5]);
47}
48
49static int parse_cb(struct nl_msg *msg, void *arg) {
50	struct nlmsghdr *nlh = nlmsg_hdr(msg);
51	struct genlmsghdr *gnlh = nlmsg_data(nlh);
52	struct nlattr *attrs[FAST_CLASSIFIER_A_MAX];
53
54	genlmsg_parse(nlh, 0, attrs, FAST_CLASSIFIER_A_MAX, fast_classifier_genl_policy);
55
56	switch (gnlh->cmd) {
57	case FAST_CLASSIFIER_C_OFFLOADED:
58		printf("Got a offloaded message\n");
59		dump_fc_tuple(nla_data(attrs[FAST_CLASSIFIER_A_TUPLE]));
60		return NL_OK;
61	case FAST_CLASSIFIER_C_DONE:
62		printf("Got a done message\n");
63		dump_fc_tuple(nla_data(attrs[FAST_CLASSIFIER_A_TUPLE]));
64		return NL_OK;
65	}
66
67	return NL_SKIP;
68}
69
70int fast_classifier_init() {
71	int err;
72
73	sock = nl_socket_alloc();
74	if (sock == NULL) {
75		printf("Unable to allocation socket.\n");
76		return -1;
77	}
78	genl_connect(sock);
79
80	sock_event = nl_socket_alloc();
81	if (sock_event == NULL) {
82	        nl_close(sock);
83		nl_socket_free(sock);
84		printf("Unable to allocation socket.\n");
85		return -1;
86	}
87	genl_connect(sock_event);
88
89	family = genl_ctrl_resolve(sock, FAST_CLASSIFIER_GENL_NAME);
90	if (family < 0) {
91		nl_close(sock_event);
92	        nl_close(sock);
93		nl_socket_free(sock);
94		nl_socket_free(sock_event);
95		printf("Unable to resolve family\n");
96		return -1;
97	}
98
99	grp_id = genl_ctrl_resolve_grp(sock, FAST_CLASSIFIER_GENL_NAME,
100					FAST_CLASSIFIER_GENL_MCGRP);
101	if (grp_id < 0) {
102		printf("Unable to resolve mcast group\n");
103		return -1;
104	}
105
106	err = nl_socket_add_membership(sock_event, grp_id);
107	if (err < 0) {
108		printf("Unable to add membership\n");
109		return -1;
110	}
111
112	nl_socket_disable_seq_check(sock_event);
113	nl_socket_modify_cb(sock_event, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL);
114
115	return 0;
116}
117
118void fast_classifier_close() {
119	nl_close(sock_event);
120        nl_close(sock);
121	nl_socket_free(sock_event);
122        nl_socket_free(sock);
123}
124
125void fast_classifier_ipv4_offload(unsigned char proto, unsigned long src_saddr,
126					 unsigned long dst_saddr, unsigned short sport,
127					 unsigned short dport) {
128	struct nl_msg *msg;
129	int ret;
130#ifdef DEBUG
131	char src_str[INET_ADDRSTRLEN];
132	char dst_str[INET_ADDRSTRLEN];
133#endif
134	struct fast_classifier_tuple fc_msg;
135
136#ifdef DEBUG
137	printf("DEBUG: would offload: %d, %s, %s, %d, %d\n", proto,
138				inet_ntop(AF_INET, &src_saddr,  src_str, INET_ADDRSTRLEN),
139				inet_ntop(AF_INET, &dst_saddr,  dst_str, INET_ADDRSTRLEN),
140				sport, dport);
141#endif
142
143	fc_msg.proto = proto;
144	fc_msg.src_saddr = src_saddr;
145	fc_msg.dst_saddr = dst_saddr;
146	fc_msg.sport = sport;
147	fc_msg.dport = dport;
148	fc_msg.smac[0] = 'a';
149	fc_msg.smac[1] = 'b';
150	fc_msg.smac[2] = 'c';
151	fc_msg.smac[3] = 'd';
152	fc_msg.smac[4] = 'e';
153	fc_msg.smac[5] = 'f';
154	fc_msg.dmac[0] = 'f';
155	fc_msg.dmac[1] = 'e';
156	fc_msg.dmac[2] = 'd';
157	fc_msg.dmac[3] = 'c';
158	fc_msg.dmac[4] = 'b';
159	fc_msg.dmac[5] = 'a';
160
161	if (fast_classifier_init() < 0) {
162		printf("Unable to init generic netlink\n");
163		exit(1);
164	}
165
166	msg = nlmsg_alloc();
167	if (msg == NULL) {
168		nl_socket_free(sock);
169		printf("Unable to allocate message\n");
170		return;
171	}
172
173        genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family,
174			FAST_CLASSIFIER_GENL_HDRSIZE, NLM_F_REQUEST,
175			FAST_CLASSIFIER_C_OFFLOAD, FAST_CLASSIFIER_GENL_VERSION);
176        nla_put(msg, 1, sizeof(fc_msg), &fc_msg);
177
178        ret = nl_send_auto_complete(sock, msg);
179
180        nlmsg_free(msg);
181        if (ret < 0) {
182                printf("nlmsg_free failed");
183		nl_close(sock);
184		nl_socket_free(sock);
185                return;
186        }
187
188        ret = nl_wait_for_ack(sock);
189        if (ret < 0) {
190                printf("wait for ack failed");
191		nl_close(sock);
192		nl_socket_free(sock);
193                return;
194        }
195}
196
197void fast_classifier_listen_for_messages(void) {
198	printf("waiting for netlink events\n");
199
200	while (1) {
201		nl_recvmsgs_default(sock_event);
202	}
203}
204int main(int argc, char *argv[])
205{
206	if (fast_classifier_init() < 0) {
207		printf("Unable to init generic netlink\n");
208		exit(1);
209	}
210
211	fast_classifier_ipv4_offload('a', 0, 0, 0, 0);
212
213	/* this never returns */
214	fast_classifier_listen_for_messages();
215
216	fast_classifier_close();
217
218        return 0;
219}
220