client模式下对应接口加入桥接出错

client模式下,响应的接口wlan0 加入桥接时出现如下错误:

root@root:~# brctl addif br-lan wlan0
brctl: bridge br-lan: Operation not supported。

查看相应busybox代码(brctl.c),函数为 brctl_main,

  strncpy_IFNAMSIZ(ifr.ifr_name, br);
  if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
     brif = *argv;
     ifr.ifr_ifindex = if_nametoindex(brif);
    if (!ifr.ifr_ifindex) {
      bb_perror_msg_and_die("iface %s", brif);
    }
    ioctl_or_perror_and_die(fd,
         key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,  &ifr, "bridge %s", br);
     goto done_next_argv;
  }

得到addif 和 delif 相应的ioctl命令码为   SIOCBRADDIF  和  SIOCBRDELIF。

内核中对应命令字的定义:
include/linux/sockios.h:#define SIOCBRADDIF     0x89a2         /* add interface to bridge,十进制为35234

查找内核中响应的代码, 此处内核版本为3.10.14。

 * Perform the SIOCxIFxxx calls, inside rtnl_lock()
 */
static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
{
 switch (cmd) {
  /*
  * Unknown or private ioctl
  */
   default:
  if ((cmd >= SIOCDEVPRIVATE &&
      cmd <= SIOCDEVPRIVATE + 15) ||
      cmd == SIOCBONDENSLAVE ||
      cmd == SIOCBONDRELEASE ||
      cmd == SIOCBONDSETHWADDR ||
      cmd == SIOCBONDSLAVEINFOQUERY ||
      cmd == SIOCBONDINFOQUERY ||
      cmd == SIOCBONDCHANGEACTIVE ||
      cmd == SIOCGMIIPHY ||
      cmd == SIOCGMIIREG ||
      cmd == SIOCSMIIREG ||
      cmd == SIOCBRADDIF ||      // 添加桥接接口
      cmd == SIOCBRDELIF ||      // 删除桥接接口
      cmd == SIOCSHWTSTAMP ||
      cmd == SIOCWANDEV) {
         err = -EOPNOTSUPP;
         if (ops->ndo_do_ioctl) {
            if (netif_device_present(dev))
               err = ops->ndo_do_ioctl(dev, ifr, cmd);  // 调用回调函数
            else
               err = -ENODEV;
         }
   } else
     err = -EINVAL;
  }
}

 对应的回调函数位于 /net/bridge/br_device.c中

static const struct net_device_ops br_netdev_ops = {
 .ndo_open     = br_dev_open,
 .ndo_stop     = br_dev_stop,
 .ndo_init    = br_dev_init,
 .ndo_start_xmit    = br_dev_xmit,
 .ndo_get_stats64  = br_get_stats64,
 .ndo_set_mac_address = br_set_mac_address,
 .ndo_set_rx_mode   = br_dev_set_multicast_list,
 .ndo_change_mtu    = br_change_mtu,
 .ndo_do_ioctl    = br_dev_ioctl,    // 此处对应增加(addif)和删除(delif)的回调
#ifdef CONFIG_NET_POLL_CONTROLLER
 .ndo_netpoll_setup   = br_netpoll_setup,
 .ndo_netpoll_cleanup = br_netpoll_cleanup,
 .ndo_poll_controller = br_poll_controller,
#endif
 .ndo_add_slave    = br_add_slave,
 .ndo_del_slave    = br_del_slave,
 .ndo_fix_features       = br_fix_features,
 .ndo_fdb_add    = br_fdb_add,
 .ndo_fdb_del    = br_fdb_delete,
 .ndo_fdb_dump    = br_fdb_dump,
 .ndo_bridge_getlink   = br_getlink,
 .ndo_bridge_setlink   = br_setlink,
 .ndo_bridge_dellink   = br_dellink,
};

 

查看回调函数如下:

int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
 struct net_bridge *br = netdev_priv(dev);
 
 switch(cmd) {

   // 旧式的处理方式
   case SIOCDEVPRIVATE:
      return old_dev_ioctl(dev, rq, cmd);

   // 实现如下:
   case SIOCBRADDIF:
   case SIOCBRDELIF:
      return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);

   }

  br_debug(br, "Bridge does not support ioctl 0x%x\n", cmd);
  return -EOPNOTSUPP;
}

