diff options
Diffstat (limited to 'net/batman-adv')
| -rw-r--r-- | net/batman-adv/aggregation.c | 293 | ||||
| -rw-r--r-- | net/batman-adv/aggregation.h | 46 | ||||
| -rw-r--r-- | net/batman-adv/bat_debugfs.c | 359 | ||||
| -rw-r--r-- | net/batman-adv/bat_debugfs.h | 33 | ||||
| -rw-r--r-- | net/batman-adv/bat_sysfs.c | 674 | ||||
| -rw-r--r-- | net/batman-adv/bat_sysfs.h | 44 |
6 files changed, 1449 insertions, 0 deletions
diff --git a/net/batman-adv/aggregation.c b/net/batman-adv/aggregation.c new file mode 100644 index 00000000000..69467fe71ff --- /dev/null +++ b/net/batman-adv/aggregation.c | |||
| @@ -0,0 +1,293 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "translation-table.h" | ||
| 24 | #include "aggregation.h" | ||
| 25 | #include "send.h" | ||
| 26 | #include "routing.h" | ||
| 27 | #include "hard-interface.h" | ||
| 28 | |||
| 29 | /* return true if new_packet can be aggregated with forw_packet */ | ||
| 30 | static bool can_aggregate_with(const struct batman_packet *new_batman_packet, | ||
| 31 | struct bat_priv *bat_priv, | ||
| 32 | int packet_len, | ||
| 33 | unsigned long send_time, | ||
| 34 | bool directlink, | ||
| 35 | const struct hard_iface *if_incoming, | ||
| 36 | const struct forw_packet *forw_packet) | ||
| 37 | { | ||
| 38 | struct batman_packet *batman_packet = | ||
| 39 | (struct batman_packet *)forw_packet->skb->data; | ||
| 40 | int aggregated_bytes = forw_packet->packet_len + packet_len; | ||
| 41 | struct hard_iface *primary_if = NULL; | ||
| 42 | bool res = false; | ||
| 43 | |||
| 44 | /** | ||
| 45 | * we can aggregate the current packet to this aggregated packet | ||
| 46 | * if: | ||
| 47 | * | ||
| 48 | * - the send time is within our MAX_AGGREGATION_MS time | ||
| 49 | * - the resulting packet wont be bigger than | ||
| 50 | * MAX_AGGREGATION_BYTES | ||
| 51 | */ | ||
| 52 | |||
| 53 | if (time_before(send_time, forw_packet->send_time) && | ||
| 54 | time_after_eq(send_time + msecs_to_jiffies(MAX_AGGREGATION_MS), | ||
| 55 | forw_packet->send_time) && | ||
| 56 | (aggregated_bytes <= MAX_AGGREGATION_BYTES)) { | ||
| 57 | |||
| 58 | /** | ||
| 59 | * check aggregation compatibility | ||
| 60 | * -> direct link packets are broadcasted on | ||
| 61 | * their interface only | ||
| 62 | * -> aggregate packet if the current packet is | ||
| 63 | * a "global" packet as well as the base | ||
| 64 | * packet | ||
| 65 | */ | ||
| 66 | |||
| 67 | primary_if = primary_if_get_selected(bat_priv); | ||
| 68 | if (!primary_if) | ||
| 69 | goto out; | ||
| 70 | |||
| 71 | /* packets without direct link flag and high TTL | ||
| 72 | * are flooded through the net */ | ||
| 73 | if ((!directlink) && | ||
| 74 | (!(batman_packet->flags & DIRECTLINK)) && | ||
| 75 | (batman_packet->ttl != 1) && | ||
| 76 | |||
| 77 | /* own packets originating non-primary | ||
| 78 | * interfaces leave only that interface */ | ||
| 79 | ((!forw_packet->own) || | ||
| 80 | (forw_packet->if_incoming == primary_if))) { | ||
| 81 | res = true; | ||
| 82 | goto out; | ||
| 83 | } | ||
| 84 | |||
| 85 | /* if the incoming packet is sent via this one | ||
| 86 | * interface only - we still can aggregate */ | ||
| 87 | if ((directlink) && | ||
| 88 | (new_batman_packet->ttl == 1) && | ||
| 89 | (forw_packet->if_incoming == if_incoming) && | ||
| 90 | |||
| 91 | /* packets from direct neighbors or | ||
| 92 | * own secondary interface packets | ||
| 93 | * (= secondary interface packets in general) */ | ||
| 94 | (batman_packet->flags & DIRECTLINK || | ||
| 95 | (forw_packet->own && | ||
| 96 | forw_packet->if_incoming != primary_if))) { | ||
| 97 | res = true; | ||
| 98 | goto out; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | out: | ||
| 103 | if (primary_if) | ||
| 104 | hardif_free_ref(primary_if); | ||
| 105 | return res; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* create a new aggregated packet and add this packet to it */ | ||
| 109 | static void new_aggregated_packet(const unsigned char *packet_buff, | ||
| 110 | int packet_len, unsigned long send_time, | ||
| 111 | bool direct_link, | ||
| 112 | struct hard_iface *if_incoming, | ||
| 113 | int own_packet) | ||
| 114 | { | ||
| 115 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
| 116 | struct forw_packet *forw_packet_aggr; | ||
| 117 | unsigned char *skb_buff; | ||
| 118 | |||
| 119 | if (!atomic_inc_not_zero(&if_incoming->refcount)) | ||
| 120 | return; | ||
| 121 | |||
| 122 | /* own packet should always be scheduled */ | ||
| 123 | if (!own_packet) { | ||
| 124 | if (!atomic_dec_not_zero(&bat_priv->batman_queue_left)) { | ||
| 125 | bat_dbg(DBG_BATMAN, bat_priv, | ||
| 126 | "batman packet queue full\n"); | ||
| 127 | goto out; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | forw_packet_aggr = kmalloc(sizeof(*forw_packet_aggr), GFP_ATOMIC); | ||
| 132 | if (!forw_packet_aggr) { | ||
| 133 | if (!own_packet) | ||
| 134 | atomic_inc(&bat_priv->batman_queue_left); | ||
| 135 | goto out; | ||
| 136 | } | ||
| 137 | |||
| 138 | if ((atomic_read(&bat_priv->aggregated_ogms)) && | ||
| 139 | (packet_len < MAX_AGGREGATION_BYTES)) | ||
| 140 | forw_packet_aggr->skb = dev_alloc_skb(MAX_AGGREGATION_BYTES + | ||
| 141 | sizeof(struct ethhdr)); | ||
| 142 | else | ||
| 143 | forw_packet_aggr->skb = dev_alloc_skb(packet_len + | ||
| 144 | sizeof(struct ethhdr)); | ||
| 145 | |||
| 146 | if (!forw_packet_aggr->skb) { | ||
| 147 | if (!own_packet) | ||
| 148 | atomic_inc(&bat_priv->batman_queue_left); | ||
| 149 | kfree(forw_packet_aggr); | ||
| 150 | goto out; | ||
| 151 | } | ||
| 152 | skb_reserve(forw_packet_aggr->skb, sizeof(struct ethhdr)); | ||
| 153 | |||
| 154 | INIT_HLIST_NODE(&forw_packet_aggr->list); | ||
| 155 | |||
| 156 | skb_buff = skb_put(forw_packet_aggr->skb, packet_len); | ||
| 157 | forw_packet_aggr->packet_len = packet_len; | ||
| 158 | memcpy(skb_buff, packet_buff, packet_len); | ||
| 159 | |||
| 160 | forw_packet_aggr->own = own_packet; | ||
| 161 | forw_packet_aggr->if_incoming = if_incoming; | ||
| 162 | forw_packet_aggr->num_packets = 0; | ||
| 163 | forw_packet_aggr->direct_link_flags = NO_FLAGS; | ||
| 164 | forw_packet_aggr->send_time = send_time; | ||
| 165 | |||
| 166 | /* save packet direct link flag status */ | ||
| 167 | if (direct_link) | ||
| 168 | forw_packet_aggr->direct_link_flags |= 1; | ||
| 169 | |||
| 170 | /* add new packet to packet list */ | ||
| 171 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
| 172 | hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list); | ||
| 173 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
| 174 | |||
| 175 | /* start timer for this packet */ | ||
| 176 | INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work, | ||
| 177 | send_outstanding_bat_packet); | ||
| 178 | queue_delayed_work(bat_event_workqueue, | ||
| 179 | &forw_packet_aggr->delayed_work, | ||
| 180 | send_time - jiffies); | ||
| 181 | |||
| 182 | return; | ||
| 183 | out: | ||
| 184 | hardif_free_ref(if_incoming); | ||
| 185 | } | ||
| 186 | |||
| 187 | /* aggregate a new packet into the existing aggregation */ | ||
| 188 | static void aggregate(struct forw_packet *forw_packet_aggr, | ||
| 189 | const unsigned char *packet_buff, int packet_len, | ||
| 190 | bool direct_link) | ||
| 191 | { | ||
| 192 | unsigned char *skb_buff; | ||
| 193 | |||
| 194 | skb_buff = skb_put(forw_packet_aggr->skb, packet_len); | ||
| 195 | memcpy(skb_buff, packet_buff, packet_len); | ||
| 196 | forw_packet_aggr->packet_len += packet_len; | ||
| 197 | forw_packet_aggr->num_packets++; | ||
| 198 | |||
| 199 | /* save packet direct link flag status */ | ||
| 200 | if (direct_link) | ||
| 201 | forw_packet_aggr->direct_link_flags |= | ||
| 202 | (1 << forw_packet_aggr->num_packets); | ||
| 203 | } | ||
| 204 | |||
| 205 | void add_bat_packet_to_list(struct bat_priv *bat_priv, | ||
| 206 | unsigned char *packet_buff, int packet_len, | ||
| 207 | struct hard_iface *if_incoming, int own_packet, | ||
| 208 | unsigned long send_time) | ||
| 209 | { | ||
| 210 | /** | ||
| 211 | * _aggr -> pointer to the packet we want to aggregate with | ||
| 212 | * _pos -> pointer to the position in the queue | ||
| 213 | */ | ||
| 214 | struct forw_packet *forw_packet_aggr = NULL, *forw_packet_pos = NULL; | ||
| 215 | struct hlist_node *tmp_node; | ||
| 216 | struct batman_packet *batman_packet = | ||
| 217 | (struct batman_packet *)packet_buff; | ||
| 218 | bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0; | ||
| 219 | |||
| 220 | /* find position for the packet in the forward queue */ | ||
| 221 | spin_lock_bh(&bat_priv->forw_bat_list_lock); | ||
| 222 | /* own packets are not to be aggregated */ | ||
| 223 | if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) { | ||
| 224 | hlist_for_each_entry(forw_packet_pos, tmp_node, | ||
| 225 | &bat_priv->forw_bat_list, list) { | ||
| 226 | if (can_aggregate_with(batman_packet, | ||
| 227 | bat_priv, | ||
| 228 | packet_len, | ||
| 229 | send_time, | ||
| 230 | direct_link, | ||
| 231 | if_incoming, | ||
| 232 | forw_packet_pos)) { | ||
| 233 | forw_packet_aggr = forw_packet_pos; | ||
| 234 | break; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | /* nothing to aggregate with - either aggregation disabled or no | ||
| 240 | * suitable aggregation packet found */ | ||
| 241 | if (!forw_packet_aggr) { | ||
| 242 | /* the following section can run without the lock */ | ||
| 243 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
| 244 | |||
| 245 | /** | ||
| 246 | * if we could not aggregate this packet with one of the others | ||
| 247 | * we hold it back for a while, so that it might be aggregated | ||
| 248 | * later on | ||
| 249 | */ | ||
| 250 | if ((!own_packet) && | ||
| 251 | (atomic_read(&bat_priv->aggregated_ogms))) | ||
| 252 | send_time += msecs_to_jiffies(MAX_AGGREGATION_MS); | ||
| 253 | |||
| 254 | new_aggregated_packet(packet_buff, packet_len, | ||
| 255 | send_time, direct_link, | ||
| 256 | if_incoming, own_packet); | ||
| 257 | } else { | ||
| 258 | aggregate(forw_packet_aggr, | ||
| 259 | packet_buff, packet_len, | ||
| 260 | direct_link); | ||
| 261 | spin_unlock_bh(&bat_priv->forw_bat_list_lock); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | /* unpack the aggregated packets and process them one by one */ | ||
| 266 | void receive_aggr_bat_packet(const struct ethhdr *ethhdr, | ||
| 267 | unsigned char *packet_buff, int packet_len, | ||
| 268 | struct hard_iface *if_incoming) | ||
| 269 | { | ||
| 270 | struct batman_packet *batman_packet; | ||
| 271 | int buff_pos = 0; | ||
| 272 | unsigned char *tt_buff; | ||
| 273 | |||
| 274 | batman_packet = (struct batman_packet *)packet_buff; | ||
| 275 | |||
| 276 | do { | ||
| 277 | /* network to host order for our 32bit seqno and the | ||
| 278 | orig_interval */ | ||
| 279 | batman_packet->seqno = ntohl(batman_packet->seqno); | ||
| 280 | batman_packet->tt_crc = ntohs(batman_packet->tt_crc); | ||
| 281 | |||
| 282 | tt_buff = packet_buff + buff_pos + BAT_PACKET_LEN; | ||
| 283 | |||
| 284 | receive_bat_packet(ethhdr, batman_packet, tt_buff, if_incoming); | ||
| 285 | |||
| 286 | buff_pos += BAT_PACKET_LEN + | ||
| 287 | tt_len(batman_packet->tt_num_changes); | ||
| 288 | |||
| 289 | batman_packet = (struct batman_packet *) | ||
| 290 | (packet_buff + buff_pos); | ||
| 291 | } while (aggregated_packet(buff_pos, packet_len, | ||
| 292 | batman_packet->tt_num_changes)); | ||
| 293 | } | ||
diff --git a/net/batman-adv/aggregation.h b/net/batman-adv/aggregation.h new file mode 100644 index 00000000000..216337bb841 --- /dev/null +++ b/net/batman-adv/aggregation.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner, Simon Wunderlich | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #ifndef _NET_BATMAN_ADV_AGGREGATION_H_ | ||
| 23 | #define _NET_BATMAN_ADV_AGGREGATION_H_ | ||
| 24 | |||
| 25 | #include "main.h" | ||
| 26 | |||
| 27 | /* is there another aggregated packet here? */ | ||
| 28 | static inline int aggregated_packet(int buff_pos, int packet_len, | ||
| 29 | int tt_num_changes) | ||
| 30 | { | ||
| 31 | int next_buff_pos = buff_pos + BAT_PACKET_LEN + (tt_num_changes * | ||
| 32 | sizeof(struct tt_change)); | ||
| 33 | |||
| 34 | return (next_buff_pos <= packet_len) && | ||
| 35 | (next_buff_pos <= MAX_AGGREGATION_BYTES); | ||
| 36 | } | ||
| 37 | |||
| 38 | void add_bat_packet_to_list(struct bat_priv *bat_priv, | ||
| 39 | unsigned char *packet_buff, int packet_len, | ||
| 40 | struct hard_iface *if_incoming, int own_packet, | ||
| 41 | unsigned long send_time); | ||
| 42 | void receive_aggr_bat_packet(const struct ethhdr *ethhdr, | ||
| 43 | unsigned char *packet_buff, int packet_len, | ||
| 44 | struct hard_iface *if_incoming); | ||
| 45 | |||
| 46 | #endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */ | ||
diff --git a/net/batman-adv/bat_debugfs.c b/net/batman-adv/bat_debugfs.c new file mode 100644 index 00000000000..d0af9bf69e4 --- /dev/null +++ b/net/batman-adv/bat_debugfs.c | |||
| @@ -0,0 +1,359 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | |||
| 24 | #include <linux/debugfs.h> | ||
| 25 | |||
| 26 | #include "bat_debugfs.h" | ||
| 27 | #include "translation-table.h" | ||
| 28 | #include "originator.h" | ||
| 29 | #include "hard-interface.h" | ||
| 30 | #include "gateway_common.h" | ||
| 31 | #include "gateway_client.h" | ||
| 32 | #include "soft-interface.h" | ||
| 33 | #include "vis.h" | ||
| 34 | #include "icmp_socket.h" | ||
| 35 | |||
| 36 | static struct dentry *bat_debugfs; | ||
| 37 | |||
| 38 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
| 39 | #define LOG_BUFF_MASK (log_buff_len-1) | ||
| 40 | #define LOG_BUFF(idx) (debug_log->log_buff[(idx) & LOG_BUFF_MASK]) | ||
| 41 | |||
| 42 | static int log_buff_len = LOG_BUF_LEN; | ||
| 43 | |||
| 44 | static void emit_log_char(struct debug_log *debug_log, char c) | ||
| 45 | { | ||
| 46 | LOG_BUFF(debug_log->log_end) = c; | ||
| 47 | debug_log->log_end++; | ||
| 48 | |||
| 49 | if (debug_log->log_end - debug_log->log_start > log_buff_len) | ||
| 50 | debug_log->log_start = debug_log->log_end - log_buff_len; | ||
| 51 | } | ||
| 52 | |||
| 53 | __printf(2, 3) | ||
| 54 | static int fdebug_log(struct debug_log *debug_log, const char *fmt, ...) | ||
| 55 | { | ||
| 56 | va_list args; | ||
| 57 | static char debug_log_buf[256]; | ||
| 58 | char *p; | ||
| 59 | |||
| 60 | if (!debug_log) | ||
| 61 | return 0; | ||
| 62 | |||
| 63 | spin_lock_bh(&debug_log->lock); | ||
| 64 | va_start(args, fmt); | ||
| 65 | vscnprintf(debug_log_buf, sizeof(debug_log_buf), fmt, args); | ||
| 66 | va_end(args); | ||
| 67 | |||
| 68 | for (p = debug_log_buf; *p != 0; p++) | ||
| 69 | emit_log_char(debug_log, *p); | ||
| 70 | |||
| 71 | spin_unlock_bh(&debug_log->lock); | ||
| 72 | |||
| 73 | wake_up(&debug_log->queue_wait); | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | int debug_log(struct bat_priv *bat_priv, const char *fmt, ...) | ||
| 79 | { | ||
| 80 | va_list args; | ||
| 81 | char tmp_log_buf[256]; | ||
| 82 | |||
| 83 | va_start(args, fmt); | ||
| 84 | vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args); | ||
| 85 | fdebug_log(bat_priv->debug_log, "[%10lu] %s", | ||
| 86 | (jiffies / HZ), tmp_log_buf); | ||
| 87 | va_end(args); | ||
| 88 | |||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | static int log_open(struct inode *inode, struct file *file) | ||
| 93 | { | ||
| 94 | nonseekable_open(inode, file); | ||
| 95 | file->private_data = inode->i_private; | ||
| 96 | inc_module_count(); | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int log_release(struct inode *inode, struct file *file) | ||
| 101 | { | ||
| 102 | dec_module_count(); | ||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | static ssize_t log_read(struct file *file, char __user *buf, | ||
| 107 | size_t count, loff_t *ppos) | ||
| 108 | { | ||
| 109 | struct bat_priv *bat_priv = file->private_data; | ||
| 110 | struct debug_log *debug_log = bat_priv->debug_log; | ||
| 111 | int error, i = 0; | ||
| 112 | char c; | ||
| 113 | |||
| 114 | if ((file->f_flags & O_NONBLOCK) && | ||
| 115 | !(debug_log->log_end - debug_log->log_start)) | ||
| 116 | return -EAGAIN; | ||
| 117 | |||
| 118 | if (!buf) | ||
| 119 | return -EINVAL; | ||
| 120 | |||
| 121 | if (count == 0) | ||
| 122 | return 0; | ||
| 123 | |||
| 124 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
| 125 | return -EFAULT; | ||
| 126 | |||
| 127 | error = wait_event_interruptible(debug_log->queue_wait, | ||
| 128 | (debug_log->log_start - debug_log->log_end)); | ||
| 129 | |||
| 130 | if (error) | ||
| 131 | return error; | ||
| 132 | |||
| 133 | spin_lock_bh(&debug_log->lock); | ||
| 134 | |||
| 135 | while ((!error) && (i < count) && | ||
| 136 | (debug_log->log_start != debug_log->log_end)) { | ||
| 137 | c = LOG_BUFF(debug_log->log_start); | ||
| 138 | |||
| 139 | debug_log->log_start++; | ||
| 140 | |||
| 141 | spin_unlock_bh(&debug_log->lock); | ||
| 142 | |||
| 143 | error = __put_user(c, buf); | ||
| 144 | |||
| 145 | spin_lock_bh(&debug_log->lock); | ||
| 146 | |||
| 147 | buf++; | ||
| 148 | i++; | ||
| 149 | |||
| 150 | } | ||
| 151 | |||
| 152 | spin_unlock_bh(&debug_log->lock); | ||
| 153 | |||
| 154 | if (!error) | ||
| 155 | return i; | ||
| 156 | |||
| 157 | return error; | ||
| 158 | } | ||
| 159 | |||
| 160 | static unsigned int log_poll(struct file *file, poll_table *wait) | ||
| 161 | { | ||
| 162 | struct bat_priv *bat_priv = file->private_data; | ||
| 163 | struct debug_log *debug_log = bat_priv->debug_log; | ||
| 164 | |||
| 165 | poll_wait(file, &debug_log->queue_wait, wait); | ||
| 166 | |||
| 167 | if (debug_log->log_end - debug_log->log_start) | ||
| 168 | return POLLIN | POLLRDNORM; | ||
| 169 | |||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | static const struct file_operations log_fops = { | ||
| 174 | .open = log_open, | ||
| 175 | .release = log_release, | ||
| 176 | .read = log_read, | ||
| 177 | .poll = log_poll, | ||
| 178 | .llseek = no_llseek, | ||
| 179 | }; | ||
| 180 | |||
| 181 | static int debug_log_setup(struct bat_priv *bat_priv) | ||
| 182 | { | ||
| 183 | struct dentry *d; | ||
| 184 | |||
| 185 | if (!bat_priv->debug_dir) | ||
| 186 | goto err; | ||
| 187 | |||
| 188 | bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC); | ||
| 189 | if (!bat_priv->debug_log) | ||
| 190 | goto err; | ||
| 191 | |||
| 192 | spin_lock_init(&bat_priv->debug_log->lock); | ||
| 193 | init_waitqueue_head(&bat_priv->debug_log->queue_wait); | ||
| 194 | |||
| 195 | d = debugfs_create_file("log", S_IFREG | S_IRUSR, | ||
| 196 | bat_priv->debug_dir, bat_priv, &log_fops); | ||
| 197 | if (d) | ||
| 198 | goto err; | ||
| 199 | |||
| 200 | return 0; | ||
| 201 | |||
| 202 | err: | ||
| 203 | return 1; | ||
| 204 | } | ||
| 205 | |||
| 206 | static void debug_log_cleanup(struct bat_priv *bat_priv) | ||
| 207 | { | ||
| 208 | kfree(bat_priv->debug_log); | ||
| 209 | bat_priv->debug_log = NULL; | ||
| 210 | } | ||
| 211 | #else /* CONFIG_BATMAN_ADV_DEBUG */ | ||
| 212 | static int debug_log_setup(struct bat_priv *bat_priv) | ||
| 213 | { | ||
| 214 | bat_priv->debug_log = NULL; | ||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | static void debug_log_cleanup(struct bat_priv *bat_priv) | ||
| 219 | { | ||
| 220 | return; | ||
| 221 | } | ||
| 222 | #endif | ||
| 223 | |||
| 224 | static int originators_open(struct inode *inode, struct file *file) | ||
| 225 | { | ||
| 226 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
| 227 | return single_open(file, orig_seq_print_text, net_dev); | ||
| 228 | } | ||
| 229 | |||
| 230 | static int gateways_open(struct inode *inode, struct file *file) | ||
| 231 | { | ||
| 232 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
| 233 | return single_open(file, gw_client_seq_print_text, net_dev); | ||
| 234 | } | ||
| 235 | |||
| 236 | static int softif_neigh_open(struct inode *inode, struct file *file) | ||
| 237 | { | ||
| 238 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
| 239 | return single_open(file, softif_neigh_seq_print_text, net_dev); | ||
| 240 | } | ||
| 241 | |||
| 242 | static int transtable_global_open(struct inode *inode, struct file *file) | ||
| 243 | { | ||
| 244 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
| 245 | return single_open(file, tt_global_seq_print_text, net_dev); | ||
| 246 | } | ||
| 247 | |||
| 248 | static int transtable_local_open(struct inode *inode, struct file *file) | ||
| 249 | { | ||
| 250 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
| 251 | return single_open(file, tt_local_seq_print_text, net_dev); | ||
| 252 | } | ||
| 253 | |||
| 254 | static int vis_data_open(struct inode *inode, struct file *file) | ||
| 255 | { | ||
| 256 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
| 257 | return single_open(file, vis_seq_print_text, net_dev); | ||
| 258 | } | ||
| 259 | |||
| 260 | struct bat_debuginfo { | ||
| 261 | struct attribute attr; | ||
| 262 | const struct file_operations fops; | ||
| 263 | }; | ||
| 264 | |||
| 265 | #define BAT_DEBUGINFO(_name, _mode, _open) \ | ||
| 266 | struct bat_debuginfo bat_debuginfo_##_name = { \ | ||
| 267 | .attr = { .name = __stringify(_name), \ | ||
| 268 | .mode = _mode, }, \ | ||
| 269 | .fops = { .owner = THIS_MODULE, \ | ||
| 270 | .open = _open, \ | ||
| 271 | .read = seq_read, \ | ||
| 272 | .llseek = seq_lseek, \ | ||
| 273 | .release = single_release, \ | ||
| 274 | } \ | ||
| 275 | }; | ||
| 276 | |||
| 277 | static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); | ||
| 278 | static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); | ||
| 279 | static BAT_DEBUGINFO(softif_neigh, S_IRUGO, softif_neigh_open); | ||
| 280 | static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); | ||
| 281 | static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); | ||
| 282 | static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); | ||
| 283 | |||
| 284 | static struct bat_debuginfo *mesh_debuginfos[] = { | ||
| 285 | &bat_debuginfo_originators, | ||
| 286 | &bat_debuginfo_gateways, | ||
| 287 | &bat_debuginfo_softif_neigh, | ||
| 288 | &bat_debuginfo_transtable_global, | ||
| 289 | &bat_debuginfo_transtable_local, | ||
| 290 | &bat_debuginfo_vis_data, | ||
| 291 | NULL, | ||
| 292 | }; | ||
| 293 | |||
| 294 | void debugfs_init(void) | ||
| 295 | { | ||
| 296 | bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL); | ||
| 297 | if (bat_debugfs == ERR_PTR(-ENODEV)) | ||
| 298 | bat_debugfs = NULL; | ||
| 299 | } | ||
| 300 | |||
| 301 | void debugfs_destroy(void) | ||
| 302 | { | ||
| 303 | if (bat_debugfs) { | ||
| 304 | debugfs_remove_recursive(bat_debugfs); | ||
| 305 | bat_debugfs = NULL; | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | int debugfs_add_meshif(struct net_device *dev) | ||
| 310 | { | ||
| 311 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
| 312 | struct bat_debuginfo **bat_debug; | ||
| 313 | struct dentry *file; | ||
| 314 | |||
| 315 | if (!bat_debugfs) | ||
| 316 | goto out; | ||
| 317 | |||
| 318 | bat_priv->debug_dir = debugfs_create_dir(dev->name, bat_debugfs); | ||
| 319 | if (!bat_priv->debug_dir) | ||
| 320 | goto out; | ||
| 321 | |||
| 322 | bat_socket_setup(bat_priv); | ||
| 323 | debug_log_setup(bat_priv); | ||
| 324 | |||
| 325 | for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) { | ||
| 326 | file = debugfs_create_file(((*bat_debug)->attr).name, | ||
| 327 | S_IFREG | ((*bat_debug)->attr).mode, | ||
| 328 | bat_priv->debug_dir, | ||
| 329 | dev, &(*bat_debug)->fops); | ||
| 330 | if (!file) { | ||
| 331 | bat_err(dev, "Can't add debugfs file: %s/%s\n", | ||
| 332 | dev->name, ((*bat_debug)->attr).name); | ||
| 333 | goto rem_attr; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | return 0; | ||
| 338 | rem_attr: | ||
| 339 | debugfs_remove_recursive(bat_priv->debug_dir); | ||
| 340 | bat_priv->debug_dir = NULL; | ||
| 341 | out: | ||
| 342 | #ifdef CONFIG_DEBUG_FS | ||
| 343 | return -ENOMEM; | ||
| 344 | #else | ||
| 345 | return 0; | ||
| 346 | #endif /* CONFIG_DEBUG_FS */ | ||
| 347 | } | ||
| 348 | |||
| 349 | void debugfs_del_meshif(struct net_device *dev) | ||
| 350 | { | ||
| 351 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
| 352 | |||
| 353 | debug_log_cleanup(bat_priv); | ||
| 354 | |||
| 355 | if (bat_debugfs) { | ||
| 356 | debugfs_remove_recursive(bat_priv->debug_dir); | ||
| 357 | bat_priv->debug_dir = NULL; | ||
| 358 | } | ||
| 359 | } | ||
diff --git a/net/batman-adv/bat_debugfs.h b/net/batman-adv/bat_debugfs.h new file mode 100644 index 00000000000..bc9cda3f01e --- /dev/null +++ b/net/batman-adv/bat_debugfs.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | |||
| 23 | #ifndef _NET_BATMAN_ADV_DEBUGFS_H_ | ||
| 24 | #define _NET_BATMAN_ADV_DEBUGFS_H_ | ||
| 25 | |||
| 26 | #define DEBUGFS_BAT_SUBDIR "batman_adv" | ||
| 27 | |||
| 28 | void debugfs_init(void); | ||
| 29 | void debugfs_destroy(void); | ||
| 30 | int debugfs_add_meshif(struct net_device *dev); | ||
| 31 | void debugfs_del_meshif(struct net_device *dev); | ||
| 32 | |||
| 33 | #endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */ | ||
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c new file mode 100644 index 00000000000..cd15deba60a --- /dev/null +++ b/net/batman-adv/bat_sysfs.c | |||
| @@ -0,0 +1,674 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "main.h" | ||
| 23 | #include "bat_sysfs.h" | ||
| 24 | #include "translation-table.h" | ||
| 25 | #include "originator.h" | ||
| 26 | #include "hard-interface.h" | ||
| 27 | #include "gateway_common.h" | ||
| 28 | #include "gateway_client.h" | ||
| 29 | #include "vis.h" | ||
| 30 | |||
| 31 | static struct net_device *kobj_to_netdev(struct kobject *obj) | ||
| 32 | { | ||
| 33 | struct device *dev = container_of(obj->parent, struct device, kobj); | ||
| 34 | return to_net_dev(dev); | ||
| 35 | } | ||
| 36 | |||
| 37 | static struct bat_priv *kobj_to_batpriv(struct kobject *obj) | ||
| 38 | { | ||
| 39 | struct net_device *net_dev = kobj_to_netdev(obj); | ||
| 40 | return netdev_priv(net_dev); | ||
| 41 | } | ||
| 42 | |||
| 43 | #define UEV_TYPE_VAR "BATTYPE=" | ||
| 44 | #define UEV_ACTION_VAR "BATACTION=" | ||
| 45 | #define UEV_DATA_VAR "BATDATA=" | ||
| 46 | |||
| 47 | static char *uev_action_str[] = { | ||
| 48 | "add", | ||
| 49 | "del", | ||
| 50 | "change" | ||
| 51 | }; | ||
| 52 | |||
| 53 | static char *uev_type_str[] = { | ||
| 54 | "gw" | ||
| 55 | }; | ||
| 56 | |||
| 57 | /* Use this, if you have customized show and store functions */ | ||
| 58 | #define BAT_ATTR(_name, _mode, _show, _store) \ | ||
| 59 | struct bat_attribute bat_attr_##_name = { \ | ||
| 60 | .attr = {.name = __stringify(_name), \ | ||
| 61 | .mode = _mode }, \ | ||
| 62 | .show = _show, \ | ||
| 63 | .store = _store, \ | ||
| 64 | }; | ||
| 65 | |||
| 66 | #define BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
| 67 | ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
| 68 | char *buff, size_t count) \ | ||
| 69 | { \ | ||
| 70 | struct net_device *net_dev = kobj_to_netdev(kobj); \ | ||
| 71 | struct bat_priv *bat_priv = netdev_priv(net_dev); \ | ||
| 72 | return __store_bool_attr(buff, count, _post_func, attr, \ | ||
| 73 | &bat_priv->_name, net_dev); \ | ||
| 74 | } | ||
| 75 | |||
| 76 | #define BAT_ATTR_SHOW_BOOL(_name) \ | ||
| 77 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
| 78 | char *buff) \ | ||
| 79 | { \ | ||
| 80 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ | ||
| 81 | return sprintf(buff, "%s\n", \ | ||
| 82 | atomic_read(&bat_priv->_name) == 0 ? \ | ||
| 83 | "disabled" : "enabled"); \ | ||
| 84 | } \ | ||
| 85 | |||
| 86 | /* Use this, if you are going to turn a [name] in bat_priv on or off */ | ||
| 87 | #define BAT_ATTR_BOOL(_name, _mode, _post_func) \ | ||
| 88 | static BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
| 89 | static BAT_ATTR_SHOW_BOOL(_name) \ | ||
| 90 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
| 91 | |||
| 92 | |||
| 93 | #define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
| 94 | ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
| 95 | char *buff, size_t count) \ | ||
| 96 | { \ | ||
| 97 | struct net_device *net_dev = kobj_to_netdev(kobj); \ | ||
| 98 | struct bat_priv *bat_priv = netdev_priv(net_dev); \ | ||
| 99 | return __store_uint_attr(buff, count, _min, _max, _post_func, \ | ||
| 100 | attr, &bat_priv->_name, net_dev); \ | ||
| 101 | } | ||
| 102 | |||
| 103 | #define BAT_ATTR_SHOW_UINT(_name) \ | ||
| 104 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
| 105 | char *buff) \ | ||
| 106 | { \ | ||
| 107 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ | ||
| 108 | return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ | ||
| 109 | } \ | ||
| 110 | |||
| 111 | /* Use this, if you are going to set [name] in bat_priv to unsigned integer | ||
| 112 | * values only */ | ||
| 113 | #define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \ | ||
| 114 | static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
| 115 | static BAT_ATTR_SHOW_UINT(_name) \ | ||
| 116 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
| 117 | |||
| 118 | |||
| 119 | static int store_bool_attr(char *buff, size_t count, | ||
| 120 | struct net_device *net_dev, | ||
| 121 | const char *attr_name, atomic_t *attr) | ||
| 122 | { | ||
| 123 | int enabled = -1; | ||
| 124 | |||
| 125 | if (buff[count - 1] == '\n') | ||
| 126 | buff[count - 1] = '\0'; | ||
| 127 | |||
| 128 | if ((strncmp(buff, "1", 2) == 0) || | ||
| 129 | (strncmp(buff, "enable", 7) == 0) || | ||
| 130 | (strncmp(buff, "enabled", 8) == 0)) | ||
| 131 | enabled = 1; | ||
| 132 | |||
| 133 | if ((strncmp(buff, "0", 2) == 0) || | ||
| 134 | (strncmp(buff, "disable", 8) == 0) || | ||
| 135 | (strncmp(buff, "disabled", 9) == 0)) | ||
| 136 | enabled = 0; | ||
| 137 | |||
| 138 | if (enabled < 0) { | ||
| 139 | bat_info(net_dev, | ||
| 140 | "%s: Invalid parameter received: %s\n", | ||
| 141 | attr_name, buff); | ||
| 142 | return -EINVAL; | ||
| 143 | } | ||
| 144 | |||
| 145 | if (atomic_read(attr) == enabled) | ||
| 146 | return count; | ||
| 147 | |||
| 148 | bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, | ||
| 149 | atomic_read(attr) == 1 ? "enabled" : "disabled", | ||
| 150 | enabled == 1 ? "enabled" : "disabled"); | ||
| 151 | |||
| 152 | atomic_set(attr, (unsigned)enabled); | ||
| 153 | return count; | ||
| 154 | } | ||
| 155 | |||
| 156 | static inline ssize_t __store_bool_attr(char *buff, size_t count, | ||
| 157 | void (*post_func)(struct net_device *), | ||
| 158 | struct attribute *attr, | ||
| 159 | atomic_t *attr_store, struct net_device *net_dev) | ||
| 160 | { | ||
| 161 | int ret; | ||
| 162 | |||
| 163 | ret = store_bool_attr(buff, count, net_dev, attr->name, attr_store); | ||
| 164 | if (post_func && ret) | ||
| 165 | post_func(net_dev); | ||
| 166 | |||
| 167 | return ret; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int store_uint_attr(const char *buff, size_t count, | ||
| 171 | struct net_device *net_dev, const char *attr_name, | ||
| 172 | unsigned int min, unsigned int max, atomic_t *attr) | ||
| 173 | { | ||
| 174 | unsigned long uint_val; | ||
| 175 | int ret; | ||
| 176 | |||
| 177 | ret = strict_strtoul(buff, 10, &uint_val); | ||
| 178 | if (ret) { | ||
| 179 | bat_info(net_dev, | ||
| 180 | "%s: Invalid parameter received: %s\n", | ||
| 181 | attr_name, buff); | ||
| 182 | return -EINVAL; | ||
| 183 | } | ||
| 184 | |||
| 185 | if (uint_val < min) { | ||
| 186 | bat_info(net_dev, "%s: Value is too small: %lu min: %u\n", | ||
| 187 | attr_name, uint_val, min); | ||
| 188 | return -EINVAL; | ||
| 189 | } | ||
| 190 | |||
| 191 | if (uint_val > max) { | ||
| 192 | bat_info(net_dev, "%s: Value is too big: %lu max: %u\n", | ||
| 193 | attr_name, uint_val, max); | ||
| 194 | return -EINVAL; | ||
| 195 | } | ||
| 196 | |||
| 197 | if (atomic_read(attr) == uint_val) | ||
| 198 | return count; | ||
| 199 | |||
| 200 | bat_info(net_dev, "%s: Changing from: %i to: %lu\n", | ||
| 201 | attr_name, atomic_read(attr), uint_val); | ||
| 202 | |||
| 203 | atomic_set(attr, uint_val); | ||
| 204 | return count; | ||
| 205 | } | ||
| 206 | |||
| 207 | static inline ssize_t __store_uint_attr(const char *buff, size_t count, | ||
| 208 | int min, int max, | ||
| 209 | void (*post_func)(struct net_device *), | ||
| 210 | const struct attribute *attr, | ||
| 211 | atomic_t *attr_store, struct net_device *net_dev) | ||
| 212 | { | ||
| 213 | int ret; | ||
| 214 | |||
| 215 | ret = store_uint_attr(buff, count, net_dev, attr->name, | ||
| 216 | min, max, attr_store); | ||
| 217 | if (post_func && ret) | ||
| 218 | post_func(net_dev); | ||
| 219 | |||
| 220 | return ret; | ||
| 221 | } | ||
| 222 | |||
| 223 | static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
| 224 | char *buff) | ||
| 225 | { | ||
| 226 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
| 227 | int vis_mode = atomic_read(&bat_priv->vis_mode); | ||
| 228 | |||
| 229 | return sprintf(buff, "%s\n", | ||
| 230 | vis_mode == VIS_TYPE_CLIENT_UPDATE ? | ||
| 231 | "client" : "server"); | ||
| 232 | } | ||
| 233 | |||
| 234 | static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
| 235 | char *buff, size_t count) | ||
| 236 | { | ||
| 237 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
| 238 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
| 239 | unsigned long val; | ||
| 240 | int ret, vis_mode_tmp = -1; | ||
| 241 | |||
| 242 | ret = strict_strtoul(buff, 10, &val); | ||
| 243 | |||
| 244 | if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) || | ||
| 245 | (strncmp(buff, "client", 6) == 0) || | ||
| 246 | (strncmp(buff, "off", 3) == 0)) | ||
| 247 | vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE; | ||
| 248 | |||
| 249 | if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) || | ||
| 250 | (strncmp(buff, "server", 6) == 0)) | ||
| 251 | vis_mode_tmp = VIS_TYPE_SERVER_SYNC; | ||
| 252 | |||
| 253 | if (vis_mode_tmp < 0) { | ||
| 254 | if (buff[count - 1] == '\n') | ||
| 255 | buff[count - 1] = '\0'; | ||
| 256 | |||
| 257 | bat_info(net_dev, | ||
| 258 | "Invalid parameter for 'vis mode' setting received: " | ||
| 259 | "%s\n", buff); | ||
| 260 | return -EINVAL; | ||
| 261 | } | ||
| 262 | |||
| 263 | if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) | ||
| 264 | return count; | ||
| 265 | |||
| 266 | bat_info(net_dev, "Changing vis mode from: %s to: %s\n", | ||
| 267 | atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ? | ||
| 268 | "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ? | ||
| 269 | "client" : "server"); | ||
| 270 | |||
| 271 | atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp); | ||
| 272 | return count; | ||
| 273 | } | ||
| 274 | |||
| 275 | static void post_gw_deselect(struct net_device *net_dev) | ||
| 276 | { | ||
| 277 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
| 278 | gw_deselect(bat_priv); | ||
| 279 | } | ||
| 280 | |||
| 281 | static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
| 282 | char *buff) | ||
| 283 | { | ||
| 284 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
| 285 | int bytes_written; | ||
| 286 | |||
| 287 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
| 288 | case GW_MODE_CLIENT: | ||
| 289 | bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME); | ||
| 290 | break; | ||
| 291 | case GW_MODE_SERVER: | ||
| 292 | bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME); | ||
| 293 | break; | ||
| 294 | default: | ||
| 295 | bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME); | ||
| 296 | break; | ||
| 297 | } | ||
| 298 | |||
| 299 | return bytes_written; | ||
| 300 | } | ||
| 301 | |||
| 302 | static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
| 303 | char *buff, size_t count) | ||
| 304 | { | ||
| 305 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
| 306 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
| 307 | char *curr_gw_mode_str; | ||
| 308 | int gw_mode_tmp = -1; | ||
| 309 | |||
| 310 | if (buff[count - 1] == '\n') | ||
| 311 | buff[count - 1] = '\0'; | ||
| 312 | |||
| 313 | if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0) | ||
| 314 | gw_mode_tmp = GW_MODE_OFF; | ||
| 315 | |||
| 316 | if (strncmp(buff, GW_MODE_CLIENT_NAME, | ||
| 317 | strlen(GW_MODE_CLIENT_NAME)) == 0) | ||
| 318 | gw_mode_tmp = GW_MODE_CLIENT; | ||
| 319 | |||
| 320 | if (strncmp(buff, GW_MODE_SERVER_NAME, | ||
| 321 | strlen(GW_MODE_SERVER_NAME)) == 0) | ||
| 322 | gw_mode_tmp = GW_MODE_SERVER; | ||
| 323 | |||
| 324 | if (gw_mode_tmp < 0) { | ||
| 325 | bat_info(net_dev, | ||
| 326 | "Invalid parameter for 'gw mode' setting received: " | ||
| 327 | "%s\n", buff); | ||
| 328 | return -EINVAL; | ||
| 329 | } | ||
| 330 | |||
| 331 | if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) | ||
| 332 | return count; | ||
| 333 | |||
| 334 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
| 335 | case GW_MODE_CLIENT: | ||
| 336 | curr_gw_mode_str = GW_MODE_CLIENT_NAME; | ||
| 337 | break; | ||
| 338 | case GW_MODE_SERVER: | ||
| 339 | curr_gw_mode_str = GW_MODE_SERVER_NAME; | ||
| 340 | break; | ||
| 341 | default: | ||
| 342 | curr_gw_mode_str = GW_MODE_OFF_NAME; | ||
| 343 | break; | ||
| 344 | } | ||
| 345 | |||
| 346 | bat_info(net_dev, "Changing gw mode from: %s to: %s\n", | ||
| 347 | curr_gw_mode_str, buff); | ||
| 348 | |||
| 349 | gw_deselect(bat_priv); | ||
| 350 | atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp); | ||
| 351 | return count; | ||
| 352 | } | ||
| 353 | |||
| 354 | static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
| 355 | char *buff) | ||
| 356 | { | ||
| 357 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
| 358 | int down, up; | ||
| 359 | int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); | ||
| 360 | |||
| 361 | gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); | ||
| 362 | return sprintf(buff, "%i%s/%i%s\n", | ||
| 363 | (down > 2048 ? down / 1024 : down), | ||
| 364 | (down > 2048 ? "MBit" : "KBit"), | ||
| 365 | (up > 2048 ? up / 1024 : up), | ||
| 366 | (up > 2048 ? "MBit" : "KBit")); | ||
| 367 | } | ||
| 368 | |||
| 369 | static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
| 370 | char *buff, size_t count) | ||
| 371 | { | ||
| 372 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
| 373 | |||
| 374 | if (buff[count - 1] == '\n') | ||
| 375 | buff[count - 1] = '\0'; | ||
| 376 | |||
| 377 | return gw_bandwidth_set(net_dev, buff, count); | ||
| 378 | } | ||
| 379 | |||
| 380 | BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); | ||
| 381 | BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); | ||
| 382 | BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); | ||
| 383 | static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); | ||
| 384 | static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); | ||
| 385 | BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); | ||
| 386 | BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); | ||
| 387 | BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE, | ||
| 388 | post_gw_deselect); | ||
| 389 | static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, | ||
| 390 | store_gw_bwidth); | ||
| 391 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
| 392 | BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 7, NULL); | ||
| 393 | #endif | ||
| 394 | |||
| 395 | static struct bat_attribute *mesh_attrs[] = { | ||
| 396 | &bat_attr_aggregated_ogms, | ||
| 397 | &bat_attr_bonding, | ||
| 398 | &bat_attr_fragmentation, | ||
| 399 | &bat_attr_vis_mode, | ||
| 400 | &bat_attr_gw_mode, | ||
| 401 | &bat_attr_orig_interval, | ||
| 402 | &bat_attr_hop_penalty, | ||
| 403 | &bat_attr_gw_sel_class, | ||
| 404 | &bat_attr_gw_bandwidth, | ||
| 405 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
| 406 | &bat_attr_log_level, | ||
| 407 | #endif | ||
| 408 | NULL, | ||
| 409 | }; | ||
| 410 | |||
| 411 | int sysfs_add_meshif(struct net_device *dev) | ||
| 412 | { | ||
| 413 | struct kobject *batif_kobject = &dev->dev.kobj; | ||
| 414 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
| 415 | struct bat_attribute **bat_attr; | ||
| 416 | int err; | ||
| 417 | |||
| 418 | bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR, | ||
| 419 | batif_kobject); | ||
| 420 | if (!bat_priv->mesh_obj) { | ||
| 421 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
| 422 | SYSFS_IF_MESH_SUBDIR); | ||
| 423 | goto out; | ||
| 424 | } | ||
| 425 | |||
| 426 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) { | ||
| 427 | err = sysfs_create_file(bat_priv->mesh_obj, | ||
| 428 | &((*bat_attr)->attr)); | ||
| 429 | if (err) { | ||
| 430 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
| 431 | dev->name, SYSFS_IF_MESH_SUBDIR, | ||
| 432 | ((*bat_attr)->attr).name); | ||
| 433 | goto rem_attr; | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | return 0; | ||
| 438 | |||
| 439 | rem_attr: | ||
| 440 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
| 441 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
| 442 | |||
| 443 | kobject_put(bat_priv->mesh_obj); | ||
| 444 | bat_priv->mesh_obj = NULL; | ||
| 445 | out: | ||
| 446 | return -ENOMEM; | ||
| 447 | } | ||
| 448 | |||
| 449 | void sysfs_del_meshif(struct net_device *dev) | ||
| 450 | { | ||
| 451 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
| 452 | struct bat_attribute **bat_attr; | ||
| 453 | |||
| 454 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
| 455 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
| 456 | |||
| 457 | kobject_put(bat_priv->mesh_obj); | ||
| 458 | bat_priv->mesh_obj = NULL; | ||
| 459 | } | ||
| 460 | |||
| 461 | static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
| 462 | char *buff) | ||
| 463 | { | ||
| 464 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
| 465 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | ||
| 466 | ssize_t length; | ||
| 467 | |||
| 468 | if (!hard_iface) | ||
| 469 | return 0; | ||
| 470 | |||
| 471 | length = sprintf(buff, "%s\n", hard_iface->if_status == IF_NOT_IN_USE ? | ||
| 472 | "none" : hard_iface->soft_iface->name); | ||
| 473 | |||
| 474 | hardif_free_ref(hard_iface); | ||
| 475 | |||
| 476 | return length; | ||
| 477 | } | ||
| 478 | |||
| 479 | static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
| 480 | char *buff, size_t count) | ||
| 481 | { | ||
| 482 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
| 483 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | ||
| 484 | int status_tmp = -1; | ||
| 485 | int ret = count; | ||
| 486 | |||
| 487 | if (!hard_iface) | ||
| 488 | return count; | ||
| 489 | |||
| 490 | if (buff[count - 1] == '\n') | ||
| 491 | buff[count - 1] = '\0'; | ||
| 492 | |||
| 493 | if (strlen(buff) >= IFNAMSIZ) { | ||
| 494 | pr_err("Invalid parameter for 'mesh_iface' setting received: " | ||
| 495 | "interface name too long '%s'\n", buff); | ||
| 496 | hardif_free_ref(hard_iface); | ||
| 497 | return -EINVAL; | ||
| 498 | } | ||
| 499 | |||
| 500 | if (strncmp(buff, "none", 4) == 0) | ||
| 501 | status_tmp = IF_NOT_IN_USE; | ||
| 502 | else | ||
| 503 | status_tmp = IF_I_WANT_YOU; | ||
| 504 | |||
| 505 | if (hard_iface->if_status == status_tmp) | ||
| 506 | goto out; | ||
| 507 | |||
| 508 | if ((hard_iface->soft_iface) && | ||
| 509 | (strncmp(hard_iface->soft_iface->name, buff, IFNAMSIZ) == 0)) | ||
| 510 | goto out; | ||
| 511 | |||
| 512 | if (!rtnl_trylock()) { | ||
| 513 | ret = -ERESTARTSYS; | ||
| 514 | goto out; | ||
| 515 | } | ||
| 516 | |||
| 517 | if (status_tmp == IF_NOT_IN_USE) { | ||
| 518 | hardif_disable_interface(hard_iface); | ||
| 519 | goto unlock; | ||
| 520 | } | ||
| 521 | |||
| 522 | /* if the interface already is in use */ | ||
| 523 | if (hard_iface->if_status != IF_NOT_IN_USE) | ||
| 524 | hardif_disable_interface(hard_iface); | ||
| 525 | |||
| 526 | ret = hardif_enable_interface(hard_iface, buff); | ||
| 527 | |||
| 528 | unlock: | ||
| 529 | rtnl_unlock(); | ||
| 530 | out: | ||
| 531 | hardif_free_ref(hard_iface); | ||
| 532 | return ret; | ||
| 533 | } | ||
| 534 | |||
| 535 | static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, | ||
| 536 | char *buff) | ||
| 537 | { | ||
| 538 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
| 539 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | ||
| 540 | ssize_t length; | ||
| 541 | |||
| 542 | if (!hard_iface) | ||
| 543 | return 0; | ||
| 544 | |||
| 545 | switch (hard_iface->if_status) { | ||
| 546 | case IF_TO_BE_REMOVED: | ||
| 547 | length = sprintf(buff, "disabling\n"); | ||
| 548 | break; | ||
| 549 | case IF_INACTIVE: | ||
| 550 | length = sprintf(buff, "inactive\n"); | ||
| 551 | break; | ||
| 552 | case IF_ACTIVE: | ||
| 553 | length = sprintf(buff, "active\n"); | ||
| 554 | break; | ||
| 555 | case IF_TO_BE_ACTIVATED: | ||
| 556 | length = sprintf(buff, "enabling\n"); | ||
| 557 | break; | ||
| 558 | case IF_NOT_IN_USE: | ||
| 559 | default: | ||
| 560 | length = sprintf(buff, "not in use\n"); | ||
| 561 | break; | ||
| 562 | } | ||
| 563 | |||
| 564 | hardif_free_ref(hard_iface); | ||
| 565 | |||
| 566 | return length; | ||
| 567 | } | ||
| 568 | |||
| 569 | static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR, | ||
| 570 | show_mesh_iface, store_mesh_iface); | ||
| 571 | static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL); | ||
| 572 | |||
| 573 | static struct bat_attribute *batman_attrs[] = { | ||
| 574 | &bat_attr_mesh_iface, | ||
| 575 | &bat_attr_iface_status, | ||
| 576 | NULL, | ||
| 577 | }; | ||
| 578 | |||
| 579 | int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev) | ||
| 580 | { | ||
| 581 | struct kobject *hardif_kobject = &dev->dev.kobj; | ||
| 582 | struct bat_attribute **bat_attr; | ||
| 583 | int err; | ||
| 584 | |||
| 585 | *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR, | ||
| 586 | hardif_kobject); | ||
| 587 | |||
| 588 | if (!*hardif_obj) { | ||
| 589 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
| 590 | SYSFS_IF_BAT_SUBDIR); | ||
| 591 | goto out; | ||
| 592 | } | ||
| 593 | |||
| 594 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) { | ||
| 595 | err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr)); | ||
| 596 | if (err) { | ||
| 597 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
| 598 | dev->name, SYSFS_IF_BAT_SUBDIR, | ||
| 599 | ((*bat_attr)->attr).name); | ||
| 600 | goto rem_attr; | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | return 0; | ||
| 605 | |||
| 606 | rem_attr: | ||
| 607 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) | ||
| 608 | sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr)); | ||
| 609 | out: | ||
| 610 | return -ENOMEM; | ||
| 611 | } | ||
| 612 | |||
| 613 | void sysfs_del_hardif(struct kobject **hardif_obj) | ||
| 614 | { | ||
| 615 | kobject_put(*hardif_obj); | ||
| 616 | *hardif_obj = NULL; | ||
| 617 | } | ||
| 618 | |||
| 619 | int throw_uevent(struct bat_priv *bat_priv, enum uev_type type, | ||
| 620 | enum uev_action action, const char *data) | ||
| 621 | { | ||
| 622 | int ret = -1; | ||
| 623 | struct hard_iface *primary_if = NULL; | ||
| 624 | struct kobject *bat_kobj; | ||
| 625 | char *uevent_env[4] = { NULL, NULL, NULL, NULL }; | ||
| 626 | |||
| 627 | primary_if = primary_if_get_selected(bat_priv); | ||
| 628 | if (!primary_if) | ||
| 629 | goto out; | ||
| 630 | |||
| 631 | bat_kobj = &primary_if->soft_iface->dev.kobj; | ||
| 632 | |||
| 633 | uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) + | ||
| 634 | strlen(uev_type_str[type]) + 1, | ||
| 635 | GFP_ATOMIC); | ||
| 636 | if (!uevent_env[0]) | ||
| 637 | goto out; | ||
| 638 | |||
| 639 | sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]); | ||
| 640 | |||
| 641 | uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) + | ||
| 642 | strlen(uev_action_str[action]) + 1, | ||
| 643 | GFP_ATOMIC); | ||
| 644 | if (!uevent_env[1]) | ||
| 645 | goto out; | ||
| 646 | |||
| 647 | sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]); | ||
| 648 | |||
| 649 | /* If the event is DEL, ignore the data field */ | ||
| 650 | if (action != UEV_DEL) { | ||
| 651 | uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) + | ||
| 652 | strlen(data) + 1, GFP_ATOMIC); | ||
| 653 | if (!uevent_env[2]) | ||
| 654 | goto out; | ||
| 655 | |||
| 656 | sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data); | ||
| 657 | } | ||
| 658 | |||
| 659 | ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); | ||
| 660 | out: | ||
| 661 | kfree(uevent_env[0]); | ||
| 662 | kfree(uevent_env[1]); | ||
| 663 | kfree(uevent_env[2]); | ||
| 664 | |||
| 665 | if (primary_if) | ||
| 666 | hardif_free_ref(primary_if); | ||
| 667 | |||
| 668 | if (ret) | ||
| 669 | bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send " | ||
| 670 | "uevent for (%s,%s,%s) event (err: %d)\n", | ||
| 671 | uev_type_str[type], uev_action_str[action], | ||
| 672 | (action == UEV_DEL ? "NULL" : data), ret); | ||
| 673 | return ret; | ||
| 674 | } | ||
diff --git a/net/batman-adv/bat_sysfs.h b/net/batman-adv/bat_sysfs.h new file mode 100644 index 00000000000..a3f75a723c5 --- /dev/null +++ b/net/batman-adv/bat_sysfs.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: | ||
| 3 | * | ||
| 4 | * Marek Lindner | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public | ||
| 8 | * License as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
| 18 | * 02110-1301, USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | |||
| 23 | #ifndef _NET_BATMAN_ADV_SYSFS_H_ | ||
| 24 | #define _NET_BATMAN_ADV_SYSFS_H_ | ||
| 25 | |||
| 26 | #define SYSFS_IF_MESH_SUBDIR "mesh" | ||
| 27 | #define SYSFS_IF_BAT_SUBDIR "batman_adv" | ||
| 28 | |||
| 29 | struct bat_attribute { | ||
| 30 | struct attribute attr; | ||
| 31 | ssize_t (*show)(struct kobject *kobj, struct attribute *attr, | ||
| 32 | char *buf); | ||
| 33 | ssize_t (*store)(struct kobject *kobj, struct attribute *attr, | ||
| 34 | char *buf, size_t count); | ||
| 35 | }; | ||
| 36 | |||
| 37 | int sysfs_add_meshif(struct net_device *dev); | ||
| 38 | void sysfs_del_meshif(struct net_device *dev); | ||
| 39 | int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev); | ||
| 40 | void sysfs_del_hardif(struct kobject **hardif_obj); | ||
| 41 | int throw_uevent(struct bat_priv *bat_priv, enum uev_type type, | ||
| 42 | enum uev_action action, const char *data); | ||
| 43 | |||
| 44 | #endif /* _NET_BATMAN_ADV_SYSFS_H_ */ | ||
