1243a2e63SVlad Yasevich #include <linux/kernel.h> 2243a2e63SVlad Yasevich #include <linux/netdevice.h> 3243a2e63SVlad Yasevich #include <linux/rtnetlink.h> 4243a2e63SVlad Yasevich #include <linux/slab.h> 5243a2e63SVlad Yasevich 6243a2e63SVlad Yasevich #include "br_private.h" 7243a2e63SVlad Yasevich 8552406c4SVlad Yasevich static void __vlan_add_pvid(struct net_port_vlans *v, u16 vid) 9552406c4SVlad Yasevich { 10552406c4SVlad Yasevich if (v->pvid == vid) 11552406c4SVlad Yasevich return; 12552406c4SVlad Yasevich 13552406c4SVlad Yasevich smp_wmb(); 14552406c4SVlad Yasevich v->pvid = vid; 15552406c4SVlad Yasevich } 16552406c4SVlad Yasevich 17552406c4SVlad Yasevich static void __vlan_delete_pvid(struct net_port_vlans *v, u16 vid) 18552406c4SVlad Yasevich { 19552406c4SVlad Yasevich if (v->pvid != vid) 20552406c4SVlad Yasevich return; 21552406c4SVlad Yasevich 22552406c4SVlad Yasevich smp_wmb(); 23552406c4SVlad Yasevich v->pvid = 0; 24552406c4SVlad Yasevich } 25552406c4SVlad Yasevich 26552406c4SVlad Yasevich static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags) 27243a2e63SVlad Yasevich { 28bc9a25d2SVlad Yasevich struct net_bridge_port *p = NULL; 29bc9a25d2SVlad Yasevich struct net_bridge *br; 30bc9a25d2SVlad Yasevich struct net_device *dev; 31243a2e63SVlad Yasevich int err; 32243a2e63SVlad Yasevich 33552406c4SVlad Yasevich if (test_bit(vid, v->vlan_bitmap)) { 34552406c4SVlad Yasevich if (flags & BRIDGE_VLAN_INFO_PVID) 35552406c4SVlad Yasevich __vlan_add_pvid(v, vid); 36552406c4SVlad Yasevich return 0; 37552406c4SVlad Yasevich } 38243a2e63SVlad Yasevich 39bc9a25d2SVlad Yasevich if (vid) { 40bc9a25d2SVlad Yasevich if (v->port_idx) { 41bc9a25d2SVlad Yasevich p = v->parent.port; 42bc9a25d2SVlad Yasevich br = p->br; 43bc9a25d2SVlad Yasevich dev = p->dev; 44bc9a25d2SVlad Yasevich } else { 45bc9a25d2SVlad Yasevich br = v->parent.br; 46bc9a25d2SVlad Yasevich dev = br->dev; 47bc9a25d2SVlad Yasevich } 48243a2e63SVlad Yasevich 49bc9a25d2SVlad Yasevich if (p && (dev->features & NETIF_F_HW_VLAN_FILTER)) { 50243a2e63SVlad Yasevich /* Add VLAN to the device filter if it is supported. 51bc9a25d2SVlad Yasevich * Stricly speaking, this is not necessary now, since 52bc9a25d2SVlad Yasevich * devices are made promiscuous by the bridge, but if 53bc9a25d2SVlad Yasevich * that ever changes this code will allow tagged 54bc9a25d2SVlad Yasevich * traffic to enter the bridge. 55243a2e63SVlad Yasevich */ 56243a2e63SVlad Yasevich err = dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid); 57243a2e63SVlad Yasevich if (err) 58243a2e63SVlad Yasevich return err; 59243a2e63SVlad Yasevich } 60bc9a25d2SVlad Yasevich 61bc9a25d2SVlad Yasevich err = br_fdb_insert(br, p, dev->dev_addr, vid); 62bc9a25d2SVlad Yasevich if (err) { 63bc9a25d2SVlad Yasevich br_err(br, "failed insert local address into bridge " 64bc9a25d2SVlad Yasevich "forwarding table\n"); 65bc9a25d2SVlad Yasevich goto out_filt; 66bc9a25d2SVlad Yasevich } 67bc9a25d2SVlad Yasevich 68243a2e63SVlad Yasevich } 69243a2e63SVlad Yasevich 70243a2e63SVlad Yasevich set_bit(vid, v->vlan_bitmap); 716cbdceebSVlad Yasevich v->num_vlans++; 72552406c4SVlad Yasevich if (flags & BRIDGE_VLAN_INFO_PVID) 73552406c4SVlad Yasevich __vlan_add_pvid(v, vid); 74552406c4SVlad Yasevich 75243a2e63SVlad Yasevich return 0; 76bc9a25d2SVlad Yasevich 77bc9a25d2SVlad Yasevich out_filt: 78bc9a25d2SVlad Yasevich if (p && (dev->features & NETIF_F_HW_VLAN_FILTER)) 79bc9a25d2SVlad Yasevich dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid); 80bc9a25d2SVlad Yasevich return err; 81243a2e63SVlad Yasevich } 82243a2e63SVlad Yasevich 83243a2e63SVlad Yasevich static int __vlan_del(struct net_port_vlans *v, u16 vid) 84243a2e63SVlad Yasevich { 85243a2e63SVlad Yasevich if (!test_bit(vid, v->vlan_bitmap)) 86243a2e63SVlad Yasevich return -EINVAL; 87243a2e63SVlad Yasevich 88552406c4SVlad Yasevich __vlan_delete_pvid(v, vid); 89552406c4SVlad Yasevich 90243a2e63SVlad Yasevich if (v->port_idx && vid) { 91243a2e63SVlad Yasevich struct net_device *dev = v->parent.port->dev; 92243a2e63SVlad Yasevich 93243a2e63SVlad Yasevich if (dev->features & NETIF_F_HW_VLAN_FILTER) 94243a2e63SVlad Yasevich dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid); 95243a2e63SVlad Yasevich } 96243a2e63SVlad Yasevich 97243a2e63SVlad Yasevich clear_bit(vid, v->vlan_bitmap); 986cbdceebSVlad Yasevich v->num_vlans--; 99243a2e63SVlad Yasevich if (bitmap_empty(v->vlan_bitmap, BR_VLAN_BITMAP_LEN)) { 100243a2e63SVlad Yasevich if (v->port_idx) 101243a2e63SVlad Yasevich rcu_assign_pointer(v->parent.port->vlan_info, NULL); 102243a2e63SVlad Yasevich else 103243a2e63SVlad Yasevich rcu_assign_pointer(v->parent.br->vlan_info, NULL); 104243a2e63SVlad Yasevich kfree_rcu(v, rcu); 105243a2e63SVlad Yasevich } 106243a2e63SVlad Yasevich return 0; 107243a2e63SVlad Yasevich } 108243a2e63SVlad Yasevich 109243a2e63SVlad Yasevich static void __vlan_flush(struct net_port_vlans *v) 110243a2e63SVlad Yasevich { 111552406c4SVlad Yasevich smp_wmb(); 112552406c4SVlad Yasevich v->pvid = 0; 113243a2e63SVlad Yasevich bitmap_zero(v->vlan_bitmap, BR_VLAN_BITMAP_LEN); 114243a2e63SVlad Yasevich if (v->port_idx) 115243a2e63SVlad Yasevich rcu_assign_pointer(v->parent.port->vlan_info, NULL); 116243a2e63SVlad Yasevich else 117243a2e63SVlad Yasevich rcu_assign_pointer(v->parent.br->vlan_info, NULL); 118243a2e63SVlad Yasevich kfree_rcu(v, rcu); 119243a2e63SVlad Yasevich } 120243a2e63SVlad Yasevich 12178851988SVlad Yasevich /* Strip the tag from the packet. Will return skb with tci set 0. */ 12278851988SVlad Yasevich static struct sk_buff *br_vlan_untag(struct sk_buff *skb) 12378851988SVlad Yasevich { 12478851988SVlad Yasevich if (skb->protocol != htons(ETH_P_8021Q)) { 12578851988SVlad Yasevich skb->vlan_tci = 0; 12678851988SVlad Yasevich return skb; 12778851988SVlad Yasevich } 12878851988SVlad Yasevich 12978851988SVlad Yasevich skb->vlan_tci = 0; 13078851988SVlad Yasevich skb = vlan_untag(skb); 13178851988SVlad Yasevich if (skb) 13278851988SVlad Yasevich skb->vlan_tci = 0; 13378851988SVlad Yasevich 13478851988SVlad Yasevich return skb; 13578851988SVlad Yasevich } 13678851988SVlad Yasevich 13778851988SVlad Yasevich struct sk_buff *br_handle_vlan(struct net_bridge *br, 13878851988SVlad Yasevich const struct net_port_vlans *pv, 139a37b85c9SVlad Yasevich struct sk_buff *skb) 140a37b85c9SVlad Yasevich { 141a37b85c9SVlad Yasevich u16 vid; 142a37b85c9SVlad Yasevich 14378851988SVlad Yasevich if (!br->vlan_enabled) 14478851988SVlad Yasevich goto out; 14578851988SVlad Yasevich 14678851988SVlad Yasevich /* At this point, we know that the frame was filtered and contains 14778851988SVlad Yasevich * a valid vlan id. If the vlan id matches the pvid of current port 14878851988SVlad Yasevich * send untagged; otherwise, send taged. 14978851988SVlad Yasevich */ 15078851988SVlad Yasevich br_vlan_get_tag(skb, &vid); 15178851988SVlad Yasevich if (vid == br_get_pvid(pv)) 15278851988SVlad Yasevich skb = br_vlan_untag(skb); 15378851988SVlad Yasevich else { 15478851988SVlad Yasevich /* Egress policy says "send tagged". If output device 15578851988SVlad Yasevich * is the bridge, we need to add the VLAN header 15678851988SVlad Yasevich * ourselves since we'll be going through the RX path. 15778851988SVlad Yasevich * Sending to ports puts the frame on the TX path and 15878851988SVlad Yasevich * we let dev_hard_start_xmit() add the header. 15978851988SVlad Yasevich */ 16078851988SVlad Yasevich if (skb->protocol != htons(ETH_P_8021Q) && 16178851988SVlad Yasevich pv->port_idx == 0) { 16278851988SVlad Yasevich /* vlan_put_tag expects skb->data to point to 16378851988SVlad Yasevich * mac header. 16478851988SVlad Yasevich */ 16578851988SVlad Yasevich skb_push(skb, ETH_HLEN); 16678851988SVlad Yasevich skb = __vlan_put_tag(skb, skb->vlan_tci); 16778851988SVlad Yasevich if (!skb) 16878851988SVlad Yasevich goto out; 16978851988SVlad Yasevich /* put skb->data back to where it was */ 17078851988SVlad Yasevich skb_pull(skb, ETH_HLEN); 17178851988SVlad Yasevich skb->vlan_tci = 0; 17278851988SVlad Yasevich } 17378851988SVlad Yasevich } 17478851988SVlad Yasevich 17578851988SVlad Yasevich out: 17678851988SVlad Yasevich return skb; 17778851988SVlad Yasevich } 17878851988SVlad Yasevich 17978851988SVlad Yasevich /* Called under RCU */ 18078851988SVlad Yasevich bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, 18178851988SVlad Yasevich struct sk_buff *skb, u16 *vid) 18278851988SVlad Yasevich { 183a37b85c9SVlad Yasevich /* If VLAN filtering is disabled on the bridge, all packets are 184a37b85c9SVlad Yasevich * permitted. 185a37b85c9SVlad Yasevich */ 186a37b85c9SVlad Yasevich if (!br->vlan_enabled) 187a37b85c9SVlad Yasevich return true; 188a37b85c9SVlad Yasevich 189a37b85c9SVlad Yasevich /* If there are no vlan in the permitted list, all packets are 190a37b85c9SVlad Yasevich * rejected. 191a37b85c9SVlad Yasevich */ 192a37b85c9SVlad Yasevich if (!v) 193a37b85c9SVlad Yasevich return false; 194a37b85c9SVlad Yasevich 19578851988SVlad Yasevich if (br_vlan_get_tag(skb, vid)) { 19678851988SVlad Yasevich u16 pvid = br_get_pvid(v); 19778851988SVlad Yasevich 19878851988SVlad Yasevich /* Frame did not have a tag. See if pvid is set 19978851988SVlad Yasevich * on this port. That tells us which vlan untagged 20078851988SVlad Yasevich * traffic belongs to. 20178851988SVlad Yasevich */ 20278851988SVlad Yasevich if (pvid == VLAN_N_VID) 20378851988SVlad Yasevich return false; 20478851988SVlad Yasevich 20578851988SVlad Yasevich /* PVID is set on this port. Any untagged ingress 20678851988SVlad Yasevich * frame is considered to belong to this vlan. 20778851988SVlad Yasevich */ 20878851988SVlad Yasevich __vlan_hwaccel_put_tag(skb, pvid); 20978851988SVlad Yasevich return true; 21078851988SVlad Yasevich } 21178851988SVlad Yasevich 21278851988SVlad Yasevich /* Frame had a valid vlan tag. See if vlan is allowed */ 21378851988SVlad Yasevich if (test_bit(*vid, v->vlan_bitmap)) 214a37b85c9SVlad Yasevich return true; 215a37b85c9SVlad Yasevich 216a37b85c9SVlad Yasevich return false; 217a37b85c9SVlad Yasevich } 218a37b85c9SVlad Yasevich 21985f46c6bSVlad Yasevich /* Called under RCU. */ 22085f46c6bSVlad Yasevich bool br_allowed_egress(struct net_bridge *br, 22185f46c6bSVlad Yasevich const struct net_port_vlans *v, 22285f46c6bSVlad Yasevich const struct sk_buff *skb) 22385f46c6bSVlad Yasevich { 22485f46c6bSVlad Yasevich u16 vid; 22585f46c6bSVlad Yasevich 22685f46c6bSVlad Yasevich if (!br->vlan_enabled) 22785f46c6bSVlad Yasevich return true; 22885f46c6bSVlad Yasevich 22985f46c6bSVlad Yasevich if (!v) 23085f46c6bSVlad Yasevich return false; 23185f46c6bSVlad Yasevich 23285f46c6bSVlad Yasevich br_vlan_get_tag(skb, &vid); 23385f46c6bSVlad Yasevich if (test_bit(vid, v->vlan_bitmap)) 23485f46c6bSVlad Yasevich return true; 23585f46c6bSVlad Yasevich 23685f46c6bSVlad Yasevich return false; 23785f46c6bSVlad Yasevich } 23885f46c6bSVlad Yasevich 239243a2e63SVlad Yasevich /* Must be protected by RTNL */ 240552406c4SVlad Yasevich int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags) 241243a2e63SVlad Yasevich { 242243a2e63SVlad Yasevich struct net_port_vlans *pv = NULL; 243243a2e63SVlad Yasevich int err; 244243a2e63SVlad Yasevich 245243a2e63SVlad Yasevich ASSERT_RTNL(); 246243a2e63SVlad Yasevich 247243a2e63SVlad Yasevich pv = rtnl_dereference(br->vlan_info); 248243a2e63SVlad Yasevich if (pv) 249552406c4SVlad Yasevich return __vlan_add(pv, vid, flags); 250243a2e63SVlad Yasevich 251243a2e63SVlad Yasevich /* Create port vlan infomration 252243a2e63SVlad Yasevich */ 253243a2e63SVlad Yasevich pv = kzalloc(sizeof(*pv), GFP_KERNEL); 254243a2e63SVlad Yasevich if (!pv) 255243a2e63SVlad Yasevich return -ENOMEM; 256243a2e63SVlad Yasevich 257243a2e63SVlad Yasevich pv->parent.br = br; 258552406c4SVlad Yasevich err = __vlan_add(pv, vid, flags); 259243a2e63SVlad Yasevich if (err) 260243a2e63SVlad Yasevich goto out; 261243a2e63SVlad Yasevich 262243a2e63SVlad Yasevich rcu_assign_pointer(br->vlan_info, pv); 263243a2e63SVlad Yasevich return 0; 264243a2e63SVlad Yasevich out: 265243a2e63SVlad Yasevich kfree(pv); 266243a2e63SVlad Yasevich return err; 267243a2e63SVlad Yasevich } 268243a2e63SVlad Yasevich 269243a2e63SVlad Yasevich /* Must be protected by RTNL */ 270243a2e63SVlad Yasevich int br_vlan_delete(struct net_bridge *br, u16 vid) 271243a2e63SVlad Yasevich { 272243a2e63SVlad Yasevich struct net_port_vlans *pv; 273243a2e63SVlad Yasevich 274243a2e63SVlad Yasevich ASSERT_RTNL(); 275243a2e63SVlad Yasevich 276243a2e63SVlad Yasevich pv = rtnl_dereference(br->vlan_info); 277243a2e63SVlad Yasevich if (!pv) 278243a2e63SVlad Yasevich return -EINVAL; 279243a2e63SVlad Yasevich 280bc9a25d2SVlad Yasevich if (vid) { 281bc9a25d2SVlad Yasevich /* If the VID !=0 remove fdb for this vid. VID 0 is special 282bc9a25d2SVlad Yasevich * in that it's the default and is always there in the fdb. 283bc9a25d2SVlad Yasevich */ 284bc9a25d2SVlad Yasevich spin_lock_bh(&br->hash_lock); 285bc9a25d2SVlad Yasevich fdb_delete_by_addr(br, br->dev->dev_addr, vid); 286bc9a25d2SVlad Yasevich spin_unlock_bh(&br->hash_lock); 287bc9a25d2SVlad Yasevich } 288bc9a25d2SVlad Yasevich 289243a2e63SVlad Yasevich __vlan_del(pv, vid); 290243a2e63SVlad Yasevich return 0; 291243a2e63SVlad Yasevich } 292243a2e63SVlad Yasevich 293243a2e63SVlad Yasevich void br_vlan_flush(struct net_bridge *br) 294243a2e63SVlad Yasevich { 295243a2e63SVlad Yasevich struct net_port_vlans *pv; 296243a2e63SVlad Yasevich 297243a2e63SVlad Yasevich ASSERT_RTNL(); 298243a2e63SVlad Yasevich pv = rtnl_dereference(br->vlan_info); 299243a2e63SVlad Yasevich if (!pv) 300243a2e63SVlad Yasevich return; 301243a2e63SVlad Yasevich 302243a2e63SVlad Yasevich __vlan_flush(pv); 303243a2e63SVlad Yasevich } 304243a2e63SVlad Yasevich 305243a2e63SVlad Yasevich int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) 306243a2e63SVlad Yasevich { 307243a2e63SVlad Yasevich if (!rtnl_trylock()) 308243a2e63SVlad Yasevich return restart_syscall(); 309243a2e63SVlad Yasevich 310243a2e63SVlad Yasevich if (br->vlan_enabled == val) 311243a2e63SVlad Yasevich goto unlock; 312243a2e63SVlad Yasevich 313243a2e63SVlad Yasevich br->vlan_enabled = val; 314243a2e63SVlad Yasevich 315243a2e63SVlad Yasevich unlock: 316243a2e63SVlad Yasevich rtnl_unlock(); 317243a2e63SVlad Yasevich return 0; 318243a2e63SVlad Yasevich } 319243a2e63SVlad Yasevich 320243a2e63SVlad Yasevich /* Must be protected by RTNL */ 321552406c4SVlad Yasevich int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) 322243a2e63SVlad Yasevich { 323243a2e63SVlad Yasevich struct net_port_vlans *pv = NULL; 324243a2e63SVlad Yasevich int err; 325243a2e63SVlad Yasevich 326243a2e63SVlad Yasevich ASSERT_RTNL(); 327243a2e63SVlad Yasevich 328243a2e63SVlad Yasevich pv = rtnl_dereference(port->vlan_info); 329243a2e63SVlad Yasevich if (pv) 330552406c4SVlad Yasevich return __vlan_add(pv, vid, flags); 331243a2e63SVlad Yasevich 332243a2e63SVlad Yasevich /* Create port vlan infomration 333243a2e63SVlad Yasevich */ 334243a2e63SVlad Yasevich pv = kzalloc(sizeof(*pv), GFP_KERNEL); 335243a2e63SVlad Yasevich if (!pv) { 336243a2e63SVlad Yasevich err = -ENOMEM; 337243a2e63SVlad Yasevich goto clean_up; 338243a2e63SVlad Yasevich } 339243a2e63SVlad Yasevich 340243a2e63SVlad Yasevich pv->port_idx = port->port_no; 341243a2e63SVlad Yasevich pv->parent.port = port; 342552406c4SVlad Yasevich err = __vlan_add(pv, vid, flags); 343243a2e63SVlad Yasevich if (err) 344243a2e63SVlad Yasevich goto clean_up; 345243a2e63SVlad Yasevich 346243a2e63SVlad Yasevich rcu_assign_pointer(port->vlan_info, pv); 347243a2e63SVlad Yasevich return 0; 348243a2e63SVlad Yasevich 349243a2e63SVlad Yasevich clean_up: 350243a2e63SVlad Yasevich kfree(pv); 351243a2e63SVlad Yasevich return err; 352243a2e63SVlad Yasevich } 353243a2e63SVlad Yasevich 354243a2e63SVlad Yasevich /* Must be protected by RTNL */ 355243a2e63SVlad Yasevich int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) 356243a2e63SVlad Yasevich { 357243a2e63SVlad Yasevich struct net_port_vlans *pv; 358243a2e63SVlad Yasevich 359243a2e63SVlad Yasevich ASSERT_RTNL(); 360243a2e63SVlad Yasevich 361243a2e63SVlad Yasevich pv = rtnl_dereference(port->vlan_info); 362243a2e63SVlad Yasevich if (!pv) 363243a2e63SVlad Yasevich return -EINVAL; 364243a2e63SVlad Yasevich 365bc9a25d2SVlad Yasevich if (vid) { 366bc9a25d2SVlad Yasevich /* If the VID !=0 remove fdb for this vid. VID 0 is special 367bc9a25d2SVlad Yasevich * in that it's the default and is always there in the fdb. 368bc9a25d2SVlad Yasevich */ 369bc9a25d2SVlad Yasevich spin_lock_bh(&port->br->hash_lock); 370bc9a25d2SVlad Yasevich fdb_delete_by_addr(port->br, port->dev->dev_addr, vid); 371bc9a25d2SVlad Yasevich spin_unlock_bh(&port->br->hash_lock); 372bc9a25d2SVlad Yasevich } 373bc9a25d2SVlad Yasevich 374243a2e63SVlad Yasevich return __vlan_del(pv, vid); 375243a2e63SVlad Yasevich } 376243a2e63SVlad Yasevich 377243a2e63SVlad Yasevich void nbp_vlan_flush(struct net_bridge_port *port) 378243a2e63SVlad Yasevich { 379243a2e63SVlad Yasevich struct net_port_vlans *pv; 380243a2e63SVlad Yasevich 381243a2e63SVlad Yasevich ASSERT_RTNL(); 382243a2e63SVlad Yasevich 383243a2e63SVlad Yasevich pv = rtnl_dereference(port->vlan_info); 384243a2e63SVlad Yasevich if (!pv) 385243a2e63SVlad Yasevich return; 386243a2e63SVlad Yasevich 387243a2e63SVlad Yasevich __vlan_flush(pv); 388243a2e63SVlad Yasevich } 389bc9a25d2SVlad Yasevich 390bc9a25d2SVlad Yasevich bool nbp_vlan_find(struct net_bridge_port *port, u16 vid) 391bc9a25d2SVlad Yasevich { 392bc9a25d2SVlad Yasevich struct net_port_vlans *pv; 393bc9a25d2SVlad Yasevich bool found = false; 394bc9a25d2SVlad Yasevich 395bc9a25d2SVlad Yasevich rcu_read_lock(); 396bc9a25d2SVlad Yasevich pv = rcu_dereference(port->vlan_info); 397bc9a25d2SVlad Yasevich 398bc9a25d2SVlad Yasevich if (!pv) 399bc9a25d2SVlad Yasevich goto out; 400bc9a25d2SVlad Yasevich 401bc9a25d2SVlad Yasevich if (test_bit(vid, pv->vlan_bitmap)) 402bc9a25d2SVlad Yasevich found = true; 403bc9a25d2SVlad Yasevich 404bc9a25d2SVlad Yasevich out: 405bc9a25d2SVlad Yasevich rcu_read_unlock(); 406bc9a25d2SVlad Yasevich return found; 407bc9a25d2SVlad Yasevich } 408