blob: 541b41a2914542f72d5d062aa664aea7405d745e [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/*
2 * Fastpath Cm Interface
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU FP_ERR( Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <linux/if_vlan.h>
11#include "fp_common.h"
12#include "fp_database.h"
13#include "fp_device.h"
14#include "fp_core.h"
15#include "../linux/drivers/marvell/toev2/toe.h"
16#include "../linux/drivers/marvell/toev2/toe_464xlat.h"
17
18
19#define MAXLEN 256
20#define DEVICE_NAME_MAXSIZE 64
21#define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN))
22
23static u32 g_cm_nlpid = -1;
24static u32 speed_thresh = 1000; /* kbps */
25
26static int fp_cm_genl_get_tuple(struct sk_buff *skb, struct genl_info *info);
27static int fp_cm_genl_del_tuple(struct sk_buff *skb, struct genl_info *info);
28static int fp_cm_genl_set_tuple(struct sk_buff *skb, struct genl_info *info);
29static int fp_cm_genl_set_pid(struct sk_buff *skb, struct genl_info *info);
30static void fp_cm_update_genl_pid(u32 pid);
31static u32 fp_cm_get_genl_pid(void);
32
33/* attribute type */
34enum fp_cm_genl_attrs {
35 CM_ATTR_UNSPEC,
36 CM_ATTR_PID,
37 CM_ATTR_SRC_IP,
38 CM_ATTR_DST_IP,
39 CM_ATTR_SRC_IP6, /* struct in6_addr */
40 CM_ATTR_DST_IP6, /* struct in6_addr */
41 CM_ATTR_SRC_PORT,
42 CM_ATTR_DST_PORT,
43 CM_ATTR_PROTO,
44 CM_ATTR_SRC_MAC,
45 CM_ATTR_DST_MAC,
46 CM_ATTR_SNAT,
47 CM_ATTR_FWD,
48 CM_ATTR_NAT_PORT,
49 CM_ATTR_NAT_IP,
50 CM_ATTR_DEVICE_NAME,
51 CM_ATTR_MCID,
52 CM_ATTR_RBID,
53 CM_ATTR_QFI,
54 CM_ATTR_PDU,
55 CM_ATTR_IN_PKT,
56 CM_ATTR_OUT_PKT,
57 CM_ATTR_VLAN_EN,
58 CM_ATTR_VLANID,
59 CM_ATTR_XLAT_EN,
60 CM_ATTR_XLAT_INSTANCE,
61 CM_ATTR_UPDATE_TUPLE,
62/* private: internal use only */
63 __FP_CM_ATTR_AFTER_LAST
64};
65#define FP_CM_ATTR_MAX (__FP_CM_ATTR_AFTER_LAST - 1)
66
67/* commands */
68enum fp_cm_commands {
69 CM_CMD_UNSPEC,
70 CM_CMD_SET_PID,
71 CM_CMD_GET_TUPLE,
72 CM_CMD_SET_TUPLE,
73 CM_CMD_DEL_TUPLE,
74 __FP_CM_CMD_AFTER_LAST,
75};
76#define FP_CM_CMD_MAX (__FP_CM_CMD_AFTER_LAST - 1)
77
78#define ETH_TYPE_LEN 2
79#define FP_CM_NLMSG_DEFAULT_SIZE 256
80
81
82/* attribute policy */
83static struct nla_policy fp_cm_genl_policy[FP_CM_ATTR_MAX + 1] = {
84 [CM_ATTR_PID] = { .type = NLA_U32 },
85 [CM_ATTR_SRC_IP] = { .type = NLA_U32 },
86 [CM_ATTR_DST_IP] = { .type = NLA_U32 },
87 [CM_ATTR_SRC_IP6] = {
88 .type = NLA_BINARY,
89 .len = sizeof(struct in6_addr),
90 },
91 [CM_ATTR_DST_IP6] = {
92 .type = NLA_BINARY,
93 .len = sizeof(struct in6_addr),
94 },
95 [CM_ATTR_SRC_PORT] = { .type = NLA_U16 },
96 [CM_ATTR_DST_PORT] = { .type = NLA_U16 },
97 [CM_ATTR_PROTO] = { .type = NLA_U8 },
98 [CM_ATTR_SNAT] = { .type = NLA_U8 },
99 [CM_ATTR_FWD] = { .type = NLA_U8 },
100 [CM_ATTR_NAT_PORT] = { .type = NLA_U16 },
101 [CM_ATTR_NAT_IP] = { .type = NLA_U32 },
102 [CM_ATTR_SRC_MAC] = { .type = NLA_STRING},
103 [CM_ATTR_DST_MAC] = { .type = NLA_STRING},
104 [CM_ATTR_DEVICE_NAME] = { .type = NLA_STRING,
105 .len = DEVICE_NAME_MAXSIZE },
106 [CM_ATTR_MCID] = { .type = NLA_U8 },
107 [CM_ATTR_RBID] = { .type = NLA_U8 },
108 [CM_ATTR_QFI] = { .type = NLA_U8 },
109 [CM_ATTR_PDU] = { .type = NLA_U8 },
110 [CM_ATTR_IN_PKT] = { .type = NLA_U8 },
111 [CM_ATTR_OUT_PKT] = { .type = NLA_U8 },
112 [CM_ATTR_VLAN_EN] = { .type = NLA_U8 },
113 [CM_ATTR_VLANID] = { .type = NLA_U16 },
114 [CM_ATTR_XLAT_EN] = { .type = NLA_U32 },
115 [CM_ATTR_XLAT_INSTANCE] = { .type = NLA_STRING },
116 [CM_ATTR_UPDATE_TUPLE] = { .type = NLA_U8 },
117};
118
119/* operation definition */
120struct genl_ops fp_cm_genl_ops[] = {
121 {
122 .cmd = CM_CMD_SET_PID,
123 .flags = 0,
124 .doit = fp_cm_genl_set_pid,
125 },
126 {
127 .cmd = CM_CMD_GET_TUPLE,
128 .flags = 0,
129 .doit = fp_cm_genl_get_tuple,
130 },
131 {
132 .cmd = CM_CMD_SET_TUPLE,
133 .flags = 0,
134 .doit = fp_cm_genl_set_tuple,
135 },
136 {
137 .cmd = CM_CMD_DEL_TUPLE,
138 .flags = 0,
139 .doit = fp_cm_genl_del_tuple,
140 }
141};
142
143static struct genl_family fp_cm_genl_family = {
144 .hdrsize = 0,
145 .name = "fp_cm",
146 .version = 1,
147 .maxattr = FP_CM_ATTR_MAX,
148 .policy = fp_cm_genl_policy,
149 .ops = fp_cm_genl_ops,
150 .n_ops = ARRAY_SIZE(fp_cm_genl_ops),
151};
152
153static void fp_cm_update_genl_pid(u32 pid)
154{
155 g_cm_nlpid = pid;
156}
157
158static u32 fp_cm_get_genl_pid(void)
159{
160 return g_cm_nlpid;
161}
162
163static int fp_cm_genl_set_pid(struct sk_buff *skb, struct genl_info *info)
164{
165 u32 pid;
166
167 if (!info->attrs[CM_ATTR_PID])
168 return -EINVAL;
169
170 pid = nla_get_u32(info->attrs[CM_ATTR_PID]);
171 printk("%s, get cm pid: %d\n", __func__, pid);
172 fp_cm_update_genl_pid(pid);
173 return 0;
174}
175
176static int __fp_cm_genl_fill_tuple_info(struct sk_buff *msg, struct nf_conntrack_tuple *tuple,
177 struct fpdb_entry *el, u32 portid, u32 seq, int flags, int add)
178{
179 void *hdr;
180 struct hh_cache *hh;
181 int hh_len;
182 u8 proto = 0, in_pkt = 0, out_pkt = 0, fwd = 0, nat = 0;
183 u16 nat_port = 0;
184 u32 nat_ip = 0;
185 char src_mac[ETH_ALEN]={0}, dst_mac[ETH_ALEN]={0};
186 struct fp_net_device *dst, *src;
187 struct vlan_dev_priv *vlan;
188 struct net_device *src_dev, *dst_dev;
189
190 hh = &el->hh;
191 hh_len = hh->hh_len;
192
193 if (add)
194 hdr = genlmsg_put(msg, portid, seq, &fp_cm_genl_family, flags,
195 CM_CMD_GET_TUPLE);
196 else
197 hdr = genlmsg_put(msg, portid, seq, &fp_cm_genl_family, flags,
198 CM_CMD_DEL_TUPLE);
199 if (!hdr)
200 return -EMSGSIZE;
201
202 if (tuple->src.l3num == AF_INET) {
203 if (nla_put_u32(msg, CM_ATTR_SRC_IP, tuple->src.u3.ip) ||
204 nla_put_u32(msg, CM_ATTR_DST_IP, tuple->dst.u3.ip))
205 goto nla_put_failure;
206 } else if (tuple->src.l3num == AF_INET6) {
207 if (nla_put(msg, CM_ATTR_SRC_IP6, sizeof(struct in6_addr), &tuple->src.u3.in6) ||
208 nla_put(msg, CM_ATTR_DST_IP6, sizeof(struct in6_addr), &tuple->dst.u3.in6))
209 goto nla_put_failure;
210 }
211
212 if (tuple->dst.protonum == IPPROTO_UDP)
213 proto = TOE_UDP;
214 else if (tuple->dst.protonum == IPPROTO_TCP)
215 proto = TOE_TCP;
216 else
217 proto = TOE_MAX;
218
219 if (nla_put_u16(msg, CM_ATTR_SRC_PORT, ntohs(tuple->src.u.all)) ||
220 nla_put_u16(msg, CM_ATTR_DST_PORT, ntohs(tuple->dst.u.all)) ||
221 nla_put_u8(msg, CM_ATTR_PROTO, proto))
222 goto nla_put_failure;
223
224 src = rcu_dereference_bh(el->in_dev);
225 dst = rcu_dereference_bh(el->out_dev);
226
227 if (is_vlan_dev(src->dev)) {
228 vlan = vlan_dev_priv(src->dev);
229 src_dev = vlan->real_dev;
230 nla_put_u8(msg, CM_ATTR_VLAN_EN, 1);
231 nla_put_u16(msg, CM_ATTR_VLANID, vlan->vlan_id);
232 } else
233 src_dev = src->dev;
234
235 if (!strncasecmp(src_dev->name, "ccinet", 6))
236 in_pkt = PDU_PKT;
237 else if (!strncasecmp(src_dev->name, "usbnet", 6))
238 in_pkt = USB_PKT;
239 else if (!strncasecmp(src_dev->name, "wlan", 4))
240 in_pkt = WIFI_PKT;
241 else if (!strncasecmp(src_dev->name, "eth", 3))
242 in_pkt = ETH_PKT;
243 else
244 in_pkt = AP_PKT;
245
246 if (is_vlan_dev(dst->dev)) {
247 vlan = vlan_dev_priv(dst->dev);
248 dst_dev = vlan->real_dev;
249 nla_put_u8(msg, CM_ATTR_VLAN_EN, 1);
250 nla_put_u16(msg, CM_ATTR_VLANID, vlan->vlan_id);
251 } else
252 dst_dev = dst->dev;
253
254 if (!strncasecmp(dst_dev->name, "ccinet", 6))
255 out_pkt = PDU_PKT;
256 else if (!strncasecmp(dst_dev->name, "usbnet", 6))
257 out_pkt = USB_PKT;
258 else if (!strncasecmp(dst_dev->name, "wlan", 4))
259 out_pkt = WIFI_PKT;
260 else if (!strncasecmp(dst_dev->name, "eth", 3))
261 out_pkt = ETH_PKT;
262 else
263 out_pkt = AP_PKT;
264
265 fwd = (in_pkt != AP_PKT) && (out_pkt != AP_PKT);
266 if (fwd && (tuple->src.l3num == AF_INET)) {
267 if (in_pkt == PDU_PKT && (out_pkt == USB_PKT || out_pkt == WIFI_PKT || out_pkt == ETH_PKT)) {
268 nat = 1;
269 nat_ip = el->out_tuple.src.u3.ip;
270 nat_port = ntohs(el->out_tuple.src.u.all);
271 } else if ((in_pkt == USB_PKT || in_pkt == WIFI_PKT || in_pkt == ETH_PKT) && out_pkt == PDU_PKT) {
272 nat = 1;
273 nat_ip = el->out_tuple.dst.u3.ip;
274 nat_port = ntohs(el->out_tuple.dst.u.all);
275 } else
276 /* CP TOE WIFI/WIFI TOE CP no need nat */
277 nat = 0;
278 }
279
280 if (nla_put_u8(msg, CM_ATTR_IN_PKT, in_pkt) ||
281 nla_put_u8(msg, CM_ATTR_OUT_PKT, out_pkt) ||
282 nla_put_u8(msg, CM_ATTR_FWD, fwd) ||
283 nla_put_string(msg, CM_ATTR_DEVICE_NAME, dst->dev->name))
284 goto nla_put_failure;
285
286 if (tuple->src.l3num == AF_INET) {
287 if (nla_put_u8(msg, CM_ATTR_SNAT, nat) ||
288 nla_put_u16(msg, CM_ATTR_NAT_PORT, nat_port) ||
289 nla_put_u32(msg, CM_ATTR_NAT_IP, nat_ip))
290 goto nla_put_failure;
291 }
292
293 if (hh_len) {
294 if (likely(hh_len <= HH_DATA_MOD)) {
295 /* this is inlined by gcc */
296 char mac_header[HH_DATA_MOD];
297 memcpy(mac_header, hh->hh_data, HH_DATA_MOD);
298 memcpy(src_mac, &mac_header[HH_DATA_MOD-ETH_TYPE_LEN-ETH_ALEN], ETH_ALEN);
299 memcpy(dst_mac, &mac_header[HH_DATA_MOD-ETH_TYPE_LEN-ETH_ALEN*2], ETH_ALEN);
300 } else {
301 int hh_alen = HH_DATA_ALIGN(hh_len);
302 char *mac_header = kmalloc(hh_alen, GFP_ATOMIC);
303
304 memcpy(mac_header, hh->hh_data, hh_alen);
305 memcpy(src_mac, mac_header+(hh_alen-ETH_TYPE_LEN-ETH_ALEN), ETH_ALEN);
306 memcpy(dst_mac, mac_header+(hh_alen-ETH_TYPE_LEN-ETH_ALEN*2), ETH_ALEN);
307 kfree(mac_header);
308 }
309 }
310
311 if (nla_put(msg, CM_ATTR_SRC_MAC, ETH_ALEN, src_mac) ||
312 nla_put(msg, CM_ATTR_DST_MAC, ETH_ALEN, dst_mac))
313 goto nla_put_failure;
314
315 pr_debug("%s:\n in:%d, out:%d\n src_ip:0x%x\n dst_ip:0x%x\n src_port:%d\n dst_prot:%d\n"
316 " protocol:%d\n nat_port:%d\n nat_ip:0x%x\n fwd:%d\n snat:%d\n",
317 __func__, in_pkt, out_pkt, ntohl(tuple->src.u3.ip), ntohl(tuple->dst.u3.ip), ntohs(tuple->src.u.all),
318 ntohs(tuple->dst.u.all), proto, nat_port, ntohl(nat_ip), fwd, nat);
319
320 genlmsg_end(msg, hdr);
321 if (add)
322 el->nl_flag = 1;
323
324 return 0;
325
326nla_put_failure:
327 genlmsg_cancel(msg, hdr);
328 return -EMSGSIZE;
329}
330
331static int __fp_cm_genl_fill_464xlat_info(struct sk_buff *msg, struct nf_conntrack_tuple *tuple,
332 struct fpdb_entry *el, u32 portid, u32 seq, int flags, int add)
333{
334 void *hdr;
335 struct hh_cache *hh;
336 int hh_len;
337 u8 proto = 0, in_pkt = 0, out_pkt = 0, fwd = 0, nat = 0;
338 u16 nat_port = 0;
339 u32 nat_ip = 0;
340 char src_mac[ETH_ALEN]={0}, dst_mac[ETH_ALEN]={0};
341 struct fp_net_device *dst, *src;
342 struct vlan_dev_priv *vlan;
343 struct net_device *src_dev, *dst_dev;
344 nat46_instance_t *nat46;
345 nat46_netdev_priv_t *dev_priv;
346
347 hh = &el->hh;
348 hh_len = hh->hh_len;
349
350 if (tuple->src.l3num == AF_INET6) {
351 el->nl_flag = 1;
352 return 0;
353 }
354
355 if (add)
356 hdr = genlmsg_put(msg, portid, seq, &fp_cm_genl_family, flags,
357 CM_CMD_GET_TUPLE);
358 else
359 hdr = genlmsg_put(msg, portid, seq, &fp_cm_genl_family, flags,
360 CM_CMD_DEL_TUPLE);
361 if (!hdr)
362 return -EMSGSIZE;
363
364 if (tuple->src.l3num == AF_INET) {
365 if (nla_put_u32(msg, CM_ATTR_SRC_IP, tuple->src.u3.ip) ||
366 nla_put_u32(msg, CM_ATTR_DST_IP, tuple->dst.u3.ip))
367 goto nla_put_failure;
368 }
369
370 if (tuple->dst.protonum == IPPROTO_UDP)
371 proto = TOE_UDP;
372 else if (tuple->dst.protonum == IPPROTO_TCP)
373 proto = TOE_TCP;
374 else
375 proto = TOE_MAX;
376
377 if (nla_put_u16(msg, CM_ATTR_SRC_PORT, ntohs(tuple->src.u.all)) ||
378 nla_put_u16(msg, CM_ATTR_DST_PORT, ntohs(tuple->dst.u.all)) ||
379 nla_put_u8(msg, CM_ATTR_PROTO, proto))
380 goto nla_put_failure;
381
382 src = rcu_dereference_bh(el->in_dev);
383 dst = rcu_dereference_bh(el->out_dev);
384
385 if (is_vlan_dev(src->dev)) {
386 vlan = vlan_dev_priv(src->dev);
387 src_dev = vlan->real_dev;
388 nla_put_u8(msg, CM_ATTR_VLAN_EN, 1);
389 nla_put_u16(msg, CM_ATTR_VLANID, vlan->vlan_id);
390 } else
391 src_dev = src->dev;
392
393 if (is_nat46_dev(src_dev) && is_valid_nat46_instance(src_dev)) {
394 //RX:
395 in_pkt = PDU_PKT;
396 dev_priv = netdev_priv(src_dev);
397 nat46 = dev_priv->nat46;
398 pr_debug("%s:\nDL xlat enable\n, src:%pI6c, dst:%pI6c\n", __func__, nat46->pairs[0].remote.v6_pref.s6_addr32,
399 nat46->pairs[0].local.v6_pref.s6_addr32);
400
401 if (nla_put_u32(msg, CM_ATTR_XLAT_EN, 1) ||
402 nla_put(msg, CM_ATTR_SRC_IP6, sizeof(struct in6_addr), &nat46->pairs[0].remote.v6_pref) ||
403 nla_put(msg, CM_ATTR_DST_IP6, sizeof(struct in6_addr), &nat46->pairs[0].local.v6_pref))
404 goto nla_put_failure;
405 } else if (!strncasecmp(src_dev->name, "ccinet", 6))
406 in_pkt = PDU_PKT;
407 else if (!strncasecmp(src_dev->name, "usbnet", 6))
408 in_pkt = USB_PKT;
409 else if (!strncasecmp(src_dev->name, "wlan", 4))
410 in_pkt = WIFI_PKT;
411 else if (!strncasecmp(src_dev->name, "eth", 3))
412 in_pkt = ETH_PKT;
413 else
414 in_pkt = AP_PKT;
415
416 if (is_vlan_dev(dst->dev)) {
417 vlan = vlan_dev_priv(dst->dev);
418 dst_dev = vlan->real_dev;
419 nla_put_u8(msg, CM_ATTR_VLAN_EN, 1);
420 nla_put_u16(msg, CM_ATTR_VLANID, vlan->vlan_id);
421 } else
422 dst_dev = dst->dev;
423
424 if (is_nat46_dev(dst_dev) && is_valid_nat46_instance(dst_dev)) {
425 //TX
426 out_pkt = PDU_PKT;
427 dev_priv = netdev_priv(dst_dev);
428 nat46 = dev_priv->nat46;
429 pr_debug("%s:\nUL xlat enable\n, xlat instance: %s, src:%pI6c, dst:%pI6c\n", __func__, dst_dev->name,
430 nat46->pairs[0].local.v6_pref.s6_addr32, nat46->pairs[0].remote.v6_pref.s6_addr32);
431
432 if (nla_put_u32(msg, CM_ATTR_XLAT_EN, 1) ||
433 nla_put_string(msg, CM_ATTR_XLAT_INSTANCE, dst_dev->name) ||
434 nla_put(msg, CM_ATTR_SRC_IP6, sizeof(struct in6_addr), &nat46->pairs[0].local.v6_pref) ||
435 nla_put(msg, CM_ATTR_DST_IP6, sizeof(struct in6_addr), &nat46->pairs[0].remote.v6_pref))
436 goto nla_put_failure;
437 } else if (!strncasecmp(dst_dev->name, "ccinet", 6))
438 out_pkt = PDU_PKT;
439 else if (!strncasecmp(dst_dev->name, "usbnet", 6))
440 out_pkt = USB_PKT;
441 else if (!strncasecmp(dst_dev->name, "wlan", 4))
442 out_pkt = WIFI_PKT;
443 else if (!strncasecmp(dst_dev->name, "eth", 3))
444 out_pkt = ETH_PKT;
445 else
446 out_pkt = AP_PKT;
447
448 fwd = (in_pkt != AP_PKT) && (out_pkt != AP_PKT);
449 if (fwd && (tuple->src.l3num == AF_INET)) {
450 if (in_pkt == PDU_PKT && (out_pkt == USB_PKT || out_pkt == WIFI_PKT || out_pkt == ETH_PKT)) {
451 nat = 1;
452 nat_ip = el->out_tuple.src.u3.ip;
453 nat_port = ntohs(el->out_tuple.src.u.all);
454 } else if ((in_pkt == USB_PKT || in_pkt == WIFI_PKT || in_pkt == ETH_PKT) && out_pkt == PDU_PKT) {
455 nat = 1;
456 nat_ip = el->out_tuple.dst.u3.ip;
457 nat_port = ntohs(el->out_tuple.dst.u.all);
458 } else
459 /* not support*/
460 goto nla_put_failure;
461 }
462
463 if (nla_put_u8(msg, CM_ATTR_IN_PKT, in_pkt) ||
464 nla_put_u8(msg, CM_ATTR_OUT_PKT, out_pkt) ||
465 nla_put_u8(msg, CM_ATTR_FWD, fwd) ||
466 nla_put_string(msg, CM_ATTR_DEVICE_NAME, dst_dev->name))
467 goto nla_put_failure;
468
469 if (tuple->src.l3num == AF_INET) {
470 if (nla_put_u8(msg, CM_ATTR_SNAT, nat) ||
471 nla_put_u16(msg, CM_ATTR_NAT_PORT, nat_port) ||
472 nla_put_u32(msg, CM_ATTR_NAT_IP, nat_ip))
473 goto nla_put_failure;
474 }
475
476 if (hh_len) {
477 if (likely(hh_len <= HH_DATA_MOD)) {
478 /* this is inlined by gcc */
479 char mac_header[HH_DATA_MOD];
480 memcpy(mac_header, hh->hh_data, HH_DATA_MOD);
481 memcpy(src_mac, &mac_header[HH_DATA_MOD-ETH_TYPE_LEN-ETH_ALEN], ETH_ALEN);
482 memcpy(dst_mac, &mac_header[HH_DATA_MOD-ETH_TYPE_LEN-ETH_ALEN*2], ETH_ALEN);
483 } else {
484 int hh_alen = HH_DATA_ALIGN(hh_len);
485 char *mac_header = kmalloc(hh_alen, GFP_ATOMIC);
486
487 memcpy(mac_header, hh->hh_data, hh_alen);
488 memcpy(src_mac, mac_header+(hh_alen-ETH_TYPE_LEN-ETH_ALEN), ETH_ALEN);
489 memcpy(dst_mac, mac_header+(hh_alen-ETH_TYPE_LEN-ETH_ALEN*2), ETH_ALEN);
490 kfree(mac_header);
491 }
492 }
493
494 if (nla_put(msg, CM_ATTR_SRC_MAC, ETH_ALEN, src_mac) ||
495 nla_put(msg, CM_ATTR_DST_MAC, ETH_ALEN, dst_mac))
496 goto nla_put_failure;
497
498 pr_debug("%s:\n in:%d, out:%d\n src_ip:0x%x\n dst_ip:0x%x\n src_port:%d\n dst_prot:%d\n"
499 " protocol:%d\n nat_port:%d\n nat_ip:0x%x\n fwd:%d\n snat:%d\n\n",
500 __func__, in_pkt, out_pkt, ntohl(tuple->src.u3.ip), ntohl(tuple->dst.u3.ip), ntohs(tuple->src.u.all),
501 ntohs(tuple->dst.u.all), proto, nat_port, ntohl(nat_ip), fwd, nat);
502
503 genlmsg_end(msg, hdr);
504 el->nl_flag = 1;
505
506 return 0;
507
508nla_put_failure:
509 genlmsg_cancel(msg, hdr);
510 return -EMSGSIZE;
511}
512
513static int fp_cm_genl_fill_tuple_info(struct sk_buff *msg, struct nf_conntrack_tuple *tuple,
514 struct fpdb_entry *el, u32 portid, int add)
515{
516 struct fp_net_device *dst, *src;
517
518 if (unlikely(!tuple) || unlikely(!el))
519 return -EMSGSIZE;
520
521 src = rcu_dereference_bh(el->in_dev);
522 dst = rcu_dereference_bh(el->out_dev);
523 if (!src || !dst)
524 return -EMSGSIZE;
525
526 if (is_nat46_dev(src->dev) || is_nat46_dev(dst->dev)) {
527 return __fp_cm_genl_fill_464xlat_info(msg, tuple, el, portid, 0, 0, add);
528 } else
529 return __fp_cm_genl_fill_tuple_info(msg, tuple, el, portid, 0, 0, add);
530}
531
532static int fp_cm_genl_fill_tuple_info_for_test(struct sk_buff *msg, u32 portid, u32 seq,
533 int flags, int add)
534{
535 void *hdr;
536 struct in6_addr addr;
537 char mac[ETH_ALEN] = {0x0, 0x2, 0x3, 0x4, 0x5, 0x6};
538
539 if (add)
540 hdr = genlmsg_put(msg, portid, seq, &fp_cm_genl_family, flags,
541 CM_CMD_GET_TUPLE);
542 else
543 hdr = genlmsg_put(msg, portid, seq, &fp_cm_genl_family, flags,
544 CM_CMD_DEL_TUPLE);
545 if (!hdr)
546 return -EMSGSIZE;
547
548 memset(&addr.s6_addr, 6, sizeof(struct in6_addr));
549
550 if (nla_put_u32(msg, CM_ATTR_SRC_IP, 0xC0A80101) ||
551 nla_put_u32(msg, CM_ATTR_DST_IP, 0xC0A80102) ||
552 /* nla_put(msg, CM_ATTR_SRC_IP6, sizeof(struct in6_addr), &addr) ||
553 nla_put(msg, CM_ATTR_DST_IP6, sizeof(struct in6_addr), &addr) || */
554 nla_put_u16(msg, CM_ATTR_SRC_PORT, 0x64) ||
555 nla_put_u16(msg, CM_ATTR_DST_PORT, 0xC8) ||
556 nla_put_u8(msg, CM_ATTR_PROTO, TOE_TCP) ||
557 nla_put_u16(msg, CM_ATTR_NAT_PORT, 0x64) ||
558 nla_put_u32(msg, CM_ATTR_NAT_IP, 0xC0A8010A) ||
559 nla_put(msg, CM_ATTR_SRC_MAC, ETH_ALEN, mac) ||
560 nla_put(msg, CM_ATTR_DST_MAC, ETH_ALEN, mac) ||
561 nla_put_string(msg, CM_ATTR_DEVICE_NAME, "ccinet0") ||
562 nla_put_u8(msg, CM_ATTR_IN_PKT, PDU_PKT) ||
563 nla_put_u8(msg, CM_ATTR_OUT_PKT, USB_PKT) ||
564 nla_put_u8(msg, CM_ATTR_FWD, 1) ||
565 nla_put_u8(msg, CM_ATTR_SNAT, 1) ||
566 nla_put_u8(msg, CM_ATTR_VLAN_EN, 1) ||
567 nla_put_u16(msg, CM_ATTR_VLANID, 0x64))
568 goto nla_put_failure;
569
570 genlmsg_end(msg, hdr);
571 return 0;
572
573nla_put_failure:
574 genlmsg_cancel(msg, hdr);
575 return -EMSGSIZE;
576}
577
578static int fp_cm_genl_set_tuple(struct sk_buff *skb, struct genl_info *info)
579{
580 struct toe_tuple_buff toe_tuple, toe_tuple_tmp;
581 char dev_name[DEVICE_NAME_MAXSIZE] = {0};
582 char src_mac[ETH_ALEN]={0}, dst_mac[ETH_ALEN]={0};
583 char xlat_instance[16] = {0};
584 struct in6_addr *src_ip6 = NULL;
585 struct in6_addr *dst_ip6 = NULL;
586 u32 src_ip, dst_ip, nat_ip, xlat_en = 0;
587 u16 src_port, dst_port, nat_port, vlanid;
588 u8 rx_tx, prot, fwd, nat, in_pkt, out_pkt, pdu, qfi, rbid, mcid, vlan_en;
589 u8 update = 0;
590
591 if (!info->attrs[CM_ATTR_MCID] ||
592 !info->attrs[CM_ATTR_RBID] ||
593 !info->attrs[CM_ATTR_QFI] ||
594 !info->attrs[CM_ATTR_PDU])
595 return -EINVAL;
596
597 memset(&toe_tuple, 0, sizeof(struct toe_tuple_buff));
598 memset(&toe_tuple_tmp, 0, sizeof(struct toe_tuple_buff));
599
600 if (info->attrs[CM_ATTR_SRC_IP])
601 src_ip = nla_get_u32(info->attrs[CM_ATTR_SRC_IP]);
602
603 if (info->attrs[CM_ATTR_DST_IP])
604 dst_ip = nla_get_u32(info->attrs[CM_ATTR_DST_IP]);
605
606 if (info->attrs[CM_ATTR_SRC_IP6]) {
607 src_ip6 = nla_data(info->attrs[CM_ATTR_SRC_IP6]);
608 pr_debug("%s, src_ip6=%pI6c\n", __func__, src_ip6->s6_addr32);
609 }
610
611 if (info->attrs[CM_ATTR_DST_IP6]) {
612 dst_ip6 = nla_data(info->attrs[CM_ATTR_DST_IP6]);
613 pr_debug("%s, dst_ip6=%pI6c\n", __func__, dst_ip6->s6_addr32);
614 }
615
616 if (info->attrs[CM_ATTR_SRC_PORT])
617 src_port = nla_get_u16(info->attrs[CM_ATTR_SRC_PORT]);
618
619 if (info->attrs[CM_ATTR_DST_PORT])
620 dst_port = nla_get_u16(info->attrs[CM_ATTR_DST_PORT]);
621
622 if (info->attrs[CM_ATTR_PROTO])
623 prot = nla_get_u8(info->attrs[CM_ATTR_PROTO]);
624
625 if (info->attrs[CM_ATTR_SRC_MAC]) {
626 memcpy(src_mac, nla_data(info->attrs[CM_ATTR_SRC_MAC]), ETH_ALEN);
627 pr_debug("%s, src_mac: %02x%02x-%02x%02x-%02x%02x\n", __func__,
628 src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]);
629 }
630 if (info->attrs[CM_ATTR_DST_MAC]) {
631 memcpy(dst_mac, nla_data(info->attrs[CM_ATTR_DST_MAC]), ETH_ALEN);
632 pr_debug("%s, dst_mac: %02x%02x-%02x%02x-%02x%02x\n", __func__,
633 dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5]);
634 }
635
636 if (info->attrs[CM_ATTR_SNAT])
637 nat = nla_get_u8(info->attrs[CM_ATTR_SNAT]);
638
639 if (info->attrs[CM_ATTR_FWD])
640 fwd = nla_get_u8(info->attrs[CM_ATTR_FWD]);
641
642 if (info->attrs[CM_ATTR_NAT_PORT])
643 nat_port = nla_get_u16(info->attrs[CM_ATTR_NAT_PORT]);
644
645 if (info->attrs[CM_ATTR_NAT_IP])
646 nat_ip = nla_get_u32(info->attrs[CM_ATTR_NAT_IP]);
647
648 if (info->attrs[CM_ATTR_DEVICE_NAME]) {
649 /*nla_len = strlen(dev_name) + 1 + NLA_HDRLEN;*/
650 memcpy(dev_name, (char *)nla_data(info->attrs[CM_ATTR_DEVICE_NAME]),
651 info->attrs[CM_ATTR_DEVICE_NAME]->nla_len - NLA_HDRLEN -1);
652 pr_debug("%s, dev_name: %s\n", __func__, dev_name);
653 }
654
655 if (info->attrs[CM_ATTR_MCID])
656 mcid = nla_get_u8(info->attrs[CM_ATTR_MCID]);
657
658 if (info->attrs[CM_ATTR_RBID])
659 rbid = nla_get_u8(info->attrs[CM_ATTR_RBID]);
660
661 if (info->attrs[CM_ATTR_QFI])
662 qfi = nla_get_u8(info->attrs[CM_ATTR_QFI]);
663
664 if (info->attrs[CM_ATTR_PDU])
665 pdu = nla_get_u8(info->attrs[CM_ATTR_PDU]);
666
667 if (info->attrs[CM_ATTR_IN_PKT])
668 in_pkt = nla_get_u8(info->attrs[CM_ATTR_IN_PKT]);
669
670 if (info->attrs[CM_ATTR_OUT_PKT])
671 out_pkt = nla_get_u8(info->attrs[CM_ATTR_OUT_PKT]);
672
673 if (info->attrs[CM_ATTR_VLAN_EN])
674 vlan_en = nla_get_u8(info->attrs[CM_ATTR_VLAN_EN]);
675
676 if (info->attrs[CM_ATTR_VLANID])
677 vlanid = nla_get_u16(info->attrs[CM_ATTR_VLANID]);
678
679 if (info->attrs[CM_ATTR_XLAT_EN])
680 xlat_en = nla_get_u32(info->attrs[CM_ATTR_XLAT_EN]);
681
682 if (info->attrs[CM_ATTR_XLAT_INSTANCE]) {
683 memcpy(xlat_instance, (char *)nla_data(info->attrs[CM_ATTR_XLAT_INSTANCE]),
684 info->attrs[CM_ATTR_XLAT_INSTANCE]->nla_len - NLA_HDRLEN -1);
685 pr_debug("%s, xlat_instance: %s\n", __func__, xlat_instance);
686 }
687
688 if (info->attrs[CM_ATTR_UPDATE_TUPLE])
689 update = nla_get_u8(info->attrs[CM_ATTR_UPDATE_TUPLE]);
690
691 /* rx: cp -> ap, usb, wifi */
692 if (in_pkt == PDU_PKT)
693 rx_tx = 1;
694 /* rx: ap -> usb, ap -> wifi */
695 else if ((in_pkt == AP_PKT) && (out_pkt != PDU_PKT))
696 rx_tx = 1;
697 /*
698 * tx:
699 * ap -> cp
700 * usb/wifi -> ap/cp */
701 else
702 rx_tx = 0;
703
704 if (src_ip6 && dst_ip6 && !xlat_en) {
705 memcpy(toe_tuple.src_ip6, src_ip6->s6_addr32, sizeof(toe_tuple.src_ip6));
706 memcpy(toe_tuple.dst_ip6, dst_ip6->s6_addr32, sizeof(toe_tuple.src_ip6));
707 toe_tuple.ip6 = 1;
708 } else {
709 toe_tuple.src_ip = ntohl(src_ip);
710 toe_tuple.dst_ip = ntohl(dst_ip);
711 toe_tuple.ip6 = 0;
712 toe_tuple.nat = nat;
713 toe_tuple.nat_port = nat_port;
714 toe_tuple.nat_ip = ntohl(nat_ip);
715 }
716
717 if (vlan_en) {
718 toe_tuple.vlan_en = vlan_en;
719 toe_tuple.vlanid = vlanid;
720 }
721
722 toe_tuple.src_port = src_port;
723 toe_tuple.dst_port = dst_port;
724 toe_tuple.prot = prot;
725 toe_tuple.urg = 0;
726 toe_tuple.fwd = fwd;
727 toe_tuple.crc = 1;
728 toe_tuple.rxtx = rx_tx;
729 toe_tuple.out_pkt = out_pkt;
730 toe_tuple.pdu = pdu;
731 toe_tuple.qfi = qfi ;
732 toe_tuple.rbid = rbid ;
733 toe_tuple.mcid = mcid;
734 toe_tuple.xlat_en = xlat_en;
735 toe_tuple.in_pkt = in_pkt;
736 memcpy(toe_tuple.smac, src_mac, sizeof(toe_tuple.smac));
737 memcpy(toe_tuple.dmac, dst_mac, sizeof(toe_tuple.dmac));
738 memcpy(toe_tuple.xlat_instance, xlat_instance, sizeof(xlat_instance));
739
740 pr_debug("%s:\n in:%d, out:%d, src_port:%d, dst_prot:%d,"
741 " protocol:%d, nat_port:%d, nat_ip:0x%x,fwd:%d,snat:%d, xlat instance:%s\n\n",
742 __func__, in_pkt, out_pkt, src_port, dst_port, prot,
743 nat_port, nat_ip, fwd, nat, xlat_instance);
744
745 if (update) {
746 memcpy(&toe_tuple_tmp, &toe_tuple, sizeof(struct toe_tuple_buff));
747 toe_del_connection(&toe_tuple_tmp);
748 }
749 toe_add_connection(&toe_tuple);
750
751 return 0;
752}
753
754static int fp_cm_genl_get_tuple(struct sk_buff *skb, struct genl_info *info)
755{
756 struct sk_buff *msg;
757 int rc;
758
759 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
760 if (!msg)
761 return -ENOMEM;
762
763 rc = fp_cm_genl_fill_tuple_info_for_test(msg, info->snd_portid, info->snd_seq, 0, 1);
764 if (rc < 0)
765 goto out_free;
766
767 return genlmsg_reply(msg, info);
768
769out_free:
770 nlmsg_free(msg);
771 return rc;
772}
773
774static int fp_cm_genl_del_tuple(struct sk_buff *skb, struct genl_info *info)
775{
776 struct sk_buff *msg;
777 int rc;
778
779 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
780 if (!msg)
781 return -ENOMEM;
782
783 rc = fp_cm_genl_fill_tuple_info_for_test(msg, info->snd_portid, info->snd_seq, 0, 0);
784 if (rc < 0)
785 goto out_free;
786
787 return genlmsg_reply(msg, info);
788
789out_free:
790 nlmsg_free(msg);
791 return rc;
792}
793
794static int __fp_eth_wan_set_tuple(struct nf_conntrack_tuple *tuple,
795 struct fpdb_entry *el, int add)
796{
797 struct hh_cache *hh;
798 int hh_len;
799
800 struct fp_net_device *dst, *src;
801 struct net_device *src_dev, *dst_dev;
802 struct toe_tuple_buff toe_tuple_ul; /* eth -> cp */
803 struct toe_tuple_buff toe_tuple_dl; /* cp->usb/wifi/eth */
804 struct vlan_dev_priv *vlan;
805 u8 src_vlan_en = 0, dst_vlan_en = 0;
806 u16 src_vlanid, dst_vlanid;
807
808 hh = &el->hh;
809 hh_len = hh->hh_len;
810
811 src = rcu_dereference_bh(el->in_dev);
812 dst = rcu_dereference_bh(el->out_dev);
813
814 if (is_vlan_dev(src->dev)) {
815 vlan = vlan_dev_priv(src->dev);
816 src_dev = vlan->real_dev;
817 src_vlan_en = 1;
818 src_vlanid = vlan->vlan_id;
819 } else
820 src_dev = src->dev;
821
822 if (is_vlan_dev(dst->dev)) {
823 vlan = vlan_dev_priv(dst->dev);
824 dst_dev = vlan->real_dev;
825 dst_vlan_en = 1;
826 dst_vlanid = vlan->vlan_id;
827 } else
828 dst_dev = dst->dev;
829
830 if (src->br) {
831 /* if src dev is under bridge such as usb/eth(lan)/wifi */
832
833 if (strncasecmp(dst_dev->name, "eth", 3))
834 /* dst dev is not eth */
835 return -1;
836 else {
837 if (!dst->br) {
838 /* usb/eth(lan)/wifi -> eth(wan)
839 * don't add the ul path to toe,
840 * and no need to send tuple to cm.
841 */
842 return 0;
843 } else {
844 /* dst is eth lan */
845 return -1;
846 }
847 }
848 } else {
849 if (strncasecmp(src_dev->name, "eth", 3))
850 /* src dev is not eth */
851 return -1;
852 }
853
854 /* only eth wan as input go here */
855 printk(KERN_DEBUG "%s: %s -> %s\n", __func__,
856 src_dev->name, dst_dev->name);
857
858 memset(&toe_tuple_ul, 0, sizeof(toe_tuple_ul));
859 memset(&toe_tuple_dl, 0, sizeof(toe_tuple_dl));
860 toe_tuple_ul.in_pkt = ETH_PKT;
861 toe_tuple_ul.out_pkt = PDU_PKT;
862 toe_tuple_dl.in_pkt = PDU_PKT;
863
864 if (tuple->dst.protonum == IPPROTO_UDP)
865 toe_tuple_ul.prot = TOE_UDP;
866 else if (tuple->dst.protonum == IPPROTO_TCP)
867 toe_tuple_ul.prot = TOE_TCP;
868 else
869 return 1;
870 toe_tuple_dl.prot = toe_tuple_ul.prot;
871
872 if (!strncasecmp(dst_dev->name, "usbnet", 6))
873 toe_tuple_dl.out_pkt = USB_PKT;
874 else if (!strncasecmp(dst_dev->name, "wlan", 4))
875 toe_tuple_dl.out_pkt = WIFI_PKT;
876 else if (!strncasecmp(dst_dev->name, "eth", 3))
877 toe_tuple_dl.out_pkt = ETH_PKT;
878 else
879 return 2;
880
881 if (tuple->src.l3num == AF_INET) {
882 toe_tuple_ul.src_ip = ntohl(tuple->src.u3.ip);
883 toe_tuple_ul.dst_ip = ntohl(tuple->dst.u3.ip);
884
885 toe_tuple_ul.nat_ip = ntohl(tuple->dst.u3.ip);
886 toe_tuple_ul.nat_port = ntohs(el->out_tuple.dst.u.all);
887 toe_tuple_ul.nat = 0;
888
889 toe_tuple_dl.src_ip = toe_tuple_ul.src_ip;
890 toe_tuple_dl.dst_ip = toe_tuple_ul.dst_ip;
891 toe_tuple_dl.nat_ip = ntohl(el->out_tuple.src.u3.ip);
892 toe_tuple_dl.nat_port = ntohs(el->out_tuple.src.u.all);
893 toe_tuple_dl.nat = 1;
894 } else if (tuple->src.l3num == AF_INET6) {
895 memcpy(toe_tuple_ul.src_ip6,
896 tuple->src.u3.in6.s6_addr32, sizeof(toe_tuple_ul.src_ip6));
897 memcpy(toe_tuple_ul.dst_ip6,
898 tuple->dst.u3.in6.s6_addr32, sizeof(toe_tuple_ul.dst_ip6));
899 toe_tuple_dl.ip6 = toe_tuple_ul.ip6 = 1;
900 }
901
902 toe_tuple_dl.src_port = toe_tuple_ul.src_port = ntohs(tuple->src.u.all);
903 toe_tuple_dl.dst_port = toe_tuple_ul.dst_port = ntohs(tuple->dst.u.all);
904 toe_tuple_dl.crc = toe_tuple_ul.crc = 1;
905 toe_tuple_dl.fwd = toe_tuple_ul.fwd = 1;
906 toe_tuple_ul.rxtx = 0; /* ul is tx */
907 toe_tuple_dl.rxtx = 1; /* dl is rx */
908 toe_tuple_ul.pdu = 0xff;
909 toe_tuple_ul.qfi = 0xff;
910 toe_tuple_ul.rbid = 0xff;
911 toe_tuple_ul.mcid = 0xff;
912
913 if (src_vlan_en) {
914 toe_tuple_ul.vlan_en = 1;
915 toe_tuple_ul.vlanid = src_vlanid;
916 }
917
918 if (dst_vlan_en) {
919 toe_tuple_dl.vlan_en = 1;
920 toe_tuple_dl.vlanid = dst_vlanid;
921 }
922
923 if (hh_len) {
924 if (likely(hh_len <= HH_DATA_MOD)) {
925 /* this is inlined by gcc */
926 char mac_header[HH_DATA_MOD];
927 memcpy(mac_header, hh->hh_data, HH_DATA_MOD);
928 memcpy(toe_tuple_ul.smac,
929 &mac_header[HH_DATA_MOD-ETH_TYPE_LEN-ETH_ALEN], ETH_ALEN);
930 memcpy(toe_tuple_ul.dmac,
931 &mac_header[HH_DATA_MOD-ETH_TYPE_LEN-ETH_ALEN*2], ETH_ALEN);
932 } else {
933 int hh_alen = HH_DATA_ALIGN(hh_len);
934 char *mac_header = kmalloc(hh_alen, GFP_ATOMIC);
935
936 memcpy(mac_header, hh->hh_data, hh_alen);
937 memcpy(toe_tuple_ul.smac,
938 mac_header+(hh_alen-ETH_TYPE_LEN-ETH_ALEN), ETH_ALEN);
939 memcpy(toe_tuple_ul.dmac,
940 mac_header+(hh_alen-ETH_TYPE_LEN-ETH_ALEN*2), ETH_ALEN);
941 kfree(mac_header);
942 }
943
944 memcpy(toe_tuple_dl.smac, toe_tuple_ul.smac, ETH_ALEN);
945 memcpy(toe_tuple_dl.dmac, toe_tuple_ul.dmac, ETH_ALEN);
946 }
947
948 if (add) {
949 if (toe_add_connection(&toe_tuple_ul) >= 0 &&
950 toe_add_connection(&toe_tuple_dl) >= 0) {
951 el->nl_flag = 1;
952 return 0;
953 }
954 } else {
955 toe_del_connection(&toe_tuple_ul);
956 toe_del_connection(&toe_tuple_dl);
957 el->nl_flag = 0;
958 return 0;
959 }
960
961 return -1;
962}
963
964int fp_cm_genl_send_tuple(struct nf_conntrack_tuple *tuple, struct fpdb_entry *el,
965 int add, int len)
966{
967 struct sk_buff *msg;
968 int rc;
969 u32 pid, ms;
970
971 if (add) {
972 if (!el->detect_speed_jiffies)
973 el->detect_speed_jiffies = jiffies;
974 el->detect_speed_bytes += len;
975 ms = jiffies_to_msecs(jiffies - el->detect_speed_jiffies);
976 if (ms >= 1000) {
977 el->speed = (el->detect_speed_bytes / ms) << 3; /* kbps */
978 el->detect_speed_jiffies = 0;
979 el->detect_speed_bytes = 0;
980 }
981
982 if (el->speed < speed_thresh)
983 return 0;
984 }
985
986 rc = __fp_eth_wan_set_tuple(tuple, el, add);
987 if (rc >= 0)
988 return rc;
989
990 pid = fp_cm_get_genl_pid();
991 if (pid == -1)
992 return -1;
993
994 msg = nlmsg_new(FP_CM_NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
995 if (!msg)
996 return -ENOMEM;
997
998 rc = fp_cm_genl_fill_tuple_info(msg, tuple, el, pid, add);
999 if (rc < 0)
1000 goto out_free;
1001
1002 rc = genlmsg_unicast(&init_net, msg, pid);
1003 if (rc) {
1004 pr_err_ratelimited("%s genlmsg_unicast fail, rc: %d", __func__, rc);
1005 el->nl_flag = 0;
1006 }
1007
1008 return rc;
1009out_free:
1010 nlmsg_free(msg);
1011 return rc;
1012}
1013
1014EXPORT_SYMBOL(fp_cm_genl_send_tuple);
1015
1016static ssize_t speed_thresh_show(struct fastpath_module *m, char *buf)
1017{
1018 return sprintf(buf, "speed_thresh: %dKbps\n", speed_thresh);
1019}
1020
1021static ssize_t speed_thresh_store(struct fastpath_module *m, const char *buf,
1022 size_t count)
1023{
1024 sscanf(buf, "%u", &speed_thresh);
1025 return count;
1026}
1027
1028static FP_ATTR(speed_thresh, S_IRUGO|S_IWUSR, speed_thresh_show, speed_thresh_store);
1029
1030static struct attribute *fp_cm_attrs[] = {
1031 &fp_attr_speed_thresh.attr,
1032 NULL, /* need to NULL terminate the list of attributes */
1033};
1034
1035void fp_cm_release(struct kobject *kobj)
1036{
1037 struct fastpath_module *module = to_fpmod(kobj);
1038#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
1039 int i;
1040#endif
1041
1042#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
1043 for (i = ARRAY_SIZE(fp_cm_genl_ops) - 1; i >= 0; i--)
1044 genl_unregister_ops(&fp_cm_genl_family, &fp_cm_genl_ops[i]);
1045#endif
1046 genl_unregister_family(&fp_cm_genl_family);
1047
1048 printk(KERN_ERR "fp_cm gennetlink unregister.....\n");
1049 kfree(module);
1050}
1051
1052static struct kobj_type ktype_fp_cm = {
1053 .sysfs_ops = &fp_sysfs_ops,
1054 .default_attrs = fp_cm_attrs,
1055 .release = fp_cm_release,
1056};
1057
1058static int fp_cm_probe(struct fastpath_module *module)
1059{
1060 int ret;
1061
1062 module->priv = NULL;
1063 snprintf(module->name, sizeof(module->name), "fp_cm");
1064
1065 ret = genl_register_family(&fp_cm_genl_family);
1066
1067 kobject_init(&module->kobj, &ktype_fp_cm);
1068 ret = kobject_add(&module->kobj, module->fastpath->kobj, "%s", module->name);
1069 if (ret < 0) {
1070 pr_err("kobject_add failed (%d)\n", ret);
1071 goto err_kobject_add;
1072 }
1073
1074 kobject_uevent(&module->kobj, KOBJ_ADD);
1075
1076 pr_debug("fp_cm probed\n");
1077 pr_info("fp_cm gennetlink register success!!!\n");
1078
1079 return 0;
1080
1081err_kobject_add:
1082 kobject_put(&module->kobj);
1083 genl_unregister_family(&fp_cm_genl_family);
1084
1085 return ret;
1086}
1087
1088static int fp_cm_remove(struct fastpath_module *module)
1089{
1090 kobject_put(&module->kobj);
1091
1092 printk(KERN_ERR "fp_cm removed\n");
1093 return 0;
1094}
1095
1096struct fastpath_module_ops fp_cm_ops = {
1097 .probe = fp_cm_probe,
1098 .remove = fp_cm_remove,
1099};
1100