OpenWrt Forum Archive

Topic: help with ar9331 ethernet driver patch (directly bridging 2 ports)

The content of this topic has been archived on 7 May 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

Hello everyone,

For a certain use case, I need to sometimes directly bridge eth0 and eth1. (not go through Linux bridging, not change packets mac addresses...)
I tried to write a patch to do this, by just sending whatever the ag71xx driver receives on eth0 to eth1, and vice versa.
I added a file /proc/ag71xx_fast_bridge. I write 1 to it to enable.

HOWEVER, the instant any packets are received on either port after enabling the bridging, the device reboots (probably a kernel panic).

I *can not* access serial on my device, because the case is manufactured in such a way that opening it would almost certainly cause it to crack.

Can anyone with ar9331 device and serial access help with this? My patch is below
This is the first time I have ever tried to patch anything in the Linux kernel, so excuse the code quality.
Also I am currently working with 14.07 because that is the firmware it shipped with (manufacturer supported openwrt).

14a15,21
> #include <linux/proc_fs.h>
> #include <linux/uidgid.h>
> 
> 
> #define PROCFS_MAX_SIZE        12
> static char procfs_buffer[PROCFS_MAX_SIZE];
> 
25a33,35
> static unsigned long ag71xx_fast_bridge = 0;
> static unsigned long procfs_buffer_size = 0;
> 
30a41,43
> static struct ag71xx *ag0 = NULL;
> static struct ag71xx *ag1 = NULL;
> 
652c665
<     netif_start_queue(dev);
---
>     if(!ag71xx_fast_bridge) netif_start_queue(dev);
671c684
<     netif_stop_queue(dev);
---
>     if(!ag71xx_fast_bridge) netif_stop_queue(dev);
767c780
<     netdev_sent_queue(dev, skb->len);
---
>     if(!ag71xx_fast_bridge) netdev_sent_queue(dev, skb->len);
781c794
<         netif_stop_queue(dev);
---
>         if(!ag71xx_fast_bridge) netif_stop_queue(dev); // FIXME: wat 2 do?
1006d1018
<             skb->dev = dev;
1008,1009c1020,1031
<             skb->protocol = eth_type_trans(skb, dev);
<             netif_receive_skb(skb);
---
>             if(ag71xx_fast_bridge && (ag == ag0 || ag == ag1)) {
>                 struct ag71xx *dest = ag0;
>                 if(ag == ag0)
>                     dest = ag1;
>                 skb->dev = dest->dev;
>                 skb->protocol = eth_type_trans(skb, skb->dev);
>                 ag71xx_hard_start_xmit(skb, skb->dev);
>             } else {
>                 skb->protocol = eth_type_trans(skb, dev);
>                 skb->dev = dev;
>                 netif_receive_skb(skb);
>             }
1044c1066,1067
<     ag71xx_debugfs_update_napi_stats(ag, rx_done, tx_done);
---
>     if(!ag71xx_fast_bridge)
>         ag71xx_debugfs_update_napi_stats(ag, rx_done, tx_done);
1314a1338,1347
>     
>     if(!ag0) {
>         pr_info("%s: AG71xx set as port 0 for fast bridge\n",
>             dev->name);
>         ag0 = ag;
>     } else if(!ag1) {
>         pr_info("%s: AG71xx set as port 1 for fast bridge\n",
>             dev->name);
>         ag1 = ag;
>     }
1362a1396,1457
> #define procfs_name "ag71xx_fast_bridge"
> 
> static ssize_t procfile_read(struct file*, char*, size_t, loff_t*);
> 
> static ssize_t procfile_read(struct file *file, char *buffer, size_t length, loff_t *offset)  
> {
>     static int finished = 0;
>     int ret = 0;
> 
>     if (finished) {
>         finished = 0;
>         return 0;
>     }   
> 
>     finished = 1;
>     ret = sprintf(buffer, "%lu\n",ag71xx_fast_bridge);
>     return ret;
> }
> 
> /**
>  * This function is called with the /proc file is written
>  *
>  */
> int procfile_write(struct file *file, const char *buffer, unsigned long count,
>            void *data)
> {
>     /* get buffer size */
>     procfs_buffer_size = count;
>     if (procfs_buffer_size > PROCFS_MAX_SIZE ) {
>         procfs_buffer_size = PROCFS_MAX_SIZE;
>     }
>     
>     /* write data to the buffer */
>     if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) {
>         return -EFAULT;
>     }
>     
>     kstrtol(procfs_buffer,10,&ag71xx_fast_bridge);
>     printk(KERN_INFO "ag71xx: fast bridge wrote %lu\n", ag71xx_fast_bridge);
>     
>     BUG_ON(!ag0 || !ag1);
>     
>     netif_stop_queue(ag0->dev);
>     ag71xx_stop(ag0->dev);
>     netif_stop_queue(ag1->dev);
>     ag71xx_stop(ag1->dev);
>     ag71xx_open(ag0->dev);
>     ag71xx_open(ag1->dev);
>     
>     printk(KERN_INFO "ag71xx: devices reset for fast bridge change\n");
> 
>     return procfs_buffer_size;
> }
> 
> struct proc_dir_entry *Our_Proc_File;
> 
> static struct file_operations cmd_file_ops = {  
>     .owner = THIS_MODULE,
>     .read = procfile_read,
>     .write = procfile_write,
> };
> 
1365a1461,1476
>     Our_Proc_File = proc_create(procfs_name, S_IFREG | S_IRUGO, NULL, &cmd_file_ops);
> 
>     if (Our_Proc_File == NULL) {
>         remove_proc_entry(procfs_name, NULL);
> 
>         printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", procfs_name);
>         return -ENOMEM;
>     }
> 
>     /*
>      * KUIDT_INIT is a macro defined in the file 'linux/uidgid.h'. KGIDT_INIT also appears here.
>      */
>     proc_set_user(Our_Proc_File, KUIDT_INIT(0), KGIDT_INIT(0));
>     proc_set_size(Our_Proc_File, 0);
> 
>     printk(KERN_INFO "ag71xx: fast bridge mode created by Ethan Nelson-Moore (parrotgeek1)");
1393a1505
>     remove_proc_entry(procfs_name, NULL);
1401a1514
> MODULE_AUTHOR("Ethan Nelson-Moore <parrotgeek1@gmail.com>");

-> man brctl

You can do this with stock OpenWRT
with changing the kernel.
OpenWRT does this in the most cases with one eth port (the on with the switch) and wifi interfaces.

The discussion might have continued from here.