位于 /net/bridge/br_ioctl.c中
static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
{
 struct net *net = dev_net(br->dev);
 struct net_device *dev;
 int ret;

 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
  return -EPERM;

 dev = __dev_get_by_index(net, ifindex);
 if (dev == NULL)
  return -EINVAL;

 if (isadd)
  ret = br_add_if(br, dev);   // 添加桥接接口
 else
  ret = br_del_if(br, dev);   // 删除桥接接口

 return ret;
}

 

位于 /net/bridge/br_if.c中
int br_add_if(struct net_bridge *br, struct net_device *dev)
{
 struct net_bridge_port *p;
 int err = 0;
 bool changed_addr;

 /* Don't allow bridging non-ethernet like devices */
 if ((dev->flags & IFF_LOOPBACK) ||
     dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN ||
     !is_valid_ether_addr(dev->dev_addr))
  return -EINVAL;

 /* No bridging of bridges */
 if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit)
  return -ELOOP;

 /* Device is already being bridged */
 if (br_port_exists(dev))
  return -EBUSY;

 /* No bridging devices that dislike that (e.g. wireless) */
 if (dev->priv_flags & IFF_DONT_BRIDGE)     //  wlan0加入桥接时在此处遇到问题,退出
    return -EOPNOTSUPP;

 p = new_nbp(br, dev);
 if (IS_ERR(p))
  return PTR_ERR(p);

 call_netdevice_notifiers(NETDEV_JOIN, dev);

 err = dev_set_promiscuity(dev, 1);
 if (err)
  goto put_back;

 err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
       SYSFS_BRIDGE_PORT_ATTR);
 if (err)
  goto err1;

 err = br_sysfs_addif(p);
 if (err)
  goto err2;

 if (br_netpoll_info(br) && ((err = br_netpoll_enable(p, GFP_KERNEL))))
  goto err3;

 err = netdev_master_upper_dev_link(dev, br->dev);
 if (err)
  goto err4;

 err = netdev_rx_handler_register(dev, br_handle_frame, p);
 if (err)
  goto err5;

 dev->priv_flags |= IFF_BRIDGE_PORT;

 dev_disable_lro(dev);

 list_add_rcu(&p->list, &br->port_list);

 netdev_update_features(br->dev);

 spin_lock_bh(&br->lock);
 changed_addr = br_stp_recalculate_bridge_id(br);

 if (netif_running(dev) && netif_oper_up(dev) &&
     (br->dev->flags & IFF_UP))
  br_stp_enable_port(p);
 spin_unlock_bh(&br->lock);

 br_ifinfo_notify(RTM_NEWLINK, p);

 if (changed_addr)
  call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);

 dev_set_mtu(br->dev, br_min_mtu(br));

 if (br_fdb_insert(br, p, dev->dev_addr, 0))
  netdev_err(dev, "failed insert local address bridge forwarding table\n");

 kobject_uevent(&p->kobj, KOBJ_ADD);

 return 0;

err5:
 netdev_upper_dev_unlink(dev, br->dev);
err4:
 br_netpoll_disable(p);
err3:
 sysfs_remove_link(br->ifobj, p->dev->name);
err2:
 kobject_put(&p->kobj);
 p = NULL; /* kobject_put frees */
err1:
 dev_set_promiscuity(dev, -1);
put_back:
 dev_put(dev);
 kfree(p);
 return err;
}

追溯出问题的地方,查找 IFF_DONT_BRIDGE 标志置位的地方,找到如下:

static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
      unsigned long state, void *ndev)
{

   .......
 switch (state) {
  case NETDEV_REGISTER:   // 注册设备
    if ((wdev->iftype == NL80211_IFTYPE_STATION ||
      wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
      wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
     dev->priv_flags |= IFF_DONT_BRIDGE;   
    break;
 }

 .........

从以上红色部分可以看出,当设备为client或者adhoc以及wds时,对应的无线接口是无法加入到桥接中去的。

 

在br_add_if 中判断标志位出错后,返回值为EOPNOTSUPP,定义如下:

#define EOPNOTSUPP  45 /* Op not supported on transport endpoint */ 

跟串口中配置出错时打印相符。

 

转载于:https://www.cnblogs.com/rohens-hbg/p/6515193.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
桥接模式Bridge Pattern)是一种结构型设计模式,它将抽象与实现分离开来,使得它们可以独立地变化。在桥接模式中,抽象和实现可以各自扩展,而不会相互影响。这种模式适用于需要跨越多个平台或多个实现细节的情况。 在电商领域中,桥接模式可以用于处理商品的展示和销售。具体来说,可以定义一个抽象类 `Product`,它包含商品的基本属性和方法,如名称、价格、描述、图片等。然后,针对不同的商品类型(如服装、数码产品、食品等),创建具体的子类,并实现各自的特有属性和方法。 同时,为了处理不同平台(如PC端、移动端等)的展示和销售,可以定义一个抽象类 `Platform`,它包含展示商品、下单购买等方法。然后,具体的平台实现类可以继承 `Platform` 抽象类,并实现各自的展示和销售方法。 为了将商品和平台进行桥接,可以定义一个桥接接口 `ProductDisplay`,它包含一个展示商品的方法 `display()`,接口实现类中需要持有 `Product` 和 `Platform` 的引用,并在 `display()` 方法中将它们结合起来展示商品。 下面是一个简单的示例代码: ```java // 商品抽象类 public abstract class Product { protected String name; protected double price; protected String description; protected String image; public Product(String name, double price, String description, String image) { this.name = name; this.price = price; this.description = description; this.image = image; } public abstract void showDetails(); } // 服装商品类 public class ClothingProduct extends Product { private String size; private String color; public ClothingProduct(String name, double price, String description, String image, String size, String color) { super(name, price, description, image); this.size = size; this.color = color; } @Override public void showDetails() { System.out.println("Clothing Product: " + name + ", Price: " + price + ", Size: " + size + ", Color: " + color); } } // 数码产品类 public class DigitalProduct extends Product { private String brand; private String model; public DigitalProduct(String name, double price, String description, String image, String brand, String model) { super(name, price, description, image); this.brand = brand; this.model = model; } @Override public void showDetails() { System.out.println("Digital Product: " + name + ", Price: " + price + ", Brand: " + brand + ", Model: " + model); } } // 平台抽象类 public abstract class Platform { public abstract void showProduct(Product product); public abstract void purchase(Product product); } // PC平台类 public class PCPlatform extends Platform { @Override public void showProduct(Product product) { System.out.println("PC Platform: Showing product " + product.name + ", Price: " + product.price); } @Override public void purchase(Product product) { System.out.println("PC Platform: Purchasing product " + product.name + ", Price: " + product.price); } } // 移动端平台类 public class MobilePlatform extends Platform { @Override public void showProduct(Product product) { System.out.println("Mobile Platform: Showing product " + product.name + ", Price: " + product.price); } @Override public void purchase(Product product) { System.out.println("Mobile Platform: Purchasing product " + product.name + ", Price: " + product.price); } } // 桥接接口 public interface ProductDisplay { void display(); } // 桥接实现类 public class ProductDisplayImpl implements ProductDisplay { private Product product; private Platform platform; public ProductDisplayImpl(Product product, Platform platform) { this.product = product; this.platform = platform; } @Override public void display() { product.showDetails(); platform.showProduct(product); platform.purchase(product); } } // 示例代码 public class Client { public static void main(String[] args) { Product product = new ClothingProduct("T-shirt", 29.99, "A short-sleeved T-shirt", "t-shirt.jpg", "M", "Red"); Platform platform = new PCPlatform(); ProductDisplay productDisplay = new ProductDisplayImpl(product, platform); productDisplay.display(); System.out.println(); product = new DigitalProduct("Smartphone", 999.99, "A high-end smartphone", "smartphone.jpg", "Apple", "iPhone X"); platform = new MobilePlatform(); productDisplay = new ProductDisplayImpl(product, platform); productDisplay.display(); } } ``` 在上面的代码中,我们定义了两种商品类型(服装和数码产品)和两种平台类型(PC端和移动端),并使用桥接模式将它们进行了桥接。在客户端代码中,我们创建了不同种类的商品和平台对象,并通过桥接接口将它们结合起来展示和销售商品。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值