static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, char *buff, size_t count) { struct net_device *net_dev = kobj_to_netdev(kobj); struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); int status_tmp = -1; int ret = count; if (!hard_iface) return count; if (buff[count - 1] == '\n') buff[count - 1] = '\0'; if (strlen(buff) >= IFNAMSIZ) { pr_err("Invalid parameter for 'mesh_iface' setting received: " "interface name too long '%s'\n", buff); hardif_free_ref(hard_iface); return -EINVAL; } if (strncmp(buff, "none", 4) == 0) status_tmp = IF_NOT_IN_USE; else status_tmp = IF_I_WANT_YOU; if (hard_iface->if_status == status_tmp) goto out; if ((hard_iface->soft_iface) && (strncmp(hard_iface->soft_iface->name, buff, IFNAMSIZ) == 0)) goto out; if (!rtnl_trylock()) { ret = -ERESTARTSYS; goto out; } if (status_tmp == IF_NOT_IN_USE) { hardif_disable_interface(hard_iface); goto unlock; } /* if the interface already is in use */ if (hard_iface->if_status != IF_NOT_IN_USE) hardif_disable_interface(hard_iface); ret = hardif_enable_interface(hard_iface, buff); unlock: rtnl_unlock(); out: hardif_free_ref(hard_iface); return ret; }
static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, char *buff) { struct net_device *net_dev = kobj_to_netdev(kobj); struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); ssize_t length; if (!hard_iface) return 0; switch (hard_iface->if_status) { case IF_TO_BE_REMOVED: length = sprintf(buff, "disabling\n"); break; case IF_INACTIVE: length = sprintf(buff, "inactive\n"); break; case IF_ACTIVE: length = sprintf(buff, "active\n"); break; case IF_TO_BE_ACTIVATED: length = sprintf(buff, "enabling\n"); break; case IF_NOT_IN_USE: default: length = sprintf(buff, "not in use\n"); break; } hardif_free_ref(hard_iface); return length; }
int throw_uevent(struct bat_priv *bat_priv, enum uev_type type, enum uev_action action, const char *data) { int ret = -1; struct hard_iface *primary_if = NULL; struct kobject *bat_kobj; char *uevent_env[4] = { NULL, NULL, NULL, NULL }; primary_if = primary_if_get_selected(bat_priv); if (!primary_if) goto out; bat_kobj = &primary_if->soft_iface->dev.kobj; uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) + strlen(uev_type_str[type]) + 1, GFP_ATOMIC); if (!uevent_env[0]) goto out; sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]); uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) + strlen(uev_action_str[action]) + 1, GFP_ATOMIC); if (!uevent_env[1]) goto out; sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]); /* If the event is DEL, ignore the data field */ if (action != UEV_DEL) { uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) + strlen(data) + 1, GFP_ATOMIC); if (!uevent_env[2]) goto out; sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data); } ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); out: kfree(uevent_env[0]); kfree(uevent_env[1]); kfree(uevent_env[2]); if (primary_if) hardif_free_ref(primary_if); if (ret) bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send " "uevent for (%s,%s,%s) event (err: %d)\n", uev_type_str[type], uev_action_str[action], (action == UEV_DEL ? "NULL" : data), ret); return ret; }
static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, char *buff) { struct net_device *net_dev = kobj_to_netdev(kobj); struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); ssize_t length; if (!hard_iface) return 0; length = sprintf(buff, "%s\n", hard_iface->if_status == IF_NOT_IN_USE ? "none" : hard_iface->soft_iface->name); hardif_free_ref(hard_iface); return length; }
static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) { struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct bat_priv *bat_priv = netdev_priv(soft_iface); struct hard_iface *primary_if = NULL; struct bcast_packet *bcast_packet; struct vlan_ethhdr *vhdr; static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00}; unsigned int header_len = 0; int data_len = skb->len, ret; short vid __maybe_unused = -1; bool do_bcast = false; if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dropped; soft_iface->trans_start = jiffies; switch (ntohs(ethhdr->h_proto)) { case ETH_P_8021Q: vhdr = (struct vlan_ethhdr *)skb->data; vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; if (ntohs(vhdr->h_vlan_encapsulated_proto) != ETH_P_BATMAN) break; /* fall through */ case ETH_P_BATMAN: goto dropped; } if (bla_tx(bat_priv, skb, vid)) goto dropped; /* Register the client MAC in the transtable */ tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif); /* don't accept stp packets. STP does not help in meshes. * better use the bridge loop avoidance ... */ if (compare_eth(ethhdr->h_dest, stp_addr)) goto dropped; if (is_multicast_ether_addr(ethhdr->h_dest)) { do_bcast = true; switch (atomic_read(&bat_priv->gw_mode)) { case GW_MODE_SERVER: /* gateway servers should not send dhcp * requests into the mesh */ ret = gw_is_dhcp_target(skb, &header_len); if (ret) goto dropped; break; case GW_MODE_CLIENT: /* gateway clients should send dhcp requests * via unicast to their gateway */ ret = gw_is_dhcp_target(skb, &header_len); if (ret) do_bcast = false; break; case GW_MODE_OFF: default: break; } } /* ethernet packet should be broadcasted */ if (do_bcast) { primary_if = primary_if_get_selected(bat_priv); if (!primary_if) goto dropped; if (my_skb_head_push(skb, sizeof(*bcast_packet)) < 0) goto dropped; bcast_packet = (struct bcast_packet *)skb->data; bcast_packet->header.version = COMPAT_VERSION; bcast_packet->header.ttl = TTL; /* batman packet type: broadcast */ bcast_packet->header.packet_type = BAT_BCAST; /* hw address of first interface is the orig mac because only * this mac is known throughout the mesh */ memcpy(bcast_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); /* set broadcast sequence number */ bcast_packet->seqno = htonl(atomic_inc_return(&bat_priv->bcast_seqno)); add_bcast_packet_to_list(bat_priv, skb, 1); /* a copy is stored in the bcast list, therefore removing * the original skb. */ kfree_skb(skb); /* unicast packet */ } else { if (atomic_read(&bat_priv->gw_mode) != GW_MODE_OFF) { ret = gw_out_of_range(bat_priv, skb, ethhdr); if (ret) goto dropped; } ret = unicast_send_skb(skb, bat_priv); if (ret != 0) goto dropped_freed; } bat_priv->stats.tx_packets++; bat_priv->stats.tx_bytes += data_len; goto end; dropped: kfree_skb(skb); dropped_freed: bat_priv->stats.tx_dropped++; end: if (primary_if) hardif_free_ref(primary_if); return NETDEV_TX_OK; }