1
2
3
4
5
6
7
8
9
10
11
12
13
14#if defined(CONFIG_SMP) && ! defined(__SMP__)
15#define __SMP__
16#endif
17
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <asm/unistd.h>
21
22#include <linux/sched.h>
23#include <linux/wait.h>
24
25#include <linux/netdevice.h>
26#include <linux/kernel_stat.h>
27#include <linux/pci.h>
28#include <linux/rtnetlink.h>
29#include <linux/ethtool.h>
30
31#include <net/net_namespace.h>
32
33#include "bplibk.h"
34
35#define MOD_NAME "bypass"
36
37#define VERSION "\n"MOD_NAME" version 9.0.4\n"
38
39MODULE_AUTHOR("www.silicom.co.il");
40
41MODULE_LICENSE("GPL");
42
43int init_lib_module(void);
44void cleanup_lib_module(void);
45
46static int do_cmd(struct net_device *dev, struct ifreq *ifr, int cmd, int *data)
47{
48 int ret = -1;
49 struct if_bypass *bypass_cb;
50 static int (*ioctl) (struct net_device *, struct ifreq *, int);
51
52 bypass_cb = (struct if_bypass *)ifr;
53 bypass_cb->cmd = cmd;
54 bypass_cb->data = *data;
55 if ((dev->netdev_ops) && (ioctl = dev->netdev_ops->ndo_do_ioctl)) {
56 ret = ioctl(dev, ifr, SIOCGIFBYPASS);
57 *data = bypass_cb->data;
58 }
59
60 return ret;
61}
62
63static int doit(int cmd, int if_index, int *data)
64{
65 struct ifreq ifr;
66 int ret = -1;
67 struct net_device *dev;
68 struct net_device *n;
69 for_each_netdev_safe(&init_net, dev, n) {
70
71 if (dev->ifindex == if_index) {
72 ret = do_cmd(dev, &ifr, cmd, data);
73 if (ret < 0)
74 ret = -1;
75
76 }
77 }
78
79 return ret;
80}
81
82#define bp_symbol_get(fn_name) symbol_get(fn_name)
83#define bp_symbol_put(fn_name) symbol_put(fn_name)
84
85#define SET_BPLIB_INT_FN(fn_name, arg_type, arg, ret) \
86 ({ int (* fn_ex)(arg_type)=NULL; \
87 fn_ex=bp_symbol_get(fn_name##_sd); \
88 if(fn_ex) { \
89 ret= fn_ex(arg); \
90 bp_symbol_put(fn_name##_sd); \
91 } else ret=-1; \
92 })
93
94#define SET_BPLIB_INT_FN2(fn_name, arg_type, arg, arg_type1, arg1, ret) \
95 ({ int (* fn_ex)(arg_type,arg_type1)=NULL; \
96 fn_ex=bp_symbol_get(fn_name##_sd); \
97 if(fn_ex) { \
98 ret= fn_ex(arg,arg1); \
99 bp_symbol_put(fn_name##_sd); \
100 } else ret=-1; \
101 })
102#define SET_BPLIB_INT_FN3(fn_name, arg_type, arg, arg_type1, arg1,arg_type2, arg2, ret) \
103 ({ int (* fn_ex)(arg_type,arg_type1, arg_type2)=NULL; \
104 fn_ex=bp_symbol_get(fn_name##_sd); \
105 if(fn_ex) { \
106 ret= fn_ex(arg,arg1,arg2); \
107 bp_symbol_put(fn_name##_sd); \
108 } else ret=-1; \
109 })
110
111#define DO_BPLIB_GET_ARG_FN(fn_name,ioctl_val, if_index) \
112 ({ int data, ret=0; \
113 if(is_dev_sd(if_index)){ \
114 SET_BPLIB_INT_FN(fn_name, int, if_index, ret); \
115 return ret; \
116 } \
117 return doit(ioctl_val,if_index, &data); \
118 })
119
120#define DO_BPLIB_SET_ARG_FN(fn_name,ioctl_val,if_index,arg) \
121 ({ int data, ret=0; \
122 if(is_dev_sd(if_index)){ \
123 SET_BPLIB_INT_FN2(fn_name, int, if_index, int, arg, ret); \
124 return ret; \
125 } \
126 data=arg; \
127 return doit(ioctl_val,if_index, &data); \
128 })
129
130static int is_dev_sd(int if_index)
131{
132 int ret = 0;
133 SET_BPLIB_INT_FN(is_bypass, int, if_index, ret);
134 return (ret >= 0 ? 1 : 0);
135}
136
137static int is_bypass_dev(int if_index)
138{
139 struct pci_dev *pdev = NULL;
140 struct net_device *dev = NULL;
141 struct ifreq ifr;
142 int ret = 0, data = 0;
143
144 while ((pdev = pci_get_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) {
145 if ((dev = pci_get_drvdata(pdev)) != NULL)
146 if (((dev = pci_get_drvdata(pdev)) != NULL) &&
147 (dev->ifindex == if_index)) {
148 if ((pdev->vendor == SILICOM_VID) &&
149 (pdev->device >= SILICOM_BP_PID_MIN) &&
150 (pdev->device <= SILICOM_BP_PID_MAX))
151 goto send_cmd;
152#if defined(BP_VENDOR_SUPPORT) && defined(ETHTOOL_GDRVINFO)
153 else {
154 struct ethtool_drvinfo info;
155 const struct ethtool_ops *ops =
156 dev->ethtool_ops;
157 int k = 0;
158
159 if (ops->get_drvinfo) {
160 memset(&info, 0, sizeof(info));
161 info.cmd = ETHTOOL_GDRVINFO;
162 ops->get_drvinfo(dev, &info);
163 for (; bp_desc_array[k]; k++)
164 if (!
165 (strcmp
166 (bp_desc_array[k],
167 info.driver)))
168 goto send_cmd;
169
170 }
171
172 }
173#endif
174 return -1;
175 }
176 }
177 send_cmd:
178 ret = do_cmd(dev, &ifr, IS_BYPASS, &data);
179 return (ret < 0 ? -1 : ret);
180}
181
182static int is_bypass(int if_index)
183{
184 int ret = 0;
185 SET_BPLIB_INT_FN(is_bypass, int, if_index, ret);
186
187 if (ret < 0)
188 return is_bypass_dev(if_index);
189 return ret;
190}
191
192static int get_bypass_slave(int if_index)
193{
194 DO_BPLIB_GET_ARG_FN(get_bypass_slave, GET_BYPASS_SLAVE, if_index);
195}
196
197static int get_bypass_caps(int if_index)
198{
199 DO_BPLIB_GET_ARG_FN(get_bypass_caps, GET_BYPASS_CAPS, if_index);
200}
201
202static int get_wd_set_caps(int if_index)
203{
204 DO_BPLIB_GET_ARG_FN(get_wd_set_caps, GET_WD_SET_CAPS, if_index);
205}
206
207static int set_bypass(int if_index, int bypass_mode)
208{
209 DO_BPLIB_SET_ARG_FN(set_bypass, SET_BYPASS, if_index, bypass_mode);
210}
211
212static int get_bypass(int if_index)
213{
214 DO_BPLIB_GET_ARG_FN(get_bypass, GET_BYPASS, if_index);
215}
216
217static int get_bypass_change(int if_index)
218{
219 DO_BPLIB_GET_ARG_FN(get_bypass_change, GET_BYPASS_CHANGE, if_index);
220}
221
222static int set_dis_bypass(int if_index, int dis_bypass)
223{
224 DO_BPLIB_SET_ARG_FN(set_dis_bypass, SET_DIS_BYPASS, if_index,
225 dis_bypass);
226}
227
228static int get_dis_bypass(int if_index)
229{
230 DO_BPLIB_GET_ARG_FN(get_dis_bypass, GET_DIS_BYPASS, if_index);
231}
232
233static int set_bypass_pwoff(int if_index, int bypass_mode)
234{
235 DO_BPLIB_SET_ARG_FN(set_bypass_pwoff, SET_BYPASS_PWOFF, if_index,
236 bypass_mode);
237}
238
239static int get_bypass_pwoff(int if_index)
240{
241 DO_BPLIB_GET_ARG_FN(get_bypass_pwoff, GET_BYPASS_PWOFF, if_index);
242}
243
244static int set_bypass_pwup(int if_index, int bypass_mode)
245{
246 DO_BPLIB_SET_ARG_FN(set_bypass_pwup, SET_BYPASS_PWUP, if_index,
247 bypass_mode);
248}
249
250static int get_bypass_pwup(int if_index)
251{
252 DO_BPLIB_GET_ARG_FN(get_bypass_pwup, GET_BYPASS_PWUP, if_index);
253}
254
255static int set_bypass_wd(int if_index, int ms_timeout, int *ms_timeout_set)
256{
257 int data = ms_timeout, ret = 0;
258 if (is_dev_sd(if_index))
259 SET_BPLIB_INT_FN3(set_bypass_wd, int, if_index, int, ms_timeout,
260 int *, ms_timeout_set, ret);
261 else {
262 ret = doit(SET_BYPASS_WD, if_index, &data);
263 if (ret > 0) {
264 *ms_timeout_set = ret;
265 ret = 0;
266 }
267 }
268 return ret;
269}
270
271static int get_bypass_wd(int if_index, int *ms_timeout_set)
272{
273 int *data = ms_timeout_set, ret = 0;
274 if (is_dev_sd(if_index))
275 SET_BPLIB_INT_FN2(get_bypass_wd, int, if_index, int *,
276 ms_timeout_set, ret);
277 else
278 ret = doit(GET_BYPASS_WD, if_index, data);
279 return ret;
280}
281
282static int get_wd_expire_time(int if_index, int *ms_time_left)
283{
284 int *data = ms_time_left, ret = 0;
285 if (is_dev_sd(if_index))
286 SET_BPLIB_INT_FN2(get_wd_expire_time, int, if_index, int *,
287 ms_time_left, ret);
288 else {
289 ret = doit(GET_WD_EXPIRE_TIME, if_index, data);
290 if ((ret == 0) && (*data != 0))
291 ret = 1;
292 }
293 return ret;
294}
295
296static int reset_bypass_wd_timer(int if_index)
297{
298 DO_BPLIB_GET_ARG_FN(reset_bypass_wd_timer, RESET_BYPASS_WD_TIMER,
299 if_index);
300}
301
302static int set_std_nic(int if_index, int bypass_mode)
303{
304 DO_BPLIB_SET_ARG_FN(set_std_nic, SET_STD_NIC, if_index, bypass_mode);
305}
306
307static int get_std_nic(int if_index)
308{
309 DO_BPLIB_GET_ARG_FN(get_std_nic, GET_STD_NIC, if_index);
310}
311
312static int set_tx(int if_index, int tx_state)
313{
314 DO_BPLIB_SET_ARG_FN(set_tx, SET_TX, if_index, tx_state);
315}
316
317static int get_tx(int if_index)
318{
319 DO_BPLIB_GET_ARG_FN(get_tx, GET_TX, if_index);
320}
321
322static int set_tap(int if_index, int tap_mode)
323{
324 DO_BPLIB_SET_ARG_FN(set_tap, SET_TAP, if_index, tap_mode);
325}
326
327static int get_tap(int if_index)
328{
329 DO_BPLIB_GET_ARG_FN(get_tap, GET_TAP, if_index);
330}
331
332static int get_tap_change(int if_index)
333{
334 DO_BPLIB_GET_ARG_FN(get_tap_change, GET_TAP_CHANGE, if_index);
335}
336
337static int set_dis_tap(int if_index, int dis_tap)
338{
339 DO_BPLIB_SET_ARG_FN(set_dis_tap, SET_DIS_TAP, if_index, dis_tap);
340}
341
342static int get_dis_tap(int if_index)
343{
344 DO_BPLIB_GET_ARG_FN(get_dis_tap, GET_DIS_TAP, if_index);
345}
346
347static int set_tap_pwup(int if_index, int tap_mode)
348{
349 DO_BPLIB_SET_ARG_FN(set_tap_pwup, SET_TAP_PWUP, if_index, tap_mode);
350}
351
352static int get_tap_pwup(int if_index)
353{
354 DO_BPLIB_GET_ARG_FN(get_tap_pwup, GET_TAP_PWUP, if_index);
355}
356
357static int set_bp_disc(int if_index, int disc_mode)
358{
359 DO_BPLIB_SET_ARG_FN(set_bp_disc, SET_DISC, if_index, disc_mode);
360}
361
362static int get_bp_disc(int if_index)
363{
364 DO_BPLIB_GET_ARG_FN(get_bp_disc, GET_DISC, if_index);
365}
366
367static int get_bp_disc_change(int if_index)
368{
369 DO_BPLIB_GET_ARG_FN(get_bp_disc_change, GET_DISC_CHANGE, if_index);
370}
371
372static int set_bp_dis_disc(int if_index, int dis_disc)
373{
374 DO_BPLIB_SET_ARG_FN(set_bp_dis_disc, SET_DIS_DISC, if_index, dis_disc);
375}
376
377static int get_bp_dis_disc(int if_index)
378{
379 DO_BPLIB_GET_ARG_FN(get_bp_dis_disc, GET_DIS_DISC, if_index);
380}
381
382static int set_bp_disc_pwup(int if_index, int disc_mode)
383{
384 DO_BPLIB_SET_ARG_FN(set_bp_disc_pwup, SET_DISC_PWUP, if_index,
385 disc_mode);
386}
387
388static int get_bp_disc_pwup(int if_index)
389{
390 DO_BPLIB_GET_ARG_FN(get_bp_disc_pwup, GET_DISC_PWUP, if_index);
391}
392
393static int set_wd_exp_mode(int if_index, int mode)
394{
395 DO_BPLIB_SET_ARG_FN(set_wd_exp_mode, SET_WD_EXP_MODE, if_index, mode);
396}
397
398static int get_wd_exp_mode(int if_index)
399{
400 DO_BPLIB_GET_ARG_FN(get_wd_exp_mode, GET_WD_EXP_MODE, if_index);
401}
402
403static int set_wd_autoreset(int if_index, int time)
404{
405 DO_BPLIB_SET_ARG_FN(set_wd_autoreset, SET_WD_AUTORESET, if_index, time);
406}
407
408static int get_wd_autoreset(int if_index)
409{
410 DO_BPLIB_GET_ARG_FN(get_wd_autoreset, GET_WD_AUTORESET, if_index);
411}
412
413static int set_tpl(int if_index, int tpl_mode)
414{
415 DO_BPLIB_SET_ARG_FN(set_tpl, SET_TPL, if_index, tpl_mode);
416}
417
418static int get_tpl(int if_index)
419{
420 DO_BPLIB_GET_ARG_FN(get_tpl, GET_TPL, if_index);
421}
422
423static int set_bp_hw_reset(int if_index, int mode)
424{
425 DO_BPLIB_SET_ARG_FN(set_tpl, SET_BP_HW_RESET, if_index, mode);
426}
427
428static int get_bp_hw_reset(int if_index)
429{
430 DO_BPLIB_GET_ARG_FN(get_tpl, GET_BP_HW_RESET, if_index);
431}
432
433static int get_bypass_info(int if_index, struct bp_info *bp_info)
434{
435 int ret = 0;
436 if (is_dev_sd(if_index)) {
437 SET_BPLIB_INT_FN2(get_bypass_info, int, if_index,
438 struct bp_info *, bp_info, ret);
439 } else {
440 static int (*ioctl) (struct net_device *, struct ifreq *, int);
441 struct net_device *dev;
442
443 struct net_device *n;
444 for_each_netdev_safe(&init_net, dev, n) {
445 if (dev->ifindex == if_index) {
446 struct if_bypass_info *bypass_cb;
447 struct ifreq ifr;
448
449 memset(&ifr, 0, sizeof(ifr));
450 bypass_cb = (struct if_bypass_info *)𝔦
451 bypass_cb->cmd = GET_BYPASS_INFO;
452
453 if ((dev->netdev_ops) &&
454 (ioctl = dev->netdev_ops->ndo_do_ioctl)) {
455 ret = ioctl(dev, &ifr, SIOCGIFBYPASS);
456 }
457
458 else
459 ret = -1;
460 if (ret == 0)
461 memcpy(bp_info, &bypass_cb->bp_info,
462 sizeof(struct bp_info));
463 ret = (ret < 0 ? -1 : 0);
464 break;
465 }
466 }
467 }
468 return ret;
469}
470
471int init_lib_module(void)
472{
473
474 printk(VERSION);
475 return 0;
476}
477
478void cleanup_lib_module(void)
479{
480}
481
482EXPORT_SYMBOL_NOVERS(is_bypass);
483EXPORT_SYMBOL_NOVERS(get_bypass_slave);
484EXPORT_SYMBOL_NOVERS(get_bypass_caps);
485EXPORT_SYMBOL_NOVERS(get_wd_set_caps);
486EXPORT_SYMBOL_NOVERS(set_bypass);
487EXPORT_SYMBOL_NOVERS(get_bypass);
488EXPORT_SYMBOL_NOVERS(get_bypass_change);
489EXPORT_SYMBOL_NOVERS(set_dis_bypass);
490EXPORT_SYMBOL_NOVERS(get_dis_bypass);
491EXPORT_SYMBOL_NOVERS(set_bypass_pwoff);
492EXPORT_SYMBOL_NOVERS(get_bypass_pwoff);
493EXPORT_SYMBOL_NOVERS(set_bypass_pwup);
494EXPORT_SYMBOL_NOVERS(get_bypass_pwup);
495EXPORT_SYMBOL_NOVERS(set_bypass_wd);
496EXPORT_SYMBOL_NOVERS(get_bypass_wd);
497EXPORT_SYMBOL_NOVERS(get_wd_expire_time);
498EXPORT_SYMBOL_NOVERS(reset_bypass_wd_timer);
499EXPORT_SYMBOL_NOVERS(set_std_nic);
500EXPORT_SYMBOL_NOVERS(get_std_nic);
501EXPORT_SYMBOL_NOVERS(set_tx);
502EXPORT_SYMBOL_NOVERS(get_tx);
503EXPORT_SYMBOL_NOVERS(set_tap);
504EXPORT_SYMBOL_NOVERS(get_tap);
505EXPORT_SYMBOL_NOVERS(get_tap_change);
506EXPORT_SYMBOL_NOVERS(set_dis_tap);
507EXPORT_SYMBOL_NOVERS(get_dis_tap);
508EXPORT_SYMBOL_NOVERS(set_tap_pwup);
509EXPORT_SYMBOL_NOVERS(get_tap_pwup);
510EXPORT_SYMBOL_NOVERS(set_bp_disc);
511EXPORT_SYMBOL_NOVERS(get_bp_disc);
512EXPORT_SYMBOL_NOVERS(get_bp_disc_change);
513EXPORT_SYMBOL_NOVERS(set_bp_dis_disc);
514EXPORT_SYMBOL_NOVERS(get_bp_dis_disc);
515EXPORT_SYMBOL_NOVERS(set_bp_disc_pwup);
516EXPORT_SYMBOL_NOVERS(get_bp_disc_pwup);
517EXPORT_SYMBOL_NOVERS(set_wd_exp_mode);
518EXPORT_SYMBOL_NOVERS(get_wd_exp_mode);
519EXPORT_SYMBOL_NOVERS(set_wd_autoreset);
520EXPORT_SYMBOL_NOVERS(get_wd_autoreset);
521EXPORT_SYMBOL_NOVERS(set_tpl);
522EXPORT_SYMBOL_NOVERS(get_tpl);
523EXPORT_SYMBOL_NOVERS(set_bp_hw_reset);
524EXPORT_SYMBOL_NOVERS(get_bp_hw_reset);
525EXPORT_SYMBOL_NOVERS(get_bypass_info);
526
527module_init(init_lib_module);
528module_exit(cleanup_lib_module);
529