1/*
2 * lib/route/cls/ematch/cmp.c	Simple packet data comparison ematch
3 *
4 *	This library is free software; you can redistribute it and/or
5 *	modify it under the terms of the GNU Lesser General Public
6 *	License as published by the Free Software Foundation version 2.1
7 *	of the License.
8 *
9 * Copyright (c) 2008-2009 Thomas Graf <tgraf@suug.ch>
10 */
11
12/**
13 * @ingroup ematch
14 * @defgroup em_cmp Simple packet data comparison
15 *
16 * @{
17 */
18
19#include <netlink-local.h>
20#include <netlink-tc.h>
21#include <netlink/netlink.h>
22#include <netlink/route/cls/ematch.h>
23#include <linux/tc_ematch/tc_em_cmp.h>
24
25void rtnl_ematch_cmp_set(struct rtnl_ematch *ematch,
26			 struct tcf_em_cmp *cfg)
27{
28	memcpy(rtnl_ematch_data(ematch), cfg, sizeof(*cfg));
29}
30
31struct tcf_em_cmp *rtnl_ematch_cmp_get(struct rtnl_ematch *ematch)
32{
33	return rtnl_ematch_data(ematch);
34}
35
36static const char *align_txt(struct tcf_em_cmp *cmp)
37{
38	switch (cmp->align) {
39	case TCF_EM_ALIGN_U8:
40		return "u8";
41	case TCF_EM_ALIGN_U16:
42		return (cmp->flags & TCF_EM_CMP_TRANS) ? "h16" : "u16";
43	case TCF_EM_ALIGN_U32:
44		return (cmp->flags & TCF_EM_CMP_TRANS) ? "h32" : "u32";
45	default:
46		return (cmp->flags & TCF_EM_CMP_TRANS) ? "h?" : "u?";
47	}
48}
49
50static const char *layer_txt(struct tcf_em_cmp *cmp)
51{
52	switch (cmp->layer) {
53	case TCF_LAYER_LINK:
54		return "link";
55	case TCF_LAYER_NETWORK:
56		return "network";
57	case TCF_LAYER_TRANSPORT:
58		return "transport";
59	default:
60		return "?";
61	}
62}
63
64static const char *relation_txt(struct tcf_em_cmp *cmp)
65{
66	switch (cmp->opnd) {
67	case TCF_EM_OPND_EQ:
68		return "eq";
69	case TCF_EM_OPND_LT:
70		return "lt";
71	case TCF_EM_OPND_GT:
72		return "gt";
73	default:
74		return "?";
75	}
76}
77
78static int cmp_parse(struct rtnl_ematch *m, void *data, size_t len)
79{
80	memcpy(rtnl_ematch_data(m), data, len);
81
82	return 0;
83}
84
85static void cmp_dump(struct rtnl_ematch *m, struct nl_dump_params *p)
86{
87	struct tcf_em_cmp *cmp = rtnl_ematch_data(m);
88
89	nl_dump(p, "%s at %s+%u ",
90		align_txt(cmp), layer_txt(cmp), cmp->off);
91
92	if (cmp->mask)
93		nl_dump(p, "& 0x%x ", cmp->mask);
94
95	nl_dump(p, "%s %u", relation_txt(cmp), cmp->val);
96}
97
98static struct rtnl_ematch_ops cmp_ops = {
99	.eo_kind	= TCF_EM_CMP,
100	.eo_name	= "cmp",
101	.eo_datalen	= sizeof(struct tcf_em_cmp),
102	.eo_parse	= cmp_parse,
103	.eo_dump	= cmp_dump,
104};
105
106static void __init cmp_init(void)
107{
108	rtnl_ematch_register(&cmp_ops);
109}
110
111static void __exit cmp_exit(void)
112{
113	rtnl_ematch_unregister(&cmp_ops);
114}
115
116/** @} */
117