On Tue, 2007-07-03 at 12:29 -0700, Javier Cardona wrote: > David Woodhouse suggested that this list is a more appropriate forum > for my message...
Attached is Javier's proposed patch for this. Please flame away. Dan ----------------------------------- Resent per Dan's request. Support for using setsockpt() to change the mesh-ttl on a network flow, i.e. <snip> sock = socket (PF_INET, SOCK_STREAM, 0); setsockopt(sock, SOL_IP, MESH_SO_SET_TTL, &ttl, optlen); ttl = 0; getsockopt(sock, SOL_IP, MESH_SO_GET_TTL, &ttl, &optlen); </snip> Signed-off-by: Javier Cardona <[EMAIL PROTECTED]> --- drivers/net/wireless/Kconfig | 7 + drivers/net/wireless/libertas/Makefile | 1 + drivers/net/wireless/libertas/decl.h | 3 + drivers/net/wireless/libertas/hostcmd.h | 6 + drivers/net/wireless/libertas/mesh_opts.c | 174 +++++++++++++++++++++++++++++ drivers/net/wireless/libertas/mesh_opts.h | 5 + drivers/net/wireless/libertas/tx.c | 46 +++++++- include/linux/in.h | 3 + 8 files changed, 241 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 1146f3d..f4123c3 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -294,6 +294,13 @@ config LIBERTAS_USB ---help--- A driver for Marvell Libertas 8388 USB devices. +config LIBERTAS_MESH_OPTS + tristate "Mesh Configuration Options for Libertas USB 802.11b/g cards" + depends on LIBERTAS_USB && NETFILTER + ---help--- + This module enables the configuration of mesh parameters on a + per-socket basis, via setsockopt() calls. + config LIBERTAS_DEBUG bool "Enable full debugging output in the Libertas module." depends on LIBERTAS diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile index 71c5a25..a31d4f7 100644 --- a/drivers/net/wireless/libertas/Makefile +++ b/drivers/net/wireless/libertas/Makefile @@ -18,3 +18,4 @@ usb8xxx-objs += if_usb.o obj-$(CONFIG_LIBERTAS) += libertas.o obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o +obj-m += mesh_opts.o diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 4d553da..2cbc137 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -14,6 +14,7 @@ struct wlan_private; struct sk_buff; struct net_device; +struct mesh_options; extern char *libertas_fw_name; @@ -86,6 +87,8 @@ int libertas_activate_card(wlan_private *priv, char *fw_name); int libertas_remove_card(wlan_private *priv); int libertas_add_mesh(wlan_private *priv, struct device *dev); void libertas_remove_mesh(wlan_private *priv); +int libertas_register_mesh_opts(struct mesh_options *); +int libertas_unregister_mesh_opts(struct mesh_options *); #endif /* _WLAN_DECL_H_ */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 0f67cba..bc86ed0 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -34,6 +34,12 @@ struct txpd { u8 reserved1; }; +struct txpd_mesh { + __le16 reserved; + /* mesh ttl */ + u8 ttl; +} __attribute__ ((packed)); + /* RxPD Descriptor */ struct rxpd { /* Current Rx packet status */ diff --git a/drivers/net/wireless/libertas/mesh_opts.c b/drivers/net/wireless/libertas/mesh_opts.c new file mode 100644 index 0000000..118eaed --- /dev/null +++ b/drivers/net/wireless/libertas/mesh_opts.c @@ -0,0 +1,174 @@ +/* + * mesh_opts + * + * Author: Javier Cardona <[EMAIL PROTECTED]> + * Copyright: Marvell Semiconductors Inc., 2007 + * + * Apply mesh-layer specific configuration to network flows. Currently this + * only supports the mesh TTL parameter. + * + * Users call setsockopt on sockets to configure mesh parameters. This module + * maintains a list of sockets (mesh_sks) that have different mesh parameters + * than the per-interface defaults. The driver will modify the mesh + * configuration for each outgoing frame that belongs to one of the sockets in + * the mesh_sks list. + */ + +#include <linux/module.h> +#include <linux/list.h> +#include <linux/net.h> +#include <linux/in.h> +#include <linux/netfilter.h> +#include <linux/netfilter_ipv4.h> +#include <linux/netfilter_ipv6.h> +#include <linux/spinlock.h> +#include <net/sock.h> + +#include <asm/uaccess.h> + +#include "mesh_opts.h" + +#define MESH_SO_BASE_CTL MESH_SO_SET_TTL + +static struct list_head mesh_sks = LIST_HEAD_INIT(mesh_sks); +static DEFINE_RWLOCK(mesh_sks_lock); + +struct mesh_sock { + struct list_head list; + + struct sock *sk; + unsigned char ttl; + void (*orig_sk_destruct) (struct sock *sk); +}; + +static struct mesh_sock * lookup_socket(struct sock *sk) +{ + struct mesh_sock *mesh_sk; + struct mesh_sock *found_sk = NULL; + + read_lock(&mesh_sks_lock); + list_for_each_entry(mesh_sk, &mesh_sks, list) + if (mesh_sk->sk == sk) { + found_sk = mesh_sk; + break; + } + read_unlock(&mesh_sks_lock); + return found_sk; +} + +static void mesh_sk_destruct(struct sock *sk) +{ + struct mesh_sock *mesh_sk; + void (*orig_sk_destruct) (struct sock *sk); + + mesh_sk = lookup_socket(sk); + + if (mesh_sk) { + orig_sk_destruct = mesh_sk->orig_sk_destruct; + write_lock(&mesh_sks_lock); + list_del(&mesh_sk->list); + write_unlock(&mesh_sks_lock); + kfree(mesh_sk); + (*orig_sk_destruct)(sk); + } +} + +static int do_mesh_set_mesh_ttl(struct sock *sk, void __user *user, unsigned int len) +{ + struct mesh_sock *mesh_sk; + unsigned char ttl; + + + if (len) { + if (get_user(ttl, (unsigned char *) user)) + return -EFAULT; + } else + return -EINVAL; + + mesh_sk = (struct mesh_sock*) kmalloc(sizeof(struct mesh_sock), GFP_KERNEL); + mesh_sk->ttl = ttl; + mesh_sk->sk = sk; + mesh_sk->orig_sk_destruct = sk->sk_destruct; + sk->sk_destruct = mesh_sk_destruct; + write_lock(&mesh_sks_lock); + list_add(&mesh_sk->list, &mesh_sks); + write_unlock(&mesh_sks_lock); + + return 0; +} + +static int do_mesh_get_mesh_ttl(struct sock *sk, void __user *user, int *len) +{ + struct mesh_sock *mesh_sk; + int rc = 0; + + if ((mesh_sk = lookup_socket(sk)) == NULL) + return -ENODATA; + + if (put_user(mesh_sk->ttl, (unsigned char*) user)) + return -EFAULT; + + /* netfilter wrapper does the copy to user of len */ + *len = sizeof(unsigned char); + + return rc; +} + +static int do_mesh_set_ctl(struct sock *sk, int optval, void __user *user, + unsigned int len) +{ + return do_mesh_set_mesh_ttl(sk, user, len); +} + +static int do_mesh_get_ctl(struct sock *sk, int optval, void __user *user, + int *len) +{ + return do_mesh_get_mesh_ttl(sk, user, len); +} + +static unsigned char get_sock_mesh_ttl(struct sock *sk) +{ + struct mesh_sock *mesh_sk; + + mesh_sk = lookup_socket(sk); + + /* zero ttl results in using the network interface default */ + return mesh_sk ? mesh_sk->ttl : 0; +} + +static struct mesh_options mesh_opts = +{ + .get_sock_ttl = get_sock_mesh_ttl, +}; + +static struct nf_sockopt_ops mesh_sockopt_ops = +{ + .pf = PF_INET, + .set_optmin = MESH_SO_BASE_CTL, + .set_optmax = MESH_SO_BASE_CTL + 1, + .set = do_mesh_set_ctl, + .get_optmin = MESH_SO_BASE_CTL, + .get_optmax = MESH_SO_BASE_CTL + 1, + .get = do_mesh_get_ctl, +}; + +static int __init mesh_opts_init(void) +{ + int ret; + + if ((ret = nf_register_sockopt(&mesh_sockopt_ops)) < 0) { + return ret; + } + libertas_register_mesh_opts(&mesh_opts); + return ret; +} + +static void __exit mesh_opts_fini(void) +{ + nf_unregister_sockopt(&mesh_sockopt_ops); + libertas_unregister_mesh_opts(&mesh_opts); +} + +module_init(mesh_opts_init); +module_exit(mesh_opts_fini); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/libertas/mesh_opts.h b/drivers/net/wireless/libertas/mesh_opts.h new file mode 100644 index 0000000..cd18fb1 --- /dev/null +++ b/drivers/net/wireless/libertas/mesh_opts.h @@ -0,0 +1,5 @@ + +struct mesh_options { + unsigned char (*get_sock_ttl)(struct sock*); +}; + diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 194f033..497c227 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -9,6 +9,10 @@ #include "defs.h" #include "dev.h" #include "wext.h" +#include "mesh_opts.h" + + +static struct mesh_options mesh_opts = { NULL }; /** * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE @@ -122,15 +126,34 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); if (IS_MESH_FRAME(skb)) { - plocaltxpd->tx_control |= TxPD_MESH_FRAME; + struct txpd_mesh msh_txpd; + plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); + + memset(&msh_txpd, 0, sizeof(msh_txpd)); + + if (mesh_opts.get_sock_ttl) + msh_txpd.ttl = (*mesh_opts.get_sock_ttl)(skb->sk); + + /* ttl of zero is never sent to the hardware */ + if (msh_txpd.ttl) { + /* make room for the mesh descriptor that follows */ + plocaltxpd->tx_packet_location = cpu_to_le32( + sizeof(struct txpd) + sizeof(msh_txpd)); + + memcpy(ptr + sizeof(struct txpd), &msh_txpd, + sizeof(msh_txpd)); + lbs_dbg_hex("txpd_mesh", (u8 *) &msh_txpd, + sizeof(msh_txpd)); + } } memcpy(ptr, plocaltxpd, sizeof(struct txpd)); - ptr += sizeof(struct txpd); + ptr += le32_to_cpu(plocaltxpd->tx_packet_location); - lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length); - memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length); + lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, + le16_to_cpu(plocaltxpd->tx_packet_length)); + memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); ret = priv->hw_host_to_card(priv, MVMS_DAT, priv->adapter->tmptxbuf, plocaltxpd->tx_packet_length + @@ -287,4 +310,19 @@ void libertas_send_tx_feedback(wlan_private * priv) netif_wake_queue(priv->mesh_dev); } } + +int libertas_register_mesh_opts(struct mesh_options *opts) +{ + mesh_opts.get_sock_ttl = opts->get_sock_ttl; + return 0; +} + +int libertas_unregister_mesh_opts(struct mesh_options *opts) +{ + mesh_opts.get_sock_ttl = NULL; + return 0; +} + +EXPORT_SYMBOL_GPL(libertas_register_mesh_opts); +EXPORT_SYMBOL_GPL(libertas_unregister_mesh_opts); EXPORT_SYMBOL_GPL(libertas_send_tx_feedback); diff --git a/include/linux/in.h b/include/linux/in.h index 1912e7c..a69e2ab 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -102,6 +102,9 @@ struct in_addr { #define MCAST_LEAVE_SOURCE_GROUP 47 #define MCAST_MSFILTER 48 +#define MESH_SO_SET_TTL 50 +#define MESH_SO_GET_TTL 50 + #define MCAST_EXCLUDE 0 #define MCAST_INCLUDE 1 - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html