• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************/
2 /*                                                                            */
3 /* bypass library, Copyright (c) 2004-2007 Silicom, Ltd                       */
4 /*                                                                            */
5 /* This program is free software; you can redistribute it and/or modify       */
6 /* it under the terms of the GNU General Public License as published by       */
7 /* the Free Software Foundation, located in the file LICENSE.                 */
8 /*                                                                            */
9 /*                                                                            */
10 /* bypass.c                                                                    */
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>	// struct device, and other headers
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 
39 MODULE_AUTHOR("www.silicom.co.il");
40 
41 MODULE_LICENSE("GPL");
42 
43 int init_lib_module(void);
44 void cleanup_lib_module(void);
45 
do_cmd(struct net_device * dev,struct ifreq * ifr,int cmd,int * data)46 static 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 
doit(int cmd,int if_index,int * data)63 static 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 
is_dev_sd(int if_index)130 static 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 
is_bypass_dev(int if_index)137 static 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 
is_bypass(int if_index)182 static 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 
get_bypass_slave(int if_index)192 static int get_bypass_slave(int if_index)
193 {
194 	DO_BPLIB_GET_ARG_FN(get_bypass_slave, GET_BYPASS_SLAVE, if_index);
195 }
196 
get_bypass_caps(int if_index)197 static int get_bypass_caps(int if_index)
198 {
199 	DO_BPLIB_GET_ARG_FN(get_bypass_caps, GET_BYPASS_CAPS, if_index);
200 }
201 
get_wd_set_caps(int if_index)202 static 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 
set_bypass(int if_index,int bypass_mode)207 static 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 
get_bypass(int if_index)212 static int get_bypass(int if_index)
213 {
214 	DO_BPLIB_GET_ARG_FN(get_bypass, GET_BYPASS, if_index);
215 }
216 
get_bypass_change(int if_index)217 static int get_bypass_change(int if_index)
218 {
219 	DO_BPLIB_GET_ARG_FN(get_bypass_change, GET_BYPASS_CHANGE, if_index);
220 }
221 
set_dis_bypass(int if_index,int dis_bypass)222 static 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 
get_dis_bypass(int if_index)228 static int get_dis_bypass(int if_index)
229 {
230 	DO_BPLIB_GET_ARG_FN(get_dis_bypass, GET_DIS_BYPASS, if_index);
231 }
232 
set_bypass_pwoff(int if_index,int bypass_mode)233 static 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 
get_bypass_pwoff(int if_index)239 static int get_bypass_pwoff(int if_index)
240 {
241 	DO_BPLIB_GET_ARG_FN(get_bypass_pwoff, GET_BYPASS_PWOFF, if_index);
242 }
243 
set_bypass_pwup(int if_index,int bypass_mode)244 static 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 
get_bypass_pwup(int if_index)250 static int get_bypass_pwup(int if_index)
251 {
252 	DO_BPLIB_GET_ARG_FN(get_bypass_pwup, GET_BYPASS_PWUP, if_index);
253 }
254 
set_bypass_wd(int if_index,int ms_timeout,int * ms_timeout_set)255 static 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 
get_bypass_wd(int if_index,int * ms_timeout_set)271 static 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 
get_wd_expire_time(int if_index,int * ms_time_left)282 static 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 
reset_bypass_wd_timer(int if_index)296 static 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 
set_std_nic(int if_index,int bypass_mode)302 static 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 
get_std_nic(int if_index)307 static int get_std_nic(int if_index)
308 {
309 	DO_BPLIB_GET_ARG_FN(get_std_nic, GET_STD_NIC, if_index);
310 }
311 
set_tx(int if_index,int tx_state)312 static 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 
get_tx(int if_index)317 static int get_tx(int if_index)
318 {
319 	DO_BPLIB_GET_ARG_FN(get_tx, GET_TX, if_index);
320 }
321 
set_tap(int if_index,int tap_mode)322 static 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 
get_tap(int if_index)327 static int get_tap(int if_index)
328 {
329 	DO_BPLIB_GET_ARG_FN(get_tap, GET_TAP, if_index);
330 }
331 
get_tap_change(int if_index)332 static int get_tap_change(int if_index)
333 {
334 	DO_BPLIB_GET_ARG_FN(get_tap_change, GET_TAP_CHANGE, if_index);
335 }
336 
set_dis_tap(int if_index,int dis_tap)337 static 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 
get_dis_tap(int if_index)342 static int get_dis_tap(int if_index)
343 {
344 	DO_BPLIB_GET_ARG_FN(get_dis_tap, GET_DIS_TAP, if_index);
345 }
346 
set_tap_pwup(int if_index,int tap_mode)347 static 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 
get_tap_pwup(int if_index)352 static int get_tap_pwup(int if_index)
353 {
354 	DO_BPLIB_GET_ARG_FN(get_tap_pwup, GET_TAP_PWUP, if_index);
355 }
356 
set_bp_disc(int if_index,int disc_mode)357 static 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 
get_bp_disc(int if_index)362 static int get_bp_disc(int if_index)
363 {
364 	DO_BPLIB_GET_ARG_FN(get_bp_disc, GET_DISC, if_index);
365 }
366 
get_bp_disc_change(int if_index)367 static 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 
set_bp_dis_disc(int if_index,int dis_disc)372 static 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 
get_bp_dis_disc(int if_index)377 static 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 
set_bp_disc_pwup(int if_index,int disc_mode)382 static 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 
get_bp_disc_pwup(int if_index)388 static 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 
set_wd_exp_mode(int if_index,int mode)393 static 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 
get_wd_exp_mode(int if_index)398 static 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 
set_wd_autoreset(int if_index,int time)403 static 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 
get_wd_autoreset(int if_index)408 static int get_wd_autoreset(int if_index)
409 {
410 	DO_BPLIB_GET_ARG_FN(get_wd_autoreset, GET_WD_AUTORESET, if_index);
411 }
412 
set_tpl(int if_index,int tpl_mode)413 static 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 
get_tpl(int if_index)418 static int get_tpl(int if_index)
419 {
420 	DO_BPLIB_GET_ARG_FN(get_tpl, GET_TPL, if_index);
421 }
422 
set_bp_hw_reset(int if_index,int mode)423 static 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 
get_bp_hw_reset(int if_index)428 static 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 
get_bypass_info(int if_index,struct bp_info * bp_info)433 static 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 *)&ifr;
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 
init_lib_module(void)471 int init_lib_module(void)
472 {
473 
474 	printk(VERSION);
475 	return 0;
476 }
477 
cleanup_lib_module(void)478 void cleanup_lib_module(void)
479 {
480 }
481 
482 EXPORT_SYMBOL_NOVERS(is_bypass);
483 EXPORT_SYMBOL_NOVERS(get_bypass_slave);
484 EXPORT_SYMBOL_NOVERS(get_bypass_caps);
485 EXPORT_SYMBOL_NOVERS(get_wd_set_caps);
486 EXPORT_SYMBOL_NOVERS(set_bypass);
487 EXPORT_SYMBOL_NOVERS(get_bypass);
488 EXPORT_SYMBOL_NOVERS(get_bypass_change);
489 EXPORT_SYMBOL_NOVERS(set_dis_bypass);
490 EXPORT_SYMBOL_NOVERS(get_dis_bypass);
491 EXPORT_SYMBOL_NOVERS(set_bypass_pwoff);
492 EXPORT_SYMBOL_NOVERS(get_bypass_pwoff);
493 EXPORT_SYMBOL_NOVERS(set_bypass_pwup);
494 EXPORT_SYMBOL_NOVERS(get_bypass_pwup);
495 EXPORT_SYMBOL_NOVERS(set_bypass_wd);
496 EXPORT_SYMBOL_NOVERS(get_bypass_wd);
497 EXPORT_SYMBOL_NOVERS(get_wd_expire_time);
498 EXPORT_SYMBOL_NOVERS(reset_bypass_wd_timer);
499 EXPORT_SYMBOL_NOVERS(set_std_nic);
500 EXPORT_SYMBOL_NOVERS(get_std_nic);
501 EXPORT_SYMBOL_NOVERS(set_tx);
502 EXPORT_SYMBOL_NOVERS(get_tx);
503 EXPORT_SYMBOL_NOVERS(set_tap);
504 EXPORT_SYMBOL_NOVERS(get_tap);
505 EXPORT_SYMBOL_NOVERS(get_tap_change);
506 EXPORT_SYMBOL_NOVERS(set_dis_tap);
507 EXPORT_SYMBOL_NOVERS(get_dis_tap);
508 EXPORT_SYMBOL_NOVERS(set_tap_pwup);
509 EXPORT_SYMBOL_NOVERS(get_tap_pwup);
510 EXPORT_SYMBOL_NOVERS(set_bp_disc);
511 EXPORT_SYMBOL_NOVERS(get_bp_disc);
512 EXPORT_SYMBOL_NOVERS(get_bp_disc_change);
513 EXPORT_SYMBOL_NOVERS(set_bp_dis_disc);
514 EXPORT_SYMBOL_NOVERS(get_bp_dis_disc);
515 EXPORT_SYMBOL_NOVERS(set_bp_disc_pwup);
516 EXPORT_SYMBOL_NOVERS(get_bp_disc_pwup);
517 EXPORT_SYMBOL_NOVERS(set_wd_exp_mode);
518 EXPORT_SYMBOL_NOVERS(get_wd_exp_mode);
519 EXPORT_SYMBOL_NOVERS(set_wd_autoreset);
520 EXPORT_SYMBOL_NOVERS(get_wd_autoreset);
521 EXPORT_SYMBOL_NOVERS(set_tpl);
522 EXPORT_SYMBOL_NOVERS(get_tpl);
523 EXPORT_SYMBOL_NOVERS(set_bp_hw_reset);
524 EXPORT_SYMBOL_NOVERS(get_bp_hw_reset);
525 EXPORT_SYMBOL_NOVERS(get_bypass_info);
526 
527 module_init(init_lib_module);
528 module_exit(cleanup_lib_module);
529