1 /*
2  * lib/route/cls/ematch/nbyte.c		Nbyte comparison
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) 2010-2013 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup ematch
14  * @defgroup em_nbyte N-Byte Comparison
15  *
16  * @{
17  */
18 
19 #include <netlink-private/netlink.h>
20 #include <netlink-private/tc.h>
21 #include <netlink/netlink.h>
22 #include <netlink/route/cls/ematch.h>
23 #include <netlink/route/cls/ematch/nbyte.h>
24 #include <linux/tc_ematch/tc_em_nbyte.h>
25 
26 struct nbyte_data
27 {
28 	struct tcf_em_nbyte	cfg;
29 	uint8_t *		pattern;
30 };
31 
rtnl_ematch_nbyte_set_offset(struct rtnl_ematch * e,uint8_t layer,uint16_t offset)32 void rtnl_ematch_nbyte_set_offset(struct rtnl_ematch *e, uint8_t layer,
33 				  uint16_t offset)
34 {
35 	struct nbyte_data *n = rtnl_ematch_data(e);
36 	n->cfg.off = offset;
37 	n->cfg.layer = layer;
38 }
39 
rtnl_ematch_nbyte_get_offset(struct rtnl_ematch * e)40 uint16_t rtnl_ematch_nbyte_get_offset(struct rtnl_ematch *e)
41 {
42 	return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.off;
43 }
44 
rtnl_ematch_nbyte_get_layer(struct rtnl_ematch * e)45 uint8_t rtnl_ematch_nbyte_get_layer(struct rtnl_ematch *e)
46 {
47 	return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.layer;
48 }
49 
rtnl_ematch_nbyte_set_pattern(struct rtnl_ematch * e,uint8_t * pattern,size_t len)50 void rtnl_ematch_nbyte_set_pattern(struct rtnl_ematch *e,
51 				   uint8_t *pattern, size_t len)
52 {
53 	struct nbyte_data *n = rtnl_ematch_data(e);
54 
55 	if (n->pattern)
56 		free(n->pattern);
57 
58 	n->pattern = pattern;
59 	n->cfg.len = len;
60 }
61 
rtnl_ematch_nbyte_get_pattern(struct rtnl_ematch * e)62 uint8_t *rtnl_ematch_nbyte_get_pattern(struct rtnl_ematch *e)
63 {
64 	return ((struct nbyte_data *) rtnl_ematch_data(e))->pattern;
65 }
66 
rtnl_ematch_nbyte_get_len(struct rtnl_ematch * e)67 size_t rtnl_ematch_nbyte_get_len(struct rtnl_ematch *e)
68 {
69 	return ((struct nbyte_data *) rtnl_ematch_data(e))->cfg.len;
70 }
71 
layer_txt(struct tcf_em_nbyte * nbyte)72 static const char *layer_txt(struct tcf_em_nbyte *nbyte)
73 {
74 	switch (nbyte->layer) {
75 	case TCF_LAYER_LINK:
76 		return "link";
77 	case TCF_LAYER_NETWORK:
78 		return "net";
79 	case TCF_LAYER_TRANSPORT:
80 		return "trans";
81 	default:
82 		return "?";
83 	}
84 }
85 
nbyte_parse(struct rtnl_ematch * e,void * data,size_t len)86 static int nbyte_parse(struct rtnl_ematch *e, void *data, size_t len)
87 {
88 	struct nbyte_data *n = rtnl_ematch_data(e);
89 	size_t hdrlen = sizeof(struct tcf_em_nbyte);
90 	size_t plen = len - hdrlen;
91 
92 	memcpy(&n->cfg, data, hdrlen);
93 	if (plen > 0) {
94 		if (!(n->pattern = calloc(1, plen)))
95 			return -NLE_NOMEM;
96 
97 		memcpy(n->pattern, (char *) data + hdrlen, plen);
98 	}
99 
100 	return 0;
101 }
102 
nbyte_dump(struct rtnl_ematch * e,struct nl_dump_params * p)103 static void nbyte_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
104 {
105 	struct nbyte_data *n = rtnl_ematch_data(e);
106 	int i;
107 
108 	nl_dump(p, "pattern(%u:[", n->cfg.len);
109 
110 	for (i = 0; i < n->cfg.len; i++) {
111 		nl_dump(p, "%02x", n->pattern[i]);
112 		if (i+1 < n->cfg.len)
113 			nl_dump(p, " ");
114 	}
115 
116 	nl_dump(p, "] at %s+%u)", layer_txt(&n->cfg), n->cfg.off);
117 }
118 
nbyte_free(struct rtnl_ematch * e)119 static void nbyte_free(struct rtnl_ematch *e)
120 {
121 	struct nbyte_data *n = rtnl_ematch_data(e);
122 	free(n->pattern);
123 }
124 
125 static struct rtnl_ematch_ops nbyte_ops = {
126 	.eo_kind	= TCF_EM_NBYTE,
127 	.eo_name	= "nbyte",
128 	.eo_minlen	= sizeof(struct tcf_em_nbyte),
129 	.eo_datalen	= sizeof(struct nbyte_data),
130 	.eo_parse	= nbyte_parse,
131 	.eo_dump	= nbyte_dump,
132 	.eo_free	= nbyte_free,
133 };
134 
nbyte_init(void)135 static void __init nbyte_init(void)
136 {
137 	rtnl_ematch_register(&nbyte_ops);
138 }
139 
140 /** @} */
141