* [PATCH 4/5] dev: Add dev_vprintk_emit and dev_printk_emit
From: Joe Perches @ 2012-08-26 11:25 UTC (permalink / raw)
To: Andrew Morton, Greg Kroah-Hartman
Cc: David S. Miller, Jason Baron, Jim Cromie, Kay Sievers, netdev,
linux-kernel
In-Reply-To: <cover.1345978012.git.joe@perches.com>
Add utility functions to consolidate the use of
create_syslog_header and vprintk_emit.
This allows conversion of logging functions that
call create_syslog_header and then call vprintk_emit
or printk_emit to the dev_ equivalents.
Signed-off-by: Joe Perches <joe@perches.com>
---
drivers/base/core.c | 27 +++++++++++++++++++++++++++
include/linux/device.h | 11 +++++++++++
2 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index d46b635..ffccb64 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1909,6 +1909,33 @@ int create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen)
}
EXPORT_SYMBOL(create_syslog_header);
+int dev_vprintk_emit(int level, const struct device *dev,
+ const char *fmt, va_list args)
+{
+ char hdr[128];
+ size_t hdrlen;
+
+ hdrlen = create_syslog_header(dev, hdr, sizeof(hdr));
+
+ return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen, fmt, args);
+}
+EXPORT_SYMBOL(dev_vprintk_emit);
+
+int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...)
+{
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+
+ r = dev_vprintk_emit(level, dev, fmt, args);
+
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(dev_printk_emit);
+
static int __dev_printk(const char *level, const struct device *dev,
struct va_format *vaf)
{
diff --git a/include/linux/device.h b/include/linux/device.h
index 4800d73..0063d01 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -893,6 +893,10 @@ extern const char *dev_driver_string(const struct device *dev);
extern int create_syslog_header(const struct device *dev,
char *hdr, size_t hdrlen);
+extern int dev_vprintk_emit(int level, const struct device *dev,
+ const char *fmt, va_list args);
+extern __printf(3, 4)
+int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...);
extern __printf(3, 4)
int dev_printk(const char *level, const struct device *dev,
@@ -914,6 +918,13 @@ int _dev_info(const struct device *dev, const char *fmt, ...);
#else
+static int dev_vprintk_emit(int level, const struct device *dev,
+ const char *fmt, va_list args)
+{ return 0; }
+static inline __printf(3, 4)
+int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...)
+{ return 0; }
+
static inline int __dev_printk(const char *level, const struct device *dev,
struct va_format *vaf)
{ return 0; }
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* [PATCH 5/5] device and dynamic_debug: Use dev_vprintk_emit and dev_printk_emit
From: Joe Perches @ 2012-08-26 11:25 UTC (permalink / raw)
To: Andrew Morton, Greg Kroah-Hartman, Jason Baron
Cc: David S. Miller, Jim Cromie, Kay Sievers, netdev, linux-kernel
In-Reply-To: <cover.1345978012.git.joe@perches.com>
Convert direct calls of vprintk_emit and printk_emit to the
dev_ equivalents.
Make create_syslog_header static.
Signed-off-by: Joe Perches <joe@perches.com>
---
drivers/base/core.c | 14 +++++---------
include/linux/device.h | 2 --
lib/dynamic_debug.c | 31 +++++++++++--------------------
net/core/dev.c | 16 ++++++----------
4 files changed, 22 insertions(+), 41 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index ffccb64..65f82e3 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1861,7 +1861,8 @@ void device_shutdown(void)
*/
#ifdef CONFIG_PRINTK
-int create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen)
+static int
+create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen)
{
const char *subsys;
size_t pos = 0;
@@ -1939,17 +1940,12 @@ EXPORT_SYMBOL(dev_printk_emit);
static int __dev_printk(const char *level, const struct device *dev,
struct va_format *vaf)
{
- char hdr[128];
- size_t hdrlen;
-
if (!dev)
return printk("%s(NULL device *): %pV", level, vaf);
- hdrlen = create_syslog_header(dev, hdr, sizeof(hdr));
-
- return printk_emit(0, level[1] - '0', hdrlen ? hdr : NULL, hdrlen,
- "%s %s: %pV",
- dev_driver_string(dev), dev_name(dev), vaf);
+ return dev_printk_emit(level[1] - '0', dev,
+ "%s %s: %pV",
+ dev_driver_string(dev), dev_name(dev), vaf);
}
int dev_printk(const char *level, const struct device *dev,
diff --git a/include/linux/device.h b/include/linux/device.h
index 0063d01..2da4589 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -891,8 +891,6 @@ extern const char *dev_driver_string(const struct device *dev);
#ifdef CONFIG_PRINTK
-extern int create_syslog_header(const struct device *dev,
- char *hdr, size_t hdrlen);
extern int dev_vprintk_emit(int level, const struct device *dev,
const char *fmt, va_list args);
extern __printf(3, 4)
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 6b3ebab..e7f7d99 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -591,15 +591,11 @@ int __dynamic_dev_dbg(struct _ddebug *descriptor,
res = printk(KERN_DEBUG "(NULL device *): %pV", &vaf);
} else {
char buf[PREFIX_SIZE];
- char dict[128];
- size_t dictlen;
- dictlen = create_syslog_header(dev, dict, sizeof(dict));
-
- res = printk_emit(0, 7, dictlen ? dict : NULL, dictlen,
- "%s%s %s: %pV",
- dynamic_emit_prefix(descriptor, buf),
- dev_driver_string(dev), dev_name(dev), &vaf);
+ res = dev_printk_emit(7, dev, "%s%s %s: %pV",
+ dynamic_emit_prefix(descriptor, buf),
+ dev_driver_string(dev), dev_name(dev),
+ &vaf);
}
va_end(args);
@@ -627,18 +623,13 @@ int __dynamic_netdev_dbg(struct _ddebug *descriptor,
if (dev && dev->dev.parent) {
char buf[PREFIX_SIZE];
- char dict[128];
- size_t dictlen;
-
- dictlen = create_syslog_header(dev->dev.parent,
- dict, sizeof(dict));
-
- res = printk_emit(0, 7, dictlen ? dict : NULL, dictlen,
- "%s%s %s %s: %pV",
- dynamic_emit_prefix(descriptor, buf),
- dev_driver_string(dev->dev.parent),
- dev_name(dev->dev.parent),
- netdev_name(dev), &vaf);
+
+ res = dev_printk_emit(7, dev->dev.parent,
+ "%s%s %s %s: %pV",
+ dynamic_emit_prefix(descriptor, buf),
+ dev_driver_string(dev->dev.parent),
+ dev_name(dev->dev.parent),
+ netdev_name(dev), &vaf);
} else if (dev) {
res = printk(KERN_DEBUG "%s: %pV", netdev_name(dev), &vaf);
} else {
diff --git a/net/core/dev.c b/net/core/dev.c
index 1ec186a..8ad42fd 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6428,16 +6428,12 @@ static int __netdev_printk(const char *level, const struct net_device *dev,
int r;
if (dev && dev->dev.parent) {
- char dict[128];
- size_t dictlen = create_syslog_header(dev->dev.parent,
- dict, sizeof(dict));
-
- r = printk_emit(0, level[1] - '0',
- dictlen ? dict : NULL, dictlen,
- "%s %s %s: %pV",
- dev_driver_string(dev->dev.parent),
- dev_name(dev->dev.parent),
- netdev_name(dev), vaf);
+ r = dev_printk_emit(level[1] - '0',
+ dev->dev.parent,
+ "%s %s %s: %pV",
+ dev_driver_string(dev->dev.parent),
+ dev_name(dev->dev.parent),
+ netdev_name(dev), vaf);
} else if (dev) {
r = printk("%s%s: %pV", level, netdev_name(dev), vaf);
} else {
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* Re: [REVIEW][PATCH 09/15] userns: Convert process event connector to handle kuids and kgids
From: Evgeniy Polyakov @ 2012-08-26 12:33 UTC (permalink / raw)
To: Eric W. Biederman
Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
David Miller
In-Reply-To: <877gsmfrkc.fsf@xmission.com>
On Sat, Aug 25, 2012 at 05:02:59PM -0700, Eric W. Biederman (ebiederm@xmission.com) wrote:
>
> - Only allow asking for events from the initial user and pid namespace,
> where we generate the events in.
>
> - Convert kuids and kgids into the initial user namespace to report
> them via the process event connector.
Looks good, if IDs are really supposed to be sent only from root
namespace. And you dropped PROC_EVENTS from init/Kconfig, but since it
was no, it should be ok by default.
Feel free to add my acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Although I thoughs it could be more interesting to generate events
including namespace id
--
Evgeniy Polyakov
^ permalink raw reply
* [PATCH 06/15] userns: Convert audit to use kuid and kgid where appropriate
From: Eric W. Biederman @ 2012-08-26 13:00 UTC (permalink / raw)
To: linux-kernel
Cc: netdev, linux-fsdevel, Serge E. Hallyn, David Miller, Al Viro,
Eric Paris, Paul Moore, Greg Kroah-Hartman
In-Reply-To: <87lih2h6i4.fsf@xmission.com>
- Explicitly deny permission for audit messages sent from processes
outside of the initial pid or user namespace. This removes the need
to format audit messages in other the initial user and pid namespaces.
- Explicitly format uids gids in audit messges in the initial user
namespace. This is safe because auditd is restrected to be in
the initial user namespace.
- Expliclty format pids in audit messages in the initial pid namespace.
This is safe because auditd is restricted to be in the initial pid
namespace.
- Modify audit_get_loginuid to return a kuid
- Modify /proc/<pid>/loginuid on read to convert the loginuid
into the user namespace of the opener of the file.
- Modify /proc/<pid>/loginud on write to convert the loginuid
from the user namespace of the opener of the file.
- In audit_krule store kuid_t values in a new uid field. Allowing
type safety when filtering on uids.
- In audit_krule store kgidt_t values in a new gid field. Allowing
type safety when filtering on gids.
- Get caller process uid and gid from the current task instead of the
NETLINK_CB. This results in simpler code yielding kuid_t and kgid_t
values. This is safe because netlink requests are now all processed
in the task of the sender.
- Convert audit_sig_uid into a kuid_t.
- Deny bitmask comparisons of uids and gids
- Introduce audit_uid_comparitor and audit_gid_compartor typesafe
variants of audit_compartor without the bitmask operations.
- Replace audit_compare_id with audit_compare_uid and audit_compare_gid.
This is one of those odd cases where being type safe and duplicating
code leads to simpler short and more concise code.
- For uid comparisons replace audit_comparator with audit_uid comparator.
- For gid comparisons replace audit_comparator with audit_gid_comparator.
The net result is that the audit subsystem now uses kuid_t and kgid_t whenever
possible making it almost impossible to confuse a raw uid_t with a kuid_t
preventing bugs.
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Eric Paris <eparis@redhat.com>
Cc: Paul Moore <paul@paul-moore.com>
Cc: David Miller <davem@davemloft.net>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
Apologies if you are receiving this twice. I am resending because
it looks like this message failed to be delivered to most of it's
recepients.
drivers/tty/tty_audit.c | 16 ++--
fs/proc/base.c | 12 ++-
include/linux/audit.h | 12 ++-
include/linux/init_task.h | 2 +-
include/linux/sched.h | 2 +-
include/linux/tty.h | 4 +-
include/net/netlabel.h | 2 +-
include/net/xfrm.h | 23 ++--
init/Kconfig | 2 -
kernel/audit.c | 42 +++++---
kernel/audit.h | 4 +-
kernel/audit_watch.c | 2 +-
kernel/auditfilter.c | 142 +++++++++++++++++++++----
kernel/auditsc.c | 214 +++++++++++++++++++------------------
net/core/dev.c | 2 +-
net/netlabel/netlabel_unlabeled.c | 2 +-
net/netlabel/netlabel_user.c | 2 +-
net/xfrm/xfrm_policy.c | 8 +-
net/xfrm/xfrm_state.c | 6 +-
net/xfrm/xfrm_user.c | 12 +-
20 files changed, 320 insertions(+), 191 deletions(-)
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
index 7c58669..e6b2422 100644
--- a/drivers/tty/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -61,7 +61,7 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf)
}
static void tty_audit_log(const char *description, struct task_struct *tsk,
- uid_t loginuid, unsigned sessionid, int major,
+ kuid_t loginuid, unsigned sessionid, int major,
int minor, unsigned char *data, size_t size)
{
struct audit_buffer *ab;
@@ -69,11 +69,13 @@ static void tty_audit_log(const char *description, struct task_struct *tsk,
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
if (ab) {
char name[sizeof(tsk->comm)];
- uid_t uid = task_uid(tsk);
+ uid_t uid = from_kuid_munged(&init_user_ns, task_uid(tsk));
audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
"major=%d minor=%d comm=", description,
- tsk->pid, uid, loginuid, sessionid,
+ tsk->pid, uid,
+ from_kuid(&init_user_ns, loginuid),
+ sessionid,
major, minor);
get_task_comm(name, tsk);
audit_log_untrustedstring(ab, name);
@@ -89,7 +91,7 @@ static void tty_audit_log(const char *description, struct task_struct *tsk,
* Generate an audit message from the contents of @buf, which is owned by
* @tsk with @loginuid. @buf->mutex must be locked.
*/
-static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+static void tty_audit_buf_push(struct task_struct *tsk, kuid_t loginuid,
unsigned int sessionid,
struct tty_audit_buf *buf)
{
@@ -112,7 +114,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
*/
static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
{
- uid_t auid = audit_get_loginuid(current);
+ kuid_t auid = audit_get_loginuid(current);
unsigned int sessionid = audit_get_sessionid(current);
tty_audit_buf_push(current, auid, sessionid, buf);
}
@@ -179,7 +181,7 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
}
if (should_audit && audit_enabled) {
- uid_t auid;
+ kuid_t auid;
unsigned int sessionid;
auid = audit_get_loginuid(current);
@@ -199,7 +201,7 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
* reference to the tty audit buffer if available.
* Flush the buffer or return an appropriate error code.
*/
-int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
+int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid)
{
struct tty_audit_buf *buf = ERR_PTR(-EPERM);
unsigned long flags;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1b6c84c..138cff4 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1089,7 +1089,8 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
if (!task)
return -ESRCH;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
- audit_get_loginuid(task));
+ from_kuid(file->f_cred->user_ns,
+ audit_get_loginuid(task)));
put_task_struct(task);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
@@ -1101,6 +1102,7 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
char *page, *tmp;
ssize_t length;
uid_t loginuid;
+ kuid_t kloginuid;
rcu_read_lock();
if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) {
@@ -1130,7 +1132,13 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
goto out_free_page;
}
- length = audit_set_loginuid(loginuid);
+ kloginuid = make_kuid(file->f_cred->user_ns, loginuid);
+ if (!uid_valid(kloginuid)) {
+ length = -EINVAL;
+ goto out_free_page;
+ }
+
+ length = audit_set_loginuid(kloginuid);
if (likely(length == 0))
length = count;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 36abf2a..4af8ba7 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -442,6 +442,8 @@ struct audit_krule {
struct audit_field {
u32 type;
u32 val;
+ kuid_t uid;
+ kgid_t gid;
u32 op;
char *lsm_str;
void *lsm_rule;
@@ -525,7 +527,7 @@ static inline void audit_ptrace(struct task_struct *t)
extern unsigned int audit_serial(void);
extern int auditsc_get_stamp(struct audit_context *ctx,
struct timespec *t, unsigned int *serial);
-extern int audit_set_loginuid(uid_t loginuid);
+extern int audit_set_loginuid(kuid_t loginuid);
#define audit_get_loginuid(t) ((t)->loginuid)
#define audit_get_sessionid(t) ((t)->sessionid)
extern void audit_log_task_context(struct audit_buffer *ab);
@@ -637,7 +639,7 @@ extern int audit_signals;
#define audit_core_dumps(i) do { ; } while (0)
#define audit_seccomp(i,s,c) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) (0)
-#define audit_get_loginuid(t) (-1)
+#define audit_get_loginuid(t) (INVALID_UID)
#define audit_get_sessionid(t) (-1)
#define audit_log_task_context(b) do { ; } while (0)
#define audit_ipc_obj(i) ((void)0)
@@ -700,10 +702,10 @@ extern void audit_log_secctx(struct audit_buffer *ab, u32 secid);
extern int audit_update_lsm_rules(void);
/* Private API (for audit.c only) */
-extern int audit_filter_user(struct netlink_skb_parms *cb);
+extern int audit_filter_user(void);
extern int audit_filter_type(int type);
-extern int audit_receive_filter(int type, int pid, int uid, int seq,
- void *data, size_t datasz, uid_t loginuid,
+extern int audit_receive_filter(int type, int pid, kuid_t uid, int seq,
+ void *data, size_t datasz, kuid_t loginuid,
u32 sessionid, u32 sid);
extern int audit_enabled;
#else
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 89f1cb1..6d087c5 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -92,7 +92,7 @@ extern struct group_info init_groups;
#ifdef CONFIG_AUDITSYSCALL
#define INIT_IDS \
- .loginuid = -1, \
+ .loginuid = INVALID_UID, \
.sessionid = -1,
#else
#define INIT_IDS
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c147e70..f64d092 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1426,7 +1426,7 @@ struct task_struct {
struct audit_context *audit_context;
#ifdef CONFIG_AUDITSYSCALL
- uid_t loginuid;
+ kuid_t loginuid;
unsigned int sessionid;
#endif
struct seccomp seccomp;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 9f47ab5..7298385 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -553,7 +553,7 @@ extern void tty_audit_fork(struct signal_struct *sig);
extern void tty_audit_tiocsti(struct tty_struct *tty, char ch);
extern void tty_audit_push(struct tty_struct *tty);
extern int tty_audit_push_task(struct task_struct *tsk,
- uid_t loginuid, u32 sessionid);
+ kuid_t loginuid, u32 sessionid);
#else
static inline void tty_audit_add_data(struct tty_struct *tty,
unsigned char *data, size_t size)
@@ -572,7 +572,7 @@ static inline void tty_audit_push(struct tty_struct *tty)
{
}
static inline int tty_audit_push_task(struct task_struct *tsk,
- uid_t loginuid, u32 sessionid)
+ kuid_t loginuid, u32 sessionid)
{
return 0;
}
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index f674409..2c95d55 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -110,7 +110,7 @@ struct cipso_v4_doi;
/* NetLabel audit information */
struct netlbl_audit {
u32 secid;
- uid_t loginuid;
+ kuid_t loginuid;
u32 sessionid;
};
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index d9509eb..1f217e2 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -662,7 +662,7 @@ struct xfrm_spi_skb_cb {
/* Audit Information */
struct xfrm_audit {
u32 secid;
- uid_t loginuid;
+ kuid_t loginuid;
u32 sessionid;
};
@@ -681,13 +681,14 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op)
return audit_buf;
}
-static inline void xfrm_audit_helper_usrinfo(uid_t auid, u32 ses, u32 secid,
+static inline void xfrm_audit_helper_usrinfo(kuid_t auid, u32 ses, u32 secid,
struct audit_buffer *audit_buf)
{
char *secctx;
u32 secctx_len;
- audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
+ audit_log_format(audit_buf, " auid=%u ses=%u",
+ from_kuid(&init_user_ns, auid), ses);
if (secid != 0 &&
security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) {
audit_log_format(audit_buf, " subj=%s", secctx);
@@ -697,13 +698,13 @@ static inline void xfrm_audit_helper_usrinfo(uid_t auid, u32 ses, u32 secid,
}
extern void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
- u32 auid, u32 ses, u32 secid);
+ kuid_t auid, u32 ses, u32 secid);
extern void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
- u32 auid, u32 ses, u32 secid);
+ kuid_t auid, u32 ses, u32 secid);
extern void xfrm_audit_state_add(struct xfrm_state *x, int result,
- u32 auid, u32 ses, u32 secid);
+ kuid_t auid, u32 ses, u32 secid);
extern void xfrm_audit_state_delete(struct xfrm_state *x, int result,
- u32 auid, u32 ses, u32 secid);
+ kuid_t auid, u32 ses, u32 secid);
extern void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
struct sk_buff *skb);
extern void xfrm_audit_state_replay(struct xfrm_state *x,
@@ -716,22 +717,22 @@ extern void xfrm_audit_state_icvfail(struct xfrm_state *x,
#else
static inline void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
- u32 auid, u32 ses, u32 secid)
+ kuid_t auid, u32 ses, u32 secid)
{
}
static inline void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
- u32 auid, u32 ses, u32 secid)
+ kuid_t auid, u32 ses, u32 secid)
{
}
static inline void xfrm_audit_state_add(struct xfrm_state *x, int result,
- u32 auid, u32 ses, u32 secid)
+ kuid_t auid, u32 ses, u32 secid)
{
}
static inline void xfrm_audit_state_delete(struct xfrm_state *x, int result,
- u32 auid, u32 ses, u32 secid)
+ kuid_t auid, u32 ses, u32 secid)
{
}
diff --git a/init/Kconfig b/init/Kconfig
index 4daf449..525f4e8 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -927,8 +927,6 @@ config UIDGID_CONVERTED
# Features
depends on IMA = n
depends on EVM = n
- depends on AUDIT = n
- depends on AUDITSYSCALL = n
depends on TASKSTATS = n
depends on TRACING = n
depends on FS_POSIX_ACL = n
diff --git a/kernel/audit.c b/kernel/audit.c
index ea3b7b6..b25afb7 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -61,6 +61,7 @@
#include <linux/netlink.h>
#include <linux/freezer.h>
#include <linux/tty.h>
+#include <linux/pid_namespace.h>
#include "audit.h"
@@ -104,7 +105,7 @@ static int audit_backlog_wait_time = 60 * HZ;
static int audit_backlog_wait_overflow = 0;
/* The identity of the user shutting down the audit system. */
-uid_t audit_sig_uid = -1;
+kuid_t audit_sig_uid = INVALID_UID;
pid_t audit_sig_pid = -1;
u32 audit_sig_sid = 0;
@@ -264,7 +265,7 @@ void audit_log_lost(const char *message)
}
static int audit_log_config_change(char *function_name, int new, int old,
- uid_t loginuid, u32 sessionid, u32 sid,
+ kuid_t loginuid, u32 sessionid, u32 sid,
int allow_changes)
{
struct audit_buffer *ab;
@@ -272,7 +273,7 @@ static int audit_log_config_change(char *function_name, int new, int old,
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
audit_log_format(ab, "%s=%d old=%d auid=%u ses=%u", function_name, new,
- old, loginuid, sessionid);
+ old, from_kuid(&init_user_ns, loginuid), sessionid);
if (sid) {
char *ctx = NULL;
u32 len;
@@ -292,7 +293,7 @@ static int audit_log_config_change(char *function_name, int new, int old,
}
static int audit_do_config_change(char *function_name, int *to_change,
- int new, uid_t loginuid, u32 sessionid,
+ int new, kuid_t loginuid, u32 sessionid,
u32 sid)
{
int allow_changes, rc = 0, old = *to_change;
@@ -319,21 +320,21 @@ static int audit_do_config_change(char *function_name, int *to_change,
return rc;
}
-static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sessionid,
+static int audit_set_rate_limit(int limit, kuid_t loginuid, u32 sessionid,
u32 sid)
{
return audit_do_config_change("audit_rate_limit", &audit_rate_limit,
limit, loginuid, sessionid, sid);
}
-static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sessionid,
+static int audit_set_backlog_limit(int limit, kuid_t loginuid, u32 sessionid,
u32 sid)
{
return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit,
limit, loginuid, sessionid, sid);
}
-static int audit_set_enabled(int state, uid_t loginuid, u32 sessionid, u32 sid)
+static int audit_set_enabled(int state, kuid_t loginuid, u32 sessionid, u32 sid)
{
int rc;
if (state < AUDIT_OFF || state > AUDIT_LOCKED)
@@ -348,7 +349,7 @@ static int audit_set_enabled(int state, uid_t loginuid, u32 sessionid, u32 sid)
return rc;
}
-static int audit_set_failure(int state, uid_t loginuid, u32 sessionid, u32 sid)
+static int audit_set_failure(int state, kuid_t loginuid, u32 sessionid, u32 sid)
{
if (state != AUDIT_FAIL_SILENT
&& state != AUDIT_FAIL_PRINTK
@@ -467,7 +468,7 @@ static int kauditd_thread(void *dummy)
return 0;
}
-static int audit_prepare_user_tty(pid_t pid, uid_t loginuid, u32 sessionid)
+static int audit_prepare_user_tty(pid_t pid, kuid_t loginuid, u32 sessionid)
{
struct task_struct *tsk;
int err;
@@ -588,6 +589,11 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
{
int err = 0;
+ /* Only support the initial namespaces for now. */
+ if ((current_user_ns() != &init_user_ns) ||
+ (task_active_pid_ns(current) != &init_pid_ns))
+ return -EPERM;
+
switch (msg_type) {
case AUDIT_GET:
case AUDIT_LIST:
@@ -619,7 +625,7 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
}
static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
- u32 pid, u32 uid, uid_t auid, u32 ses,
+ u32 pid, kuid_t uid, kuid_t auid, u32 ses,
u32 sid)
{
int rc = 0;
@@ -633,7 +639,10 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
*ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u",
- pid, uid, auid, ses);
+ pid,
+ from_kuid(&init_user_ns, uid),
+ from_kuid(&init_user_ns, auid),
+ ses);
if (sid) {
rc = security_secid_to_secctx(sid, &ctx, &len);
if (rc)
@@ -649,13 +658,14 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
- u32 uid, pid, seq, sid;
+ u32 pid, seq, sid;
+ kuid_t uid;
void *data;
struct audit_status *status_get, status_set;
int err;
struct audit_buffer *ab;
u16 msg_type = nlh->nlmsg_type;
- uid_t loginuid; /* loginuid of sender */
+ kuid_t loginuid; /* loginuid of sender */
u32 sessionid;
struct audit_sig_info *sig_data;
char *ctx = NULL;
@@ -676,7 +686,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
}
pid = NETLINK_CREDS(skb)->pid;
- uid = NETLINK_CREDS(skb)->uid;
+ uid = current_uid();
loginuid = audit_get_loginuid(current);
sessionid = audit_get_sessionid(current);
security_task_getsecid(current, &sid);
@@ -738,7 +748,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (!audit_enabled && msg_type != AUDIT_USER_AVC)
return 0;
- err = audit_filter_user(&NETLINK_CB(skb));
+ err = audit_filter_user();
if (err == 1) {
err = 0;
if (msg_type == AUDIT_USER_TTY) {
@@ -866,7 +876,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
security_release_secctx(ctx, len);
return -ENOMEM;
}
- sig_data->uid = audit_sig_uid;
+ sig_data->uid = from_kuid(&init_user_ns, audit_sig_uid);
sig_data->pid = audit_sig_pid;
if (audit_sig_sid) {
memcpy(sig_data->ctx, ctx, len);
diff --git a/kernel/audit.h b/kernel/audit.h
index 8167668..fd30cc7 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -76,6 +76,8 @@ static inline int audit_hash_ino(u32 ino)
extern int audit_match_class(int class, unsigned syscall);
extern int audit_comparator(const u32 left, const u32 op, const u32 right);
+extern int audit_uid_comparator(kuid_t left, const u32 op, kuid_t right);
+extern int audit_gid_comparator(kgid_t left, const u32 op, kgid_t right);
extern int audit_compare_dname_path(const char *dname, const char *path,
int *dirlen);
extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
@@ -144,7 +146,7 @@ extern void audit_kill_trees(struct list_head *);
extern char *audit_unpack_string(void **, size_t *, size_t);
extern pid_t audit_sig_pid;
-extern uid_t audit_sig_uid;
+extern kuid_t audit_sig_uid;
extern u32 audit_sig_sid;
#ifdef CONFIG_AUDITSYSCALL
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 3823281..1c22ec3 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -241,7 +241,7 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watc
struct audit_buffer *ab;
ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
audit_log_format(ab, "auid=%u ses=%u op=",
- audit_get_loginuid(current),
+ from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
audit_log_string(ab, op);
audit_log_format(ab, " path=");
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index a6c3f1a..1a8a648 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -342,6 +342,8 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
f->type = rule->fields[i] & ~(AUDIT_NEGATE|AUDIT_OPERATORS);
f->val = rule->values[i];
+ f->uid = INVALID_UID;
+ f->gid = INVALID_GID;
err = -EINVAL;
if (f->op == Audit_bad)
@@ -350,16 +352,34 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
switch(f->type) {
default:
goto exit_free;
- case AUDIT_PID:
case AUDIT_UID:
case AUDIT_EUID:
case AUDIT_SUID:
case AUDIT_FSUID:
+ case AUDIT_LOGINUID:
+ /* bit ops not implemented for uid comparisons */
+ if (f->op == Audit_bitmask || f->op == Audit_bittest)
+ goto exit_free;
+
+ f->uid = make_kuid(current_user_ns(), f->val);
+ if (!uid_valid(f->uid))
+ goto exit_free;
+ break;
+
case AUDIT_GID:
case AUDIT_EGID:
case AUDIT_SGID:
case AUDIT_FSGID:
- case AUDIT_LOGINUID:
+ /* bit ops not implemented for gid comparisons */
+ if (f->op == Audit_bitmask || f->op == Audit_bittest)
+ goto exit_free;
+
+ f->gid = make_kgid(current_user_ns(), f->val);
+ if (!gid_valid(f->gid))
+ goto exit_free;
+ break;
+
+ case AUDIT_PID:
case AUDIT_PERS:
case AUDIT_MSGTYPE:
case AUDIT_PPID:
@@ -437,19 +457,41 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
f->type = data->fields[i];
f->val = data->values[i];
+ f->uid = INVALID_UID;
+ f->gid = INVALID_GID;
f->lsm_str = NULL;
f->lsm_rule = NULL;
switch(f->type) {
- case AUDIT_PID:
case AUDIT_UID:
case AUDIT_EUID:
case AUDIT_SUID:
case AUDIT_FSUID:
+ case AUDIT_LOGINUID:
+ case AUDIT_OBJ_UID:
+ /* bit ops not implemented for uid comparisons */
+ if (f->op == Audit_bitmask || f->op == Audit_bittest)
+ goto exit_free;
+
+ f->uid = make_kuid(current_user_ns(), f->val);
+ if (!uid_valid(f->uid))
+ goto exit_free;
+ break;
+
case AUDIT_GID:
case AUDIT_EGID:
case AUDIT_SGID:
case AUDIT_FSGID:
- case AUDIT_LOGINUID:
+ case AUDIT_OBJ_GID:
+ /* bit ops not implemented for gid comparisons */
+ if (f->op == Audit_bitmask || f->op == Audit_bittest)
+ goto exit_free;
+
+ f->gid = make_kgid(current_user_ns(), f->val);
+ if (!gid_valid(f->gid))
+ goto exit_free;
+ break;
+
+ case AUDIT_PID:
case AUDIT_PERS:
case AUDIT_MSGTYPE:
case AUDIT_PPID:
@@ -461,9 +503,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
case AUDIT_ARG1:
case AUDIT_ARG2:
case AUDIT_ARG3:
- case AUDIT_OBJ_UID:
- case AUDIT_OBJ_GID:
break;
+ /* arch is only allowed to be = or != */
case AUDIT_ARCH:
entry->rule.arch_f = f;
break;
@@ -707,6 +748,23 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
if (strcmp(a->filterkey, b->filterkey))
return 1;
break;
+ case AUDIT_UID:
+ case AUDIT_EUID:
+ case AUDIT_SUID:
+ case AUDIT_FSUID:
+ case AUDIT_LOGINUID:
+ case AUDIT_OBJ_UID:
+ if (!uid_eq(a->fields[i].uid, b->fields[i].uid))
+ return 1;
+ break;
+ case AUDIT_GID:
+ case AUDIT_EGID:
+ case AUDIT_SGID:
+ case AUDIT_FSGID:
+ case AUDIT_OBJ_GID:
+ if (!gid_eq(a->fields[i].gid, b->fields[i].gid))
+ return 1;
+ break;
default:
if (a->fields[i].val != b->fields[i].val)
return 1;
@@ -1056,7 +1114,7 @@ static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
}
/* Log rule additions and removals */
-static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid,
+static void audit_log_rule_change(kuid_t loginuid, u32 sessionid, u32 sid,
char *action, struct audit_krule *rule,
int res)
{
@@ -1068,7 +1126,8 @@ static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid,
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
if (!ab)
return;
- audit_log_format(ab, "auid=%u ses=%u", loginuid, sessionid);
+ audit_log_format(ab, "auid=%u ses=%u",
+ from_kuid(&init_user_ns, loginuid), sessionid);
if (sid) {
char *ctx = NULL;
u32 len;
@@ -1098,8 +1157,8 @@ static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid,
* @sessionid: sessionid for netlink audit message
* @sid: SE Linux Security ID of sender
*/
-int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
- size_t datasz, uid_t loginuid, u32 sessionid, u32 sid)
+int audit_receive_filter(int type, int pid, kuid_t uid, int seq, void *data,
+ size_t datasz, kuid_t loginuid, u32 sessionid, u32 sid)
{
struct task_struct *tsk;
struct audit_netlink_list *dest;
@@ -1198,6 +1257,52 @@ int audit_comparator(u32 left, u32 op, u32 right)
}
}
+int audit_uid_comparator(kuid_t left, u32 op, kuid_t right)
+{
+ switch (op) {
+ case Audit_equal:
+ return uid_eq(left, right);
+ case Audit_not_equal:
+ return !uid_eq(left, right);
+ case Audit_lt:
+ return uid_lt(left, right);
+ case Audit_le:
+ return uid_lte(left, right);
+ case Audit_gt:
+ return uid_gt(left, right);
+ case Audit_ge:
+ return uid_gte(left, right);
+ case Audit_bitmask:
+ case Audit_bittest:
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+int audit_gid_comparator(kgid_t left, u32 op, kgid_t right)
+{
+ switch (op) {
+ case Audit_equal:
+ return gid_eq(left, right);
+ case Audit_not_equal:
+ return !gid_eq(left, right);
+ case Audit_lt:
+ return gid_lt(left, right);
+ case Audit_le:
+ return gid_lte(left, right);
+ case Audit_gt:
+ return gid_gt(left, right);
+ case Audit_ge:
+ return gid_gte(left, right);
+ case Audit_bitmask:
+ case Audit_bittest:
+ default:
+ BUG();
+ return 0;
+ }
+}
+
/* Compare given dentry name with last component in given path,
* return of 0 indicates a match. */
int audit_compare_dname_path(const char *dname, const char *path,
@@ -1236,8 +1341,7 @@ int audit_compare_dname_path(const char *dname, const char *path,
return strncmp(p, dname, dlen);
}
-static int audit_filter_user_rules(struct netlink_skb_parms *cb,
- struct audit_krule *rule,
+static int audit_filter_user_rules(struct audit_krule *rule,
enum audit_state *state)
{
int i;
@@ -1249,17 +1353,17 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb,
switch (f->type) {
case AUDIT_PID:
- result = audit_comparator(cb->creds.pid, f->op, f->val);
+ result = audit_comparator(task_pid_nr(current), f->op, f->val);
break;
case AUDIT_UID:
- result = audit_comparator(cb->creds.uid, f->op, f->val);
+ result = audit_uid_comparator(current_uid(), f->op, f->uid);
break;
case AUDIT_GID:
- result = audit_comparator(cb->creds.gid, f->op, f->val);
+ result = audit_gid_comparator(current_gid(), f->op, f->gid);
break;
case AUDIT_LOGINUID:
- result = audit_comparator(audit_get_loginuid(current),
- f->op, f->val);
+ result = audit_uid_comparator(audit_get_loginuid(current),
+ f->op, f->uid);
break;
case AUDIT_SUBJ_USER:
case AUDIT_SUBJ_ROLE:
@@ -1287,7 +1391,7 @@ static int audit_filter_user_rules(struct netlink_skb_parms *cb,
return 1;
}
-int audit_filter_user(struct netlink_skb_parms *cb)
+int audit_filter_user(void)
{
enum audit_state state = AUDIT_DISABLED;
struct audit_entry *e;
@@ -1295,7 +1399,7 @@ int audit_filter_user(struct netlink_skb_parms *cb)
rcu_read_lock();
list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) {
- if (audit_filter_user_rules(cb, &e->rule, &state)) {
+ if (audit_filter_user_rules(&e->rule, &state)) {
if (state == AUDIT_DISABLED)
ret = 0;
break;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4b96415..0795f58 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -113,8 +113,8 @@ struct audit_names {
unsigned long ino;
dev_t dev;
umode_t mode;
- uid_t uid;
- gid_t gid;
+ kuid_t uid;
+ kgid_t gid;
dev_t rdev;
u32 osid;
struct audit_cap_data fcap;
@@ -149,8 +149,8 @@ struct audit_aux_data_execve {
struct audit_aux_data_pids {
struct audit_aux_data d;
pid_t target_pid[AUDIT_AUX_PIDS];
- uid_t target_auid[AUDIT_AUX_PIDS];
- uid_t target_uid[AUDIT_AUX_PIDS];
+ kuid_t target_auid[AUDIT_AUX_PIDS];
+ kuid_t target_uid[AUDIT_AUX_PIDS];
unsigned int target_sessionid[AUDIT_AUX_PIDS];
u32 target_sid[AUDIT_AUX_PIDS];
char target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN];
@@ -208,14 +208,14 @@ struct audit_context {
size_t sockaddr_len;
/* Save things to print about task_struct */
pid_t pid, ppid;
- uid_t uid, euid, suid, fsuid;
- gid_t gid, egid, sgid, fsgid;
+ kuid_t uid, euid, suid, fsuid;
+ kgid_t gid, egid, sgid, fsgid;
unsigned long personality;
int arch;
pid_t target_pid;
- uid_t target_auid;
- uid_t target_uid;
+ kuid_t target_auid;
+ kuid_t target_uid;
unsigned int target_sessionid;
u32 target_sid;
char target_comm[TASK_COMM_LEN];
@@ -231,8 +231,8 @@ struct audit_context {
long args[6];
} socketcall;
struct {
- uid_t uid;
- gid_t gid;
+ kuid_t uid;
+ kgid_t gid;
umode_t mode;
u32 osid;
int has_perm;
@@ -464,37 +464,47 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
return 0;
}
-static int audit_compare_id(uid_t uid1,
- struct audit_names *name,
- unsigned long name_offset,
- struct audit_field *f,
- struct audit_context *ctx)
+static int audit_compare_uid(kuid_t uid,
+ struct audit_names *name,
+ struct audit_field *f,
+ struct audit_context *ctx)
{
struct audit_names *n;
- unsigned long addr;
- uid_t uid2;
int rc;
- BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
-
if (name) {
- addr = (unsigned long)name;
- addr += name_offset;
-
- uid2 = *(uid_t *)addr;
- rc = audit_comparator(uid1, f->op, uid2);
+ rc = audit_uid_comparator(uid, f->op, name->uid);
if (rc)
return rc;
}
if (ctx) {
list_for_each_entry(n, &ctx->names_list, list) {
- addr = (unsigned long)n;
- addr += name_offset;
+ rc = audit_uid_comparator(uid, f->op, n->uid);
+ if (rc)
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static int audit_compare_gid(kgid_t gid,
+ struct audit_names *name,
+ struct audit_field *f,
+ struct audit_context *ctx)
+{
+ struct audit_names *n;
+ int rc;
- uid2 = *(uid_t *)addr;
+ if (name) {
+ rc = audit_gid_comparator(gid, f->op, name->gid);
+ if (rc)
+ return rc;
+ }
- rc = audit_comparator(uid1, f->op, uid2);
+ if (ctx) {
+ list_for_each_entry(n, &ctx->names_list, list) {
+ rc = audit_gid_comparator(gid, f->op, n->gid);
if (rc)
return rc;
}
@@ -511,80 +521,62 @@ static int audit_field_compare(struct task_struct *tsk,
switch (f->val) {
/* process to file object comparisons */
case AUDIT_COMPARE_UID_TO_OBJ_UID:
- return audit_compare_id(cred->uid,
- name, offsetof(struct audit_names, uid),
- f, ctx);
+ return audit_compare_uid(cred->uid, name, f, ctx);
case AUDIT_COMPARE_GID_TO_OBJ_GID:
- return audit_compare_id(cred->gid,
- name, offsetof(struct audit_names, gid),
- f, ctx);
+ return audit_compare_gid(cred->gid, name, f, ctx);
case AUDIT_COMPARE_EUID_TO_OBJ_UID:
- return audit_compare_id(cred->euid,
- name, offsetof(struct audit_names, uid),
- f, ctx);
+ return audit_compare_uid(cred->euid, name, f, ctx);
case AUDIT_COMPARE_EGID_TO_OBJ_GID:
- return audit_compare_id(cred->egid,
- name, offsetof(struct audit_names, gid),
- f, ctx);
+ return audit_compare_gid(cred->egid, name, f, ctx);
case AUDIT_COMPARE_AUID_TO_OBJ_UID:
- return audit_compare_id(tsk->loginuid,
- name, offsetof(struct audit_names, uid),
- f, ctx);
+ return audit_compare_uid(tsk->loginuid, name, f, ctx);
case AUDIT_COMPARE_SUID_TO_OBJ_UID:
- return audit_compare_id(cred->suid,
- name, offsetof(struct audit_names, uid),
- f, ctx);
+ return audit_compare_uid(cred->suid, name, f, ctx);
case AUDIT_COMPARE_SGID_TO_OBJ_GID:
- return audit_compare_id(cred->sgid,
- name, offsetof(struct audit_names, gid),
- f, ctx);
+ return audit_compare_gid(cred->sgid, name, f, ctx);
case AUDIT_COMPARE_FSUID_TO_OBJ_UID:
- return audit_compare_id(cred->fsuid,
- name, offsetof(struct audit_names, uid),
- f, ctx);
+ return audit_compare_uid(cred->fsuid, name, f, ctx);
case AUDIT_COMPARE_FSGID_TO_OBJ_GID:
- return audit_compare_id(cred->fsgid,
- name, offsetof(struct audit_names, gid),
- f, ctx);
+ return audit_compare_gid(cred->fsgid, name, f, ctx);
/* uid comparisons */
case AUDIT_COMPARE_UID_TO_AUID:
- return audit_comparator(cred->uid, f->op, tsk->loginuid);
+ return audit_uid_comparator(cred->uid, f->op, tsk->loginuid);
case AUDIT_COMPARE_UID_TO_EUID:
- return audit_comparator(cred->uid, f->op, cred->euid);
+ return audit_uid_comparator(cred->uid, f->op, cred->euid);
case AUDIT_COMPARE_UID_TO_SUID:
- return audit_comparator(cred->uid, f->op, cred->suid);
+ return audit_uid_comparator(cred->uid, f->op, cred->suid);
case AUDIT_COMPARE_UID_TO_FSUID:
- return audit_comparator(cred->uid, f->op, cred->fsuid);
+ return audit_uid_comparator(cred->uid, f->op, cred->fsuid);
/* auid comparisons */
case AUDIT_COMPARE_AUID_TO_EUID:
- return audit_comparator(tsk->loginuid, f->op, cred->euid);
+ return audit_uid_comparator(tsk->loginuid, f->op, cred->euid);
case AUDIT_COMPARE_AUID_TO_SUID:
- return audit_comparator(tsk->loginuid, f->op, cred->suid);
+ return audit_uid_comparator(tsk->loginuid, f->op, cred->suid);
case AUDIT_COMPARE_AUID_TO_FSUID:
- return audit_comparator(tsk->loginuid, f->op, cred->fsuid);
+ return audit_uid_comparator(tsk->loginuid, f->op, cred->fsuid);
/* euid comparisons */
case AUDIT_COMPARE_EUID_TO_SUID:
- return audit_comparator(cred->euid, f->op, cred->suid);
+ return audit_uid_comparator(cred->euid, f->op, cred->suid);
case AUDIT_COMPARE_EUID_TO_FSUID:
- return audit_comparator(cred->euid, f->op, cred->fsuid);
+ return audit_uid_comparator(cred->euid, f->op, cred->fsuid);
/* suid comparisons */
case AUDIT_COMPARE_SUID_TO_FSUID:
- return audit_comparator(cred->suid, f->op, cred->fsuid);
+ return audit_uid_comparator(cred->suid, f->op, cred->fsuid);
/* gid comparisons */
case AUDIT_COMPARE_GID_TO_EGID:
- return audit_comparator(cred->gid, f->op, cred->egid);
+ return audit_gid_comparator(cred->gid, f->op, cred->egid);
case AUDIT_COMPARE_GID_TO_SGID:
- return audit_comparator(cred->gid, f->op, cred->sgid);
+ return audit_gid_comparator(cred->gid, f->op, cred->sgid);
case AUDIT_COMPARE_GID_TO_FSGID:
- return audit_comparator(cred->gid, f->op, cred->fsgid);
+ return audit_gid_comparator(cred->gid, f->op, cred->fsgid);
/* egid comparisons */
case AUDIT_COMPARE_EGID_TO_SGID:
- return audit_comparator(cred->egid, f->op, cred->sgid);
+ return audit_gid_comparator(cred->egid, f->op, cred->sgid);
case AUDIT_COMPARE_EGID_TO_FSGID:
- return audit_comparator(cred->egid, f->op, cred->fsgid);
+ return audit_gid_comparator(cred->egid, f->op, cred->fsgid);
/* sgid comparison */
case AUDIT_COMPARE_SGID_TO_FSGID:
- return audit_comparator(cred->sgid, f->op, cred->fsgid);
+ return audit_gid_comparator(cred->sgid, f->op, cred->fsgid);
default:
WARN(1, "Missing AUDIT_COMPARE define. Report as a bug\n");
return 0;
@@ -630,28 +622,28 @@ static int audit_filter_rules(struct task_struct *tsk,
}
break;
case AUDIT_UID:
- result = audit_comparator(cred->uid, f->op, f->val);
+ result = audit_uid_comparator(cred->uid, f->op, f->uid);
break;
case AUDIT_EUID:
- result = audit_comparator(cred->euid, f->op, f->val);
+ result = audit_uid_comparator(cred->euid, f->op, f->uid);
break;
case AUDIT_SUID:
- result = audit_comparator(cred->suid, f->op, f->val);
+ result = audit_uid_comparator(cred->suid, f->op, f->uid);
break;
case AUDIT_FSUID:
- result = audit_comparator(cred->fsuid, f->op, f->val);
+ result = audit_uid_comparator(cred->fsuid, f->op, f->uid);
break;
case AUDIT_GID:
- result = audit_comparator(cred->gid, f->op, f->val);
+ result = audit_gid_comparator(cred->gid, f->op, f->gid);
break;
case AUDIT_EGID:
- result = audit_comparator(cred->egid, f->op, f->val);
+ result = audit_gid_comparator(cred->egid, f->op, f->gid);
break;
case AUDIT_SGID:
- result = audit_comparator(cred->sgid, f->op, f->val);
+ result = audit_gid_comparator(cred->sgid, f->op, f->gid);
break;
case AUDIT_FSGID:
- result = audit_comparator(cred->fsgid, f->op, f->val);
+ result = audit_gid_comparator(cred->fsgid, f->op, f->gid);
break;
case AUDIT_PERS:
result = audit_comparator(tsk->personality, f->op, f->val);
@@ -717,10 +709,10 @@ static int audit_filter_rules(struct task_struct *tsk,
break;
case AUDIT_OBJ_UID:
if (name) {
- result = audit_comparator(name->uid, f->op, f->val);
+ result = audit_uid_comparator(name->uid, f->op, f->uid);
} else if (ctx) {
list_for_each_entry(n, &ctx->names_list, list) {
- if (audit_comparator(n->uid, f->op, f->val)) {
+ if (audit_uid_comparator(n->uid, f->op, f->uid)) {
++result;
break;
}
@@ -729,10 +721,10 @@ static int audit_filter_rules(struct task_struct *tsk,
break;
case AUDIT_OBJ_GID:
if (name) {
- result = audit_comparator(name->gid, f->op, f->val);
+ result = audit_gid_comparator(name->gid, f->op, f->gid);
} else if (ctx) {
list_for_each_entry(n, &ctx->names_list, list) {
- if (audit_comparator(n->gid, f->op, f->val)) {
+ if (audit_gid_comparator(n->gid, f->op, f->gid)) {
++result;
break;
}
@@ -750,7 +742,7 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_LOGINUID:
result = 0;
if (ctx)
- result = audit_comparator(tsk->loginuid, f->op, f->val);
+ result = audit_uid_comparator(tsk->loginuid, f->op, f->uid);
break;
case AUDIT_SUBJ_USER:
case AUDIT_SUBJ_ROLE:
@@ -1184,7 +1176,7 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
}
static int audit_log_pid_context(struct audit_context *context, pid_t pid,
- uid_t auid, uid_t uid, unsigned int sessionid,
+ kuid_t auid, kuid_t uid, unsigned int sessionid,
u32 sid, char *comm)
{
struct audit_buffer *ab;
@@ -1196,8 +1188,9 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
if (!ab)
return rc;
- audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid,
- uid, sessionid);
+ audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid,
+ from_kuid(&init_user_ns, auid),
+ from_kuid(&init_user_ns, uid), sessionid);
if (security_secid_to_secctx(sid, &ctx, &len)) {
audit_log_format(ab, " obj=(none)");
rc = 1;
@@ -1447,7 +1440,9 @@ static void show_special(struct audit_context *context, int *call_panic)
u32 osid = context->ipc.osid;
audit_log_format(ab, "ouid=%u ogid=%u mode=%#ho",
- context->ipc.uid, context->ipc.gid, context->ipc.mode);
+ from_kuid(&init_user_ns, context->ipc.uid),
+ from_kgid(&init_user_ns, context->ipc.gid),
+ context->ipc.mode);
if (osid) {
char *ctx = NULL;
u32 len;
@@ -1560,8 +1555,8 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
MAJOR(n->dev),
MINOR(n->dev),
n->mode,
- n->uid,
- n->gid,
+ from_kuid(&init_user_ns, n->uid),
+ from_kgid(&init_user_ns, n->gid),
MAJOR(n->rdev),
MINOR(n->rdev));
}
@@ -1638,11 +1633,16 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
context->name_count,
context->ppid,
context->pid,
- tsk->loginuid,
- context->uid,
- context->gid,
- context->euid, context->suid, context->fsuid,
- context->egid, context->sgid, context->fsgid, tty,
+ from_kuid(&init_user_ns, tsk->loginuid),
+ from_kuid(&init_user_ns, context->uid),
+ from_kgid(&init_user_ns, context->gid),
+ from_kuid(&init_user_ns, context->euid),
+ from_kuid(&init_user_ns, context->suid),
+ from_kuid(&init_user_ns, context->fsuid),
+ from_kgid(&init_user_ns, context->egid),
+ from_kgid(&init_user_ns, context->sgid),
+ from_kgid(&init_user_ns, context->fsgid),
+ tty,
tsk->sessionid);
@@ -2299,14 +2299,14 @@ static atomic_t session_id = ATOMIC_INIT(0);
*
* Called (set) from fs/proc/base.c::proc_loginuid_write().
*/
-int audit_set_loginuid(uid_t loginuid)
+int audit_set_loginuid(kuid_t loginuid)
{
struct task_struct *task = current;
struct audit_context *context = task->audit_context;
unsigned int sessionid;
#ifdef CONFIG_AUDIT_LOGINUID_IMMUTABLE
- if (task->loginuid != -1)
+ if (uid_valid(task->loginuid))
return -EPERM;
#else /* CONFIG_AUDIT_LOGINUID_IMMUTABLE */
if (!capable(CAP_AUDIT_CONTROL))
@@ -2322,8 +2322,10 @@ int audit_set_loginuid(uid_t loginuid)
audit_log_format(ab, "login pid=%d uid=%u "
"old auid=%u new auid=%u"
" old ses=%u new ses=%u",
- task->pid, task_uid(task),
- task->loginuid, loginuid,
+ task->pid,
+ from_kuid(&init_user_ns, task_uid(task)),
+ from_kuid(&init_user_ns, task->loginuid),
+ from_kuid(&init_user_ns, loginuid),
task->sessionid, sessionid);
audit_log_end(ab);
}
@@ -2546,15 +2548,14 @@ int __audit_signal_info(int sig, struct task_struct *t)
struct audit_aux_data_pids *axp;
struct task_struct *tsk = current;
struct audit_context *ctx = tsk->audit_context;
- uid_t uid = current_uid(), t_uid = task_uid(t);
if (audit_pid && t->tgid == audit_pid) {
if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) {
audit_sig_pid = tsk->pid;
- if (tsk->loginuid != -1)
+ if (uid_valid(tsk->loginuid))
audit_sig_uid = tsk->loginuid;
else
- audit_sig_uid = uid;
+ audit_sig_uid = current_uid();
security_task_getsecid(tsk, &audit_sig_sid);
}
if (!audit_signals || audit_dummy_context())
@@ -2566,7 +2567,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
if (!ctx->target_pid) {
ctx->target_pid = t->tgid;
ctx->target_auid = audit_get_loginuid(t);
- ctx->target_uid = t_uid;
+ ctx->target_uid = task_uid(t);
ctx->target_sessionid = audit_get_sessionid(t);
security_task_getsecid(t, &ctx->target_sid);
memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
@@ -2587,7 +2588,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
axp->target_pid[axp->pid_count] = t->tgid;
axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
- axp->target_uid[axp->pid_count] = t_uid;
+ axp->target_uid[axp->pid_count] = task_uid(t);
axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
@@ -2676,9 +2677,10 @@ static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
gid_t gid;
unsigned int sessionid;
- auid = audit_get_loginuid(current);
+ auid = from_kuid(&init_user_ns, audit_get_loginuid(current));
sessionid = audit_get_sessionid(current);
- current_uid_gid(&uid, &gid);
+ uid = from_kuid(&init_user_ns, current_uid());
+ gid = from_kgid(&init_user_ns, current_gid());
audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
auid, uid, gid, sessionid);
diff --git a/net/core/dev.c b/net/core/dev.c
index 026bb4a..1c0d082 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4524,7 +4524,7 @@ static int __dev_set_promiscuity(struct net_device *dev, int inc)
"dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
dev->name, (dev->flags & IFF_PROMISC),
(old_flags & IFF_PROMISC),
- audit_get_loginuid(current),
+ from_kuid(&init_user_ns, audit_get_loginuid(current)),
from_kuid(&init_user_ns, uid),
from_kgid(&init_user_ns, gid),
audit_get_sessionid(current));
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index e7ff694..729a345 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1541,7 +1541,7 @@ int __init netlbl_unlabel_defconf(void)
* it is called is at bootup before the audit subsystem is reporting
* messages so don't worry to much about these values. */
security_task_getsecid(current, &audit_info.secid);
- audit_info.loginuid = 0;
+ audit_info.loginuid = GLOBAL_ROOT_UID;
audit_info.sessionid = 0;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 9fae63f..9650c4a 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -109,7 +109,7 @@ struct audit_buffer *netlbl_audit_start_common(int type,
return NULL;
audit_log_format(audit_buf, "netlabel: auid=%u ses=%u",
- audit_info->loginuid,
+ from_kuid(&init_user_ns, audit_info->loginuid),
audit_info->sessionid);
if (audit_info->secid != 0 &&
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index c5a5165..2f47515 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2630,12 +2630,12 @@ static void xfrm_policy_fini(struct net *net)
flush_work(&net->xfrm.policy_hash_work);
#ifdef CONFIG_XFRM_SUB_POLICY
- audit_info.loginuid = -1;
+ audit_info.loginuid = INVALID_UID;
audit_info.sessionid = -1;
audit_info.secid = 0;
xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info);
#endif
- audit_info.loginuid = -1;
+ audit_info.loginuid = INVALID_UID;
audit_info.sessionid = -1;
audit_info.secid = 0;
xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
@@ -2742,7 +2742,7 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
}
void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
- uid_t auid, u32 sessionid, u32 secid)
+ kuid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
@@ -2757,7 +2757,7 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
- uid_t auid, u32 sessionid, u32 secid)
+ kuid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 5b228f9..fce6a49 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -2045,7 +2045,7 @@ void xfrm_state_fini(struct net *net)
unsigned int sz;
flush_work(&net->xfrm.state_hash_work);
- audit_info.loginuid = -1;
+ audit_info.loginuid = INVALID_UID;
audit_info.sessionid = -1;
audit_info.secid = 0;
xfrm_state_flush(net, IPSEC_PROTO_ANY, &audit_info);
@@ -2112,7 +2112,7 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
}
void xfrm_audit_state_add(struct xfrm_state *x, int result,
- uid_t auid, u32 sessionid, u32 secid)
+ kuid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
@@ -2127,7 +2127,7 @@ void xfrm_audit_state_add(struct xfrm_state *x, int result,
EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
void xfrm_audit_state_delete(struct xfrm_state *x, int result,
- uid_t auid, u32 sessionid, u32 secid)
+ kuid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index e75d8e4..9ea55db 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -575,7 +575,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
struct xfrm_state *x;
int err;
struct km_event c;
- uid_t loginuid = audit_get_loginuid(current);
+ kuid_t loginuid = audit_get_loginuid(current);
u32 sessionid = audit_get_sessionid(current);
u32 sid;
@@ -654,7 +654,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
int err = -ESRCH;
struct km_event c;
struct xfrm_usersa_id *p = nlmsg_data(nlh);
- uid_t loginuid = audit_get_loginuid(current);
+ kuid_t loginuid = audit_get_loginuid(current);
u32 sessionid = audit_get_sessionid(current);
u32 sid;
@@ -1369,7 +1369,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
struct km_event c;
int err;
int excl;
- uid_t loginuid = audit_get_loginuid(current);
+ kuid_t loginuid = audit_get_loginuid(current);
u32 sessionid = audit_get_sessionid(current);
u32 sid;
@@ -1624,7 +1624,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
NETLINK_CB(skb).pid);
}
} else {
- uid_t loginuid = audit_get_loginuid(current);
+ kuid_t loginuid = audit_get_loginuid(current);
u32 sessionid = audit_get_sessionid(current);
u32 sid;
@@ -1918,7 +1918,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
err = 0;
if (up->hard) {
- uid_t loginuid = audit_get_loginuid(current);
+ kuid_t loginuid = audit_get_loginuid(current);
u32 sessionid = audit_get_sessionid(current);
u32 sid;
@@ -1961,7 +1961,7 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
km_state_expired(x, ue->hard, current->pid);
if (ue->hard) {
- uid_t loginuid = audit_get_loginuid(current);
+ kuid_t loginuid = audit_get_loginuid(current);
u32 sessionid = audit_get_sessionid(current);
u32 sid;
--
1.7.5.4
^ permalink raw reply related
* Re: [net-next 10/13] igb: Tidy up wrapping for CONFIG_IGB_PTP.
From: Richard Cochran @ 2012-08-26 13:01 UTC (permalink / raw)
To: Keller, Jacob E
Cc: Ben Hutchings, Vick, Matthew, Kirsher, Jeffrey T,
davem@davemloft.net, netdev@vger.kernel.org, gospo@redhat.com,
sassmann@redhat.com
In-Reply-To: <02874ECE860811409154E81DA85FBB58078591DF@ORSMSX105.amr.corp.intel.com>
On Sun, Aug 26, 2012 at 01:33:42AM +0000, Keller, Jacob E wrote:
>
> IMO it should be but only for parts with HWTSTAMP_FILTER_ALL, and only for that mode (other modes should be ignored) because timestamping only PTP packets is a PTP feature, so this change should still disable other modes if they exist.
Yes, the other Rx modes are PTP specific, and they don't make sense
unless the PTP clock is also enabled.
IIRC, on the Tx side, the 82580 can time stamp any marked packet
regardless of the packet contents, so this should also be always
available, along with HWTSTAMP_FILTER_ALL.
Thanks,
Richard
^ permalink raw reply
* Re: [RFC PATCH] net: Add support for virtual machine device queues (VMDQ)
From: Or Gerlitz @ 2012-08-26 13:11 UTC (permalink / raw)
To: John Fastabend; +Cc: davem, roland, netdev, ali, sean.hefty, shlomop
In-Reply-To: <20120718220544.22619.97136.stgit@i40e.jf1>
On Thu, Jul 19, 2012 at 1:05 AM, John Fastabend
<john.r.fastabend@intel.com> wrote:
> This adds support to allow virtual net devices to be created. These
> devices can be managed independently of the physical function but
> use the same physical link.
>
> This is analogous to an offloaded macvlan device. The primary
> advantage to VMDQ net devices over virtual functions is they can
> be added and removed dynamically as needed.
Hi John,
When VMDQ devices are opened over a virtual function which is
assigned to guest, the design should include a way to apply the
following ndo_set_vf_yyy calls to them
int (*ndo_set_vf_mac)(struct net_device *dev, int vf, u8* mac);
int (*ndo_set_vf_vlan)(struct net_device *dev, int vf, u16 vlan, u8 qos);
int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate);
int (*ndo_set_vf_spoofchk)(struct net_device *dev, int vf, bool setting);
Someone here suggested using a sub-index notation, that is m.n
represents vmdq device index = n on VF index = m where vf.0 is
the non vmdq VF device, makes sense? other thoughts?
Or.
^ permalink raw reply
* Re: [REVIEW][PATCH 09/15] userns: Convert process event connector to handle kuids and kgids
From: Eric W. Biederman @ 2012-08-26 13:43 UTC (permalink / raw)
To: Evgeniy Polyakov
Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
David Miller
In-Reply-To: <20120826123354.GA23803@ioremap.net>
Evgeniy Polyakov <zbr@ioremap.net> writes:
> On Sat, Aug 25, 2012 at 05:02:59PM -0700, Eric W. Biederman (ebiederm@xmission.com) wrote:
>>
>> - Only allow asking for events from the initial user and pid namespace,
>> where we generate the events in.
>>
>> - Convert kuids and kgids into the initial user namespace to report
>> them via the process event connector.
>
>
> Looks good, if IDs are really supposed to be sent only from root
> namespace.
It is more about where events are recevied rather than where events are
sent from.
With this change events continue to be sent from all processes but can
only be received by processes in the initial user and initial pid
namespace.
To processes in other namespaces the uids and pids that the proc
connector code puts into it's messages are just non-sense, so I
cause the registration of connector clients in other namespaces to fail.
All of that I can do easily without a complete reworking of the current
connector code. Which is enough for my current goal of building able
to build a kernel with all features enabled and only loosing features
if you are in somethin other than the initial namespaces.
> And you dropped PROC_EVENTS from init/Kconfig, but since it
> was no, it should be ok by default.
The removal of PROC_EVENTS from init/Kconfig was removing of the compile
guard that kept PROC_EVENTS and USER_NS from being selected at the same
time. The curent user namespace code simply disables code that fails
to build when user namespace support is enabled.
> Feel free to add my acked-by: Evgeniy Polyakov <zbr@ioremap.net>
> Although I thoughs it could be more interesting to generate events
> including namespace id
There isn't a namespace id. It is perfectly possible to generate events
that can be received by processes in multiple pid and user nameapces
just by calling pid_nr_ns() and from_kuid() with the right parameters.
The challenge is figuring out what namespaces have listening netlink
sockets we should send messages to.
Adding support for recepetion of connector proc events by listeners in
other namespaces looks like it would require near complete rewrite of
the connector code:
- Adding support for connector netlink sockets in other than the initial
network namespace.
- Tracking which sockets were opened in which pid and which user
namespaces.
- Filtering messages based on which namespaces the clients are listening
in.
- Generating the different messages for the different sets of clients.
When someone cares enough I am certain the code will get written.
Having a clear unambigous that configuration does not work is
the first step in getting there.
I presume that whatever listens to connector based proc events listens
for the appropriate ack when registering and the daemon will fail to
start up.
Eric
^ permalink raw reply
* Re: [REVIEW][PATCH 0/15] userns subsystem conversions
From: Eric W. Biederman @ 2012-08-26 14:25 UTC (permalink / raw)
To: Vyacheslav Dubeyko
Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
David Miller
In-Reply-To: <9E0E8AAC-9548-4009-AE29-D368244D8EEA@dubeyko.com>
Vyacheslav Dubeyko <slava@dubeyko.com> writes:
> HI,
>
> On Aug 26, 2012, at 3:54 AM, Eric W. Biederman wrote:
>>
>> fs/9p/acl.c | 8 +-
>> fs/btrfs/acl.c | 8 +-
>> fs/configfs/inode.c | 4 +-
>> fs/debugfs/inode.c | 26 +++--
>> fs/ext2/acl.c | 32 ++++--
>> fs/ext3/acl.c | 32 ++++--
>> fs/ext4/acl.c | 31 ++++--
>> fs/generic_acl.c | 4 +-
>> fs/gfs2/acl.c | 14 ++--
>> fs/gfs2/quota.c | 44 +++++---
>> fs/jffs2/acl.c | 4 +-
>> fs/jfs/acl.c | 4 +-
>> fs/jfs/xattr.c | 4 +-
>> fs/nfs/nfs3acl.c | 4 +-
>> fs/nfsd/vfs.c | 8 +-
>> fs/ocfs2/acl.c | 4 +-
>> fs/ocfs2/file.c | 6 +-
>> fs/ocfs2/quota_global.c | 34 +++++--
>> fs/ocfs2/quota_local.c | 12 ++-
>> fs/posix_acl.c | 30 +++---
>> fs/proc/base.c | 12 ++-
>> fs/quota/dquot.c | 43 ++++----
>> fs/quota/netlink.c | 11 ++-
>> fs/quota/quota.c | 44 +++++---
>> fs/quota/quota_tree.c | 20 +++-
>> fs/quota/quota_v1.c | 8 +-
>> fs/quota/quota_v2.c | 14 ++-
>> drivers/connector/cn_proc.c | 18 +++-
>> drivers/gpu/drm/drm_fops.c | 3 +-
>> drivers/gpu/drm/drm_info.c | 5 +-
>> drivers/gpu/drm/drm_ioctl.c | 4 +-
>> drivers/tty/tty_audit.c | 16 ++--
>> fs/9p/acl.c | 8 +-
>> fs/btrfs/acl.c | 8 +-
>> fs/configfs/inode.c | 4 +-
>> fs/debugfs/inode.c | 26 +++--
>> fs/ext2/acl.c | 32 ++++--
>> fs/ext3/acl.c | 32 ++++--
>> fs/ext4/acl.c | 31 ++++--
>> fs/generic_acl.c | 4 +-
>> fs/gfs2/acl.c | 14 ++--
>> fs/gfs2/quota.c | 44 +++++---
>> fs/jffs2/acl.c | 4 +-
>> fs/jfs/acl.c | 4 +-
>> fs/jfs/xattr.c | 4 +-
>> fs/nfs/nfs3acl.c | 4 +-
>> fs/nfsd/vfs.c | 8 +-
>> fs/ocfs2/acl.c | 4 +-
>> fs/ocfs2/file.c | 6 +-
>> fs/ocfs2/quota_global.c | 34 +++++--
>> fs/ocfs2/quota_local.c | 12 ++-
>> fs/posix_acl.c | 30 +++---
>> fs/proc/base.c | 12 ++-
>> fs/quota/dquot.c | 43 ++++----
>> fs/quota/netlink.c | 11 ++-
>> fs/quota/quota.c | 44 +++++---
>> fs/quota/quota_tree.c | 20 +++-
>> fs/quota/quota_v1.c | 8 +-
>> fs/quota/quota_v2.c | 14 ++-
>> fs/reiserfs/xattr_acl.c | 4 +-
>> fs/xattr.c | 7 ++
>> fs/xattr_acl.c | 96 +++++++++++++++--
>> fs/xfs/xfs_acl.c | 4 +-
>> fs/xfs/xfs_quotaops.c | 18 ++--
>> fs/xfs/xfs_trans_dquot.c | 8 +-
>
>
> Sorry, maybe I misunderstand something. But I can't find in the patch
> set changes in concrete filesystems' code.
I assume the problem is patches 6 8 13 and 14 didn't make it through to
the mailling for some reason.
Just to see what is going on I you can look at my development branch
git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git userns-always-map-user-v48
Meanwhile I am going to scratch my head and try and resolve my technical
patch sending difficulties.
Eric
^ permalink raw reply
* [PATCH 0/2]: ieee802154 drivers location
From: Alexander Smirnov @ 2012-08-26 15:10 UTC (permalink / raw)
To: davem; +Cc: netdev, dbaryshkov
Please review these two patches:
1. I want to keep 'ieee802154' drivers with other networking code in
'drivers/net' folder instead of current location in drivers root.
I don't exactly know this historical reason, but lets keep networking
code together.
2. Minor cosmetic improvement in at86rf230 driver
With best regards,
Alex
8<--
Alexander Smirnov (2):
drivers/ieee802154/at86rf230: replace the code under _init and _exit
by macro
drivers/ieee802154: move ieee802154 drivers to net folder
drivers/Makefile | 1 -
drivers/ieee802154/Kconfig | 36 --
drivers/ieee802154/Makefile | 3 -
drivers/ieee802154/at86rf230.c | 968 ------------------------------------
drivers/ieee802154/fakehard.c | 449 -----------------
drivers/ieee802154/fakelb.c | 294 -----------
drivers/net/Kconfig | 4 +-
drivers/net/Makefile | 1 +
drivers/net/ieee802154/Kconfig | 36 ++
drivers/net/ieee802154/Makefile | 3 +
drivers/net/ieee802154/at86rf230.c | 958 +++++++++++++++++++++++++++++++++++
drivers/net/ieee802154/fakehard.c | 449 +++++++++++++++++
drivers/net/ieee802154/fakelb.c | 294 +++++++++++
13 files changed, 1743 insertions(+), 1753 deletions(-)
delete mode 100644 drivers/ieee802154/Kconfig
delete mode 100644 drivers/ieee802154/Makefile
delete mode 100644 drivers/ieee802154/at86rf230.c
delete mode 100644 drivers/ieee802154/fakehard.c
delete mode 100644 drivers/ieee802154/fakelb.c
create mode 100644 drivers/net/ieee802154/Kconfig
create mode 100644 drivers/net/ieee802154/Makefile
create mode 100644 drivers/net/ieee802154/at86rf230.c
create mode 100644 drivers/net/ieee802154/fakehard.c
create mode 100644 drivers/net/ieee802154/fakelb.c
--
1.7.2.3
^ permalink raw reply
* [PATCH 1/2] drivers/ieee802154/at86rf230: replace the code under _init and _exit by macro
From: Alexander Smirnov @ 2012-08-26 15:10 UTC (permalink / raw)
To: davem; +Cc: netdev, dbaryshkov, Alexander Smirnov, Devendra Naga
In-Reply-To: <1345993811-13803-1-git-send-email-alex.bluesman.smirnov@gmail.com>
The code under _init and _exit functions is similar to the code of
module_spi_driver macro, which is a wrapper to the module_driver macro,
so use it instead.
Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
Cc: Devendra Naga <develkernel412222@gmail.com>
---
drivers/ieee802154/at86rf230.c | 12 +-----------
1 files changed, 1 insertions(+), 11 deletions(-)
diff --git a/drivers/ieee802154/at86rf230.c b/drivers/ieee802154/at86rf230.c
index 5d30940..ba753d8 100644
--- a/drivers/ieee802154/at86rf230.c
+++ b/drivers/ieee802154/at86rf230.c
@@ -952,17 +952,7 @@ static struct spi_driver at86rf230_driver = {
.resume = at86rf230_resume,
};
-static int __init at86rf230_init(void)
-{
- return spi_register_driver(&at86rf230_driver);
-}
-module_init(at86rf230_init);
-
-static void __exit at86rf230_exit(void)
-{
- spi_unregister_driver(&at86rf230_driver);
-}
-module_exit(at86rf230_exit);
+module_spi_driver(at86rf230_driver);
MODULE_DESCRIPTION("AT86RF230 Transceiver Driver");
MODULE_LICENSE("GPL v2");
--
1.7.2.3
^ permalink raw reply related
* [PATCH 2/2] drivers/ieee802154: move ieee802154 drivers to net folder
From: Alexander Smirnov @ 2012-08-26 15:10 UTC (permalink / raw)
To: davem; +Cc: netdev, dbaryshkov, Alexander Smirnov
In-Reply-To: <1345993811-13803-1-git-send-email-alex.bluesman.smirnov@gmail.com>
The IEEE 802.15.4 standard represents a networking protocol. I don't
exactly know why drivers for this protocol are stored into the root
'driver' folder, but better will be to store them with other
networking stuff. Currently there are only 3 drivers available for
IEEE 802.15.4 stack, so lets do it now with the smallest overhead.
Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
---
drivers/Makefile | 1 -
drivers/ieee802154/Kconfig | 36 --
drivers/ieee802154/Makefile | 3 -
drivers/ieee802154/at86rf230.c | 958 ------------------------------------
drivers/ieee802154/fakehard.c | 449 -----------------
drivers/ieee802154/fakelb.c | 294 -----------
drivers/net/Kconfig | 4 +-
drivers/net/Makefile | 1 +
drivers/net/ieee802154/Kconfig | 36 ++
drivers/net/ieee802154/Makefile | 3 +
drivers/net/ieee802154/at86rf230.c | 958 ++++++++++++++++++++++++++++++++++++
drivers/net/ieee802154/fakehard.c | 449 +++++++++++++++++
drivers/net/ieee802154/fakelb.c | 294 +++++++++++
13 files changed, 1743 insertions(+), 1743 deletions(-)
delete mode 100644 drivers/ieee802154/Kconfig
delete mode 100644 drivers/ieee802154/Makefile
delete mode 100644 drivers/ieee802154/at86rf230.c
delete mode 100644 drivers/ieee802154/fakehard.c
delete mode 100644 drivers/ieee802154/fakelb.c
create mode 100644 drivers/net/ieee802154/Kconfig
create mode 100644 drivers/net/ieee802154/Makefile
create mode 100644 drivers/net/ieee802154/at86rf230.c
create mode 100644 drivers/net/ieee802154/fakehard.c
create mode 100644 drivers/net/ieee802154/fakelb.c
diff --git a/drivers/Makefile b/drivers/Makefile
index 5b42184..1ecd1bf 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -120,7 +120,6 @@ obj-$(CONFIG_VHOST_NET) += vhost/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
obj-y += platform/
-obj-y += ieee802154/
#common clk code
obj-y += clk/
diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig
deleted file mode 100644
index 1fc4eef..0000000
--- a/drivers/ieee802154/Kconfig
+++ /dev/null
@@ -1,36 +0,0 @@
-menuconfig IEEE802154_DRIVERS
- tristate "IEEE 802.15.4 drivers"
- depends on NETDEVICES && IEEE802154
- default y
- ---help---
- Say Y here to get to see options for IEEE 802.15.4 Low-Rate
- Wireless Personal Area Network device drivers. This option alone
- does not add any kernel code.
-
- If you say N, all options in this submenu will be skipped and
- disabled.
-
-config IEEE802154_FAKEHARD
- tristate "Fake LR-WPAN driver with several interconnected devices"
- depends on IEEE802154_DRIVERS
- ---help---
- Say Y here to enable the fake driver that serves as an example
- of HardMAC device driver.
-
- This driver can also be built as a module. To do so say M here.
- The module will be called 'fakehard'.
-
-config IEEE802154_FAKELB
- depends on IEEE802154_DRIVERS && MAC802154
- tristate "IEEE 802.15.4 loopback driver"
- ---help---
- Say Y here to enable the fake driver that can emulate a net
- of several interconnected radio devices.
-
- This driver can also be built as a module. To do so say M here.
- The module will be called 'fakelb'.
-
-config IEEE802154_AT86RF230
- depends on IEEE802154_DRIVERS && MAC802154
- tristate "AT86RF230/231 transceiver driver"
- depends on SPI
diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile
deleted file mode 100644
index 4f4371d..0000000
--- a/drivers/ieee802154/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
-obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
-obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
diff --git a/drivers/ieee802154/at86rf230.c b/drivers/ieee802154/at86rf230.c
deleted file mode 100644
index ba753d8..0000000
--- a/drivers/ieee802154/at86rf230.c
+++ /dev/null
@@ -1,958 +0,0 @@
-/*
- * AT86RF230/RF231 driver
- *
- * Copyright (C) 2009-2012 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Written by:
- * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/workqueue.h>
-#include <linux/spinlock.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/at86rf230.h>
-#include <linux/skbuff.h>
-
-#include <net/mac802154.h>
-#include <net/wpan-phy.h>
-
-struct at86rf230_local {
- struct spi_device *spi;
- int rstn, slp_tr, dig2;
-
- u8 part;
- u8 vers;
-
- u8 buf[2];
- struct mutex bmux;
-
- struct work_struct irqwork;
- struct completion tx_complete;
-
- struct ieee802154_dev *dev;
-
- spinlock_t lock;
- bool irq_disabled;
- bool is_tx;
-};
-
-#define RG_TRX_STATUS (0x01)
-#define SR_TRX_STATUS 0x01, 0x1f, 0
-#define SR_RESERVED_01_3 0x01, 0x20, 5
-#define SR_CCA_STATUS 0x01, 0x40, 6
-#define SR_CCA_DONE 0x01, 0x80, 7
-#define RG_TRX_STATE (0x02)
-#define SR_TRX_CMD 0x02, 0x1f, 0
-#define SR_TRAC_STATUS 0x02, 0xe0, 5
-#define RG_TRX_CTRL_0 (0x03)
-#define SR_CLKM_CTRL 0x03, 0x07, 0
-#define SR_CLKM_SHA_SEL 0x03, 0x08, 3
-#define SR_PAD_IO_CLKM 0x03, 0x30, 4
-#define SR_PAD_IO 0x03, 0xc0, 6
-#define RG_TRX_CTRL_1 (0x04)
-#define SR_IRQ_POLARITY 0x04, 0x01, 0
-#define SR_IRQ_MASK_MODE 0x04, 0x02, 1
-#define SR_SPI_CMD_MODE 0x04, 0x0c, 2
-#define SR_RX_BL_CTRL 0x04, 0x10, 4
-#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5
-#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6
-#define SR_PA_EXT_EN 0x04, 0x80, 7
-#define RG_PHY_TX_PWR (0x05)
-#define SR_TX_PWR 0x05, 0x0f, 0
-#define SR_PA_LT 0x05, 0x30, 4
-#define SR_PA_BUF_LT 0x05, 0xc0, 6
-#define RG_PHY_RSSI (0x06)
-#define SR_RSSI 0x06, 0x1f, 0
-#define SR_RND_VALUE 0x06, 0x60, 5
-#define SR_RX_CRC_VALID 0x06, 0x80, 7
-#define RG_PHY_ED_LEVEL (0x07)
-#define SR_ED_LEVEL 0x07, 0xff, 0
-#define RG_PHY_CC_CCA (0x08)
-#define SR_CHANNEL 0x08, 0x1f, 0
-#define SR_CCA_MODE 0x08, 0x60, 5
-#define SR_CCA_REQUEST 0x08, 0x80, 7
-#define RG_CCA_THRES (0x09)
-#define SR_CCA_ED_THRES 0x09, 0x0f, 0
-#define SR_RESERVED_09_1 0x09, 0xf0, 4
-#define RG_RX_CTRL (0x0a)
-#define SR_PDT_THRES 0x0a, 0x0f, 0
-#define SR_RESERVED_0a_1 0x0a, 0xf0, 4
-#define RG_SFD_VALUE (0x0b)
-#define SR_SFD_VALUE 0x0b, 0xff, 0
-#define RG_TRX_CTRL_2 (0x0c)
-#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0
-#define SR_RESERVED_0c_2 0x0c, 0x7c, 2
-#define SR_RX_SAFE_MODE 0x0c, 0x80, 7
-#define RG_ANT_DIV (0x0d)
-#define SR_ANT_CTRL 0x0d, 0x03, 0
-#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2
-#define SR_ANT_DIV_EN 0x0d, 0x08, 3
-#define SR_RESERVED_0d_2 0x0d, 0x70, 4
-#define SR_ANT_SEL 0x0d, 0x80, 7
-#define RG_IRQ_MASK (0x0e)
-#define SR_IRQ_MASK 0x0e, 0xff, 0
-#define RG_IRQ_STATUS (0x0f)
-#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0
-#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1
-#define SR_IRQ_2_RX_START 0x0f, 0x04, 2
-#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3
-#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4
-#define SR_IRQ_5_AMI 0x0f, 0x20, 5
-#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6
-#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7
-#define RG_VREG_CTRL (0x10)
-#define SR_RESERVED_10_6 0x10, 0x03, 0
-#define SR_DVDD_OK 0x10, 0x04, 2
-#define SR_DVREG_EXT 0x10, 0x08, 3
-#define SR_RESERVED_10_3 0x10, 0x30, 4
-#define SR_AVDD_OK 0x10, 0x40, 6
-#define SR_AVREG_EXT 0x10, 0x80, 7
-#define RG_BATMON (0x11)
-#define SR_BATMON_VTH 0x11, 0x0f, 0
-#define SR_BATMON_HR 0x11, 0x10, 4
-#define SR_BATMON_OK 0x11, 0x20, 5
-#define SR_RESERVED_11_1 0x11, 0xc0, 6
-#define RG_XOSC_CTRL (0x12)
-#define SR_XTAL_TRIM 0x12, 0x0f, 0
-#define SR_XTAL_MODE 0x12, 0xf0, 4
-#define RG_RX_SYN (0x15)
-#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0
-#define SR_RESERVED_15_2 0x15, 0x70, 4
-#define SR_RX_PDT_DIS 0x15, 0x80, 7
-#define RG_XAH_CTRL_1 (0x17)
-#define SR_RESERVED_17_8 0x17, 0x01, 0
-#define SR_AACK_PROM_MODE 0x17, 0x02, 1
-#define SR_AACK_ACK_TIME 0x17, 0x04, 2
-#define SR_RESERVED_17_5 0x17, 0x08, 3
-#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4
-#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5
-#define SR_RESERVED_17_2 0x17, 0x40, 6
-#define SR_RESERVED_17_1 0x17, 0x80, 7
-#define RG_FTN_CTRL (0x18)
-#define SR_RESERVED_18_2 0x18, 0x7f, 0
-#define SR_FTN_START 0x18, 0x80, 7
-#define RG_PLL_CF (0x1a)
-#define SR_RESERVED_1a_2 0x1a, 0x7f, 0
-#define SR_PLL_CF_START 0x1a, 0x80, 7
-#define RG_PLL_DCU (0x1b)
-#define SR_RESERVED_1b_3 0x1b, 0x3f, 0
-#define SR_RESERVED_1b_2 0x1b, 0x40, 6
-#define SR_PLL_DCU_START 0x1b, 0x80, 7
-#define RG_PART_NUM (0x1c)
-#define SR_PART_NUM 0x1c, 0xff, 0
-#define RG_VERSION_NUM (0x1d)
-#define SR_VERSION_NUM 0x1d, 0xff, 0
-#define RG_MAN_ID_0 (0x1e)
-#define SR_MAN_ID_0 0x1e, 0xff, 0
-#define RG_MAN_ID_1 (0x1f)
-#define SR_MAN_ID_1 0x1f, 0xff, 0
-#define RG_SHORT_ADDR_0 (0x20)
-#define SR_SHORT_ADDR_0 0x20, 0xff, 0
-#define RG_SHORT_ADDR_1 (0x21)
-#define SR_SHORT_ADDR_1 0x21, 0xff, 0
-#define RG_PAN_ID_0 (0x22)
-#define SR_PAN_ID_0 0x22, 0xff, 0
-#define RG_PAN_ID_1 (0x23)
-#define SR_PAN_ID_1 0x23, 0xff, 0
-#define RG_IEEE_ADDR_0 (0x24)
-#define SR_IEEE_ADDR_0 0x24, 0xff, 0
-#define RG_IEEE_ADDR_1 (0x25)
-#define SR_IEEE_ADDR_1 0x25, 0xff, 0
-#define RG_IEEE_ADDR_2 (0x26)
-#define SR_IEEE_ADDR_2 0x26, 0xff, 0
-#define RG_IEEE_ADDR_3 (0x27)
-#define SR_IEEE_ADDR_3 0x27, 0xff, 0
-#define RG_IEEE_ADDR_4 (0x28)
-#define SR_IEEE_ADDR_4 0x28, 0xff, 0
-#define RG_IEEE_ADDR_5 (0x29)
-#define SR_IEEE_ADDR_5 0x29, 0xff, 0
-#define RG_IEEE_ADDR_6 (0x2a)
-#define SR_IEEE_ADDR_6 0x2a, 0xff, 0
-#define RG_IEEE_ADDR_7 (0x2b)
-#define SR_IEEE_ADDR_7 0x2b, 0xff, 0
-#define RG_XAH_CTRL_0 (0x2c)
-#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0
-#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1
-#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4
-#define RG_CSMA_SEED_0 (0x2d)
-#define SR_CSMA_SEED_0 0x2d, 0xff, 0
-#define RG_CSMA_SEED_1 (0x2e)
-#define SR_CSMA_SEED_1 0x2e, 0x07, 0
-#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3
-#define SR_AACK_DIS_ACK 0x2e, 0x10, 4
-#define SR_AACK_SET_PD 0x2e, 0x20, 5
-#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6
-#define RG_CSMA_BE (0x2f)
-#define SR_MIN_BE 0x2f, 0x0f, 0
-#define SR_MAX_BE 0x2f, 0xf0, 4
-
-#define CMD_REG 0x80
-#define CMD_REG_MASK 0x3f
-#define CMD_WRITE 0x40
-#define CMD_FB 0x20
-
-#define IRQ_BAT_LOW (1 << 7)
-#define IRQ_TRX_UR (1 << 6)
-#define IRQ_AMI (1 << 5)
-#define IRQ_CCA_ED (1 << 4)
-#define IRQ_TRX_END (1 << 3)
-#define IRQ_RX_START (1 << 2)
-#define IRQ_PLL_UNL (1 << 1)
-#define IRQ_PLL_LOCK (1 << 0)
-
-#define STATE_P_ON 0x00 /* BUSY */
-#define STATE_BUSY_RX 0x01
-#define STATE_BUSY_TX 0x02
-#define STATE_FORCE_TRX_OFF 0x03
-#define STATE_FORCE_TX_ON 0x04 /* IDLE */
-/* 0x05 */ /* INVALID_PARAMETER */
-#define STATE_RX_ON 0x06
-/* 0x07 */ /* SUCCESS */
-#define STATE_TRX_OFF 0x08
-#define STATE_TX_ON 0x09
-/* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */
-#define STATE_SLEEP 0x0F
-#define STATE_BUSY_RX_AACK 0x11
-#define STATE_BUSY_TX_ARET 0x12
-#define STATE_BUSY_RX_AACK_ON 0x16
-#define STATE_BUSY_TX_ARET_ON 0x19
-#define STATE_RX_ON_NOCLK 0x1C
-#define STATE_RX_AACK_ON_NOCLK 0x1D
-#define STATE_BUSY_RX_AACK_NOCLK 0x1E
-#define STATE_TRANSITION_IN_PROGRESS 0x1F
-
-static int
-__at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data)
-{
- u8 *buf = lp->buf;
- int status;
- struct spi_message msg;
- struct spi_transfer xfer = {
- .len = 2,
- .tx_buf = buf,
- };
-
- buf[0] = (addr & CMD_REG_MASK) | CMD_REG | CMD_WRITE;
- buf[1] = data;
- dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
- dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- status = spi_sync(lp->spi, &msg);
- dev_vdbg(&lp->spi->dev, "status = %d\n", status);
- if (msg.status)
- status = msg.status;
-
- dev_vdbg(&lp->spi->dev, "status = %d\n", status);
- dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
- dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
-
- return status;
-}
-
-static int
-__at86rf230_read_subreg(struct at86rf230_local *lp,
- u8 addr, u8 mask, int shift, u8 *data)
-{
- u8 *buf = lp->buf;
- int status;
- struct spi_message msg;
- struct spi_transfer xfer = {
- .len = 2,
- .tx_buf = buf,
- .rx_buf = buf,
- };
-
- buf[0] = (addr & CMD_REG_MASK) | CMD_REG;
- buf[1] = 0xff;
- dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
- spi_message_init(&msg);
- spi_message_add_tail(&xfer, &msg);
-
- status = spi_sync(lp->spi, &msg);
- dev_vdbg(&lp->spi->dev, "status = %d\n", status);
- if (msg.status)
- status = msg.status;
-
- dev_vdbg(&lp->spi->dev, "status = %d\n", status);
- dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
- dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
-
- if (status == 0)
- *data = buf[1];
-
- return status;
-}
-
-static int
-at86rf230_read_subreg(struct at86rf230_local *lp,
- u8 addr, u8 mask, int shift, u8 *data)
-{
- int status;
-
- mutex_lock(&lp->bmux);
- status = __at86rf230_read_subreg(lp, addr, mask, shift, data);
- mutex_unlock(&lp->bmux);
-
- return status;
-}
-
-static int
-at86rf230_write_subreg(struct at86rf230_local *lp,
- u8 addr, u8 mask, int shift, u8 data)
-{
- int status;
- u8 val;
-
- mutex_lock(&lp->bmux);
- status = __at86rf230_read_subreg(lp, addr, 0xff, 0, &val);
- if (status)
- goto out;
-
- val &= ~mask;
- val |= (data << shift) & mask;
-
- status = __at86rf230_write(lp, addr, val);
-out:
- mutex_unlock(&lp->bmux);
-
- return status;
-}
-
-static int
-at86rf230_write_fbuf(struct at86rf230_local *lp, u8 *data, u8 len)
-{
- u8 *buf = lp->buf;
- int status;
- struct spi_message msg;
- struct spi_transfer xfer_head = {
- .len = 2,
- .tx_buf = buf,
-
- };
- struct spi_transfer xfer_buf = {
- .len = len,
- .tx_buf = data,
- };
-
- mutex_lock(&lp->bmux);
- buf[0] = CMD_WRITE | CMD_FB;
- buf[1] = len + 2; /* 2 bytes for CRC that isn't written */
-
- dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
- dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer_head, &msg);
- spi_message_add_tail(&xfer_buf, &msg);
-
- status = spi_sync(lp->spi, &msg);
- dev_vdbg(&lp->spi->dev, "status = %d\n", status);
- if (msg.status)
- status = msg.status;
-
- dev_vdbg(&lp->spi->dev, "status = %d\n", status);
- dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
- dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
-
- mutex_unlock(&lp->bmux);
- return status;
-}
-
-static int
-at86rf230_read_fbuf(struct at86rf230_local *lp, u8 *data, u8 *len, u8 *lqi)
-{
- u8 *buf = lp->buf;
- int status;
- struct spi_message msg;
- struct spi_transfer xfer_head = {
- .len = 2,
- .tx_buf = buf,
- .rx_buf = buf,
- };
- struct spi_transfer xfer_head1 = {
- .len = 2,
- .tx_buf = buf,
- .rx_buf = buf,
- };
- struct spi_transfer xfer_buf = {
- .len = 0,
- .rx_buf = data,
- };
-
- mutex_lock(&lp->bmux);
-
- buf[0] = CMD_FB;
- buf[1] = 0x00;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer_head, &msg);
-
- status = spi_sync(lp->spi, &msg);
- dev_vdbg(&lp->spi->dev, "status = %d\n", status);
-
- xfer_buf.len = *(buf + 1) + 1;
- *len = buf[1];
-
- buf[0] = CMD_FB;
- buf[1] = 0x00;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfer_head1, &msg);
- spi_message_add_tail(&xfer_buf, &msg);
-
- status = spi_sync(lp->spi, &msg);
-
- if (msg.status)
- status = msg.status;
-
- dev_vdbg(&lp->spi->dev, "status = %d\n", status);
- dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
- dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
-
- if (status) {
- if (lqi && (*len > lp->buf[1]))
- *lqi = data[lp->buf[1]];
- }
- mutex_unlock(&lp->bmux);
-
- return status;
-}
-
-static int
-at86rf230_ed(struct ieee802154_dev *dev, u8 *level)
-{
- might_sleep();
- BUG_ON(!level);
- *level = 0xbe;
- return 0;
-}
-
-static int
-at86rf230_state(struct ieee802154_dev *dev, int state)
-{
- struct at86rf230_local *lp = dev->priv;
- int rc;
- u8 val;
- u8 desired_status;
-
- might_sleep();
-
- if (state == STATE_FORCE_TX_ON)
- desired_status = STATE_TX_ON;
- else if (state == STATE_FORCE_TRX_OFF)
- desired_status = STATE_TRX_OFF;
- else
- desired_status = state;
-
- do {
- rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
- if (rc)
- goto err;
- } while (val == STATE_TRANSITION_IN_PROGRESS);
-
- if (val == desired_status)
- return 0;
-
- /* state is equal to phy states */
- rc = at86rf230_write_subreg(lp, SR_TRX_CMD, state);
- if (rc)
- goto err;
-
- do {
- rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
- if (rc)
- goto err;
- } while (val == STATE_TRANSITION_IN_PROGRESS);
-
-
- if (val == desired_status)
- return 0;
-
- pr_err("unexpected state change: %d, asked for %d\n", val, state);
- return -EBUSY;
-
-err:
- pr_err("error: %d\n", rc);
- return rc;
-}
-
-static int
-at86rf230_start(struct ieee802154_dev *dev)
-{
- struct at86rf230_local *lp = dev->priv;
- u8 rc;
-
- rc = at86rf230_write_subreg(lp, SR_RX_SAFE_MODE, 1);
- if (rc)
- return rc;
-
- return at86rf230_state(dev, STATE_RX_ON);
-}
-
-static void
-at86rf230_stop(struct ieee802154_dev *dev)
-{
- at86rf230_state(dev, STATE_FORCE_TRX_OFF);
-}
-
-static int
-at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
-{
- struct at86rf230_local *lp = dev->priv;
- int rc;
-
- might_sleep();
-
- if (page != 0 || channel < 11 || channel > 26) {
- WARN_ON(1);
- return -EINVAL;
- }
-
- rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel);
- msleep(1); /* Wait for PLL */
- dev->phy->current_channel = channel;
-
- return 0;
-}
-
-static int
-at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
-{
- struct at86rf230_local *lp = dev->priv;
- int rc;
- unsigned long flags;
-
- spin_lock(&lp->lock);
- if (lp->irq_disabled) {
- spin_unlock(&lp->lock);
- return -EBUSY;
- }
- spin_unlock(&lp->lock);
-
- might_sleep();
-
- rc = at86rf230_state(dev, STATE_FORCE_TX_ON);
- if (rc)
- goto err;
-
- spin_lock_irqsave(&lp->lock, flags);
- lp->is_tx = 1;
- INIT_COMPLETION(lp->tx_complete);
- spin_unlock_irqrestore(&lp->lock, flags);
-
- rc = at86rf230_write_fbuf(lp, skb->data, skb->len);
- if (rc)
- goto err_rx;
-
- rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX);
- if (rc)
- goto err_rx;
-
- rc = wait_for_completion_interruptible(&lp->tx_complete);
- if (rc < 0)
- goto err_rx;
-
- rc = at86rf230_start(dev);
-
- return rc;
-
-err_rx:
- at86rf230_start(dev);
-err:
- pr_err("error: %d\n", rc);
-
- spin_lock_irqsave(&lp->lock, flags);
- lp->is_tx = 0;
- spin_unlock_irqrestore(&lp->lock, flags);
-
- return rc;
-}
-
-static int at86rf230_rx(struct at86rf230_local *lp)
-{
- u8 len = 128, lqi = 0;
- struct sk_buff *skb;
-
- skb = alloc_skb(len, GFP_KERNEL);
-
- if (!skb)
- return -ENOMEM;
-
- if (at86rf230_read_fbuf(lp, skb_put(skb, len), &len, &lqi))
- goto err;
-
- if (len < 2)
- goto err;
-
- skb_trim(skb, len - 2); /* We do not put CRC into the frame */
-
- ieee802154_rx_irqsafe(lp->dev, skb, lqi);
-
- dev_dbg(&lp->spi->dev, "READ_FBUF: %d %x\n", len, lqi);
-
- return 0;
-err:
- pr_debug("received frame is too small\n");
-
- kfree_skb(skb);
- return -EINVAL;
-}
-
-static struct ieee802154_ops at86rf230_ops = {
- .owner = THIS_MODULE,
- .xmit = at86rf230_xmit,
- .ed = at86rf230_ed,
- .set_channel = at86rf230_channel,
- .start = at86rf230_start,
- .stop = at86rf230_stop,
-};
-
-static void at86rf230_irqwork(struct work_struct *work)
-{
- struct at86rf230_local *lp =
- container_of(work, struct at86rf230_local, irqwork);
- u8 status = 0, val;
- int rc;
- unsigned long flags;
-
- rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &val);
- status |= val;
-
- status &= ~IRQ_PLL_LOCK; /* ignore */
- status &= ~IRQ_RX_START; /* ignore */
- status &= ~IRQ_AMI; /* ignore */
- status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/
-
- if (status & IRQ_TRX_END) {
- spin_lock_irqsave(&lp->lock, flags);
- status &= ~IRQ_TRX_END;
- if (lp->is_tx) {
- lp->is_tx = 0;
- spin_unlock_irqrestore(&lp->lock, flags);
- complete(&lp->tx_complete);
- } else {
- spin_unlock_irqrestore(&lp->lock, flags);
- at86rf230_rx(lp);
- }
- }
-
- spin_lock_irqsave(&lp->lock, flags);
- lp->irq_disabled = 0;
- spin_unlock_irqrestore(&lp->lock, flags);
-
- enable_irq(lp->spi->irq);
-}
-
-static irqreturn_t at86rf230_isr(int irq, void *data)
-{
- struct at86rf230_local *lp = data;
-
- disable_irq_nosync(irq);
-
- spin_lock(&lp->lock);
- lp->irq_disabled = 1;
- spin_unlock(&lp->lock);
-
- schedule_work(&lp->irqwork);
-
- return IRQ_HANDLED;
-}
-
-
-static int at86rf230_hw_init(struct at86rf230_local *lp)
-{
- u8 status;
- int rc;
-
- rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
- if (rc)
- return rc;
-
- dev_info(&lp->spi->dev, "Status: %02x\n", status);
- if (status == STATE_P_ON) {
- rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF);
- if (rc)
- return rc;
- msleep(1);
- rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
- if (rc)
- return rc;
- dev_info(&lp->spi->dev, "Status: %02x\n", status);
- }
-
- rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, 0xff); /* IRQ_TRX_UR |
- * IRQ_CCA_ED |
- * IRQ_TRX_END |
- * IRQ_PLL_UNL |
- * IRQ_PLL_LOCK
- */
- if (rc)
- return rc;
-
- /* CLKM changes are applied immediately */
- rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00);
- if (rc)
- return rc;
-
- /* Turn CLKM Off */
- rc = at86rf230_write_subreg(lp, SR_CLKM_CTRL, 0x00);
- if (rc)
- return rc;
- /* Wait the next SLEEP cycle */
- msleep(100);
-
- rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON);
- if (rc)
- return rc;
- msleep(1);
-
- rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
- if (rc)
- return rc;
- dev_info(&lp->spi->dev, "Status: %02x\n", status);
-
- rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status);
- if (rc)
- return rc;
- if (!status) {
- dev_err(&lp->spi->dev, "DVDD error\n");
- return -EINVAL;
- }
-
- rc = at86rf230_read_subreg(lp, SR_AVDD_OK, &status);
- if (rc)
- return rc;
- if (!status) {
- dev_err(&lp->spi->dev, "AVDD error\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int at86rf230_suspend(struct spi_device *spi, pm_message_t message)
-{
- return 0;
-}
-
-static int at86rf230_resume(struct spi_device *spi)
-{
- return 0;
-}
-
-static int at86rf230_fill_data(struct spi_device *spi)
-{
- struct at86rf230_local *lp = spi_get_drvdata(spi);
- struct at86rf230_platform_data *pdata = spi->dev.platform_data;
-
- if (!pdata) {
- dev_err(&spi->dev, "no platform_data\n");
- return -EINVAL;
- }
-
- lp->rstn = pdata->rstn;
- lp->slp_tr = pdata->slp_tr;
- lp->dig2 = pdata->dig2;
-
- return 0;
-}
-
-static int __devinit at86rf230_probe(struct spi_device *spi)
-{
- struct ieee802154_dev *dev;
- struct at86rf230_local *lp;
- u8 man_id_0, man_id_1;
- int rc;
- const char *chip;
- int supported = 0;
-
- if (!spi->irq) {
- dev_err(&spi->dev, "no IRQ specified\n");
- return -EINVAL;
- }
-
- dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops);
- if (!dev)
- return -ENOMEM;
-
- lp = dev->priv;
- lp->dev = dev;
-
- lp->spi = spi;
-
- dev->priv = lp;
- dev->parent = &spi->dev;
- dev->extra_tx_headroom = 0;
- /* We do support only 2.4 Ghz */
- dev->phy->channels_supported[0] = 0x7FFF800;
- dev->flags = IEEE802154_HW_OMIT_CKSUM;
-
- mutex_init(&lp->bmux);
- INIT_WORK(&lp->irqwork, at86rf230_irqwork);
- spin_lock_init(&lp->lock);
- init_completion(&lp->tx_complete);
-
- spi_set_drvdata(spi, lp);
-
- rc = at86rf230_fill_data(spi);
- if (rc)
- goto err_fill;
-
- rc = gpio_request(lp->rstn, "rstn");
- if (rc)
- goto err_rstn;
-
- if (gpio_is_valid(lp->slp_tr)) {
- rc = gpio_request(lp->slp_tr, "slp_tr");
- if (rc)
- goto err_slp_tr;
- }
-
- rc = gpio_direction_output(lp->rstn, 1);
- if (rc)
- goto err_gpio_dir;
-
- if (gpio_is_valid(lp->slp_tr)) {
- rc = gpio_direction_output(lp->slp_tr, 0);
- if (rc)
- goto err_gpio_dir;
- }
-
- /* Reset */
- msleep(1);
- gpio_set_value(lp->rstn, 0);
- msleep(1);
- gpio_set_value(lp->rstn, 1);
- msleep(1);
-
- rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0);
- if (rc)
- goto err_gpio_dir;
- rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1);
- if (rc)
- goto err_gpio_dir;
-
- if (man_id_1 != 0x00 || man_id_0 != 0x1f) {
- dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n",
- man_id_1, man_id_0);
- rc = -EINVAL;
- goto err_gpio_dir;
- }
-
- rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part);
- if (rc)
- goto err_gpio_dir;
-
- rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers);
- if (rc)
- goto err_gpio_dir;
-
- switch (lp->part) {
- case 2:
- chip = "at86rf230";
- /* supported = 1; FIXME: should be easy to support; */
- break;
- case 3:
- chip = "at86rf231";
- supported = 1;
- break;
- default:
- chip = "UNKNOWN";
- break;
- }
-
- dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers);
- if (!supported) {
- rc = -ENOTSUPP;
- goto err_gpio_dir;
- }
-
- rc = at86rf230_hw_init(lp);
- if (rc)
- goto err_gpio_dir;
-
- rc = request_irq(spi->irq, at86rf230_isr, IRQF_SHARED,
- dev_name(&spi->dev), lp);
- if (rc)
- goto err_gpio_dir;
-
- rc = ieee802154_register_device(lp->dev);
- if (rc)
- goto err_irq;
-
- return rc;
-
- ieee802154_unregister_device(lp->dev);
-err_irq:
- free_irq(spi->irq, lp);
- flush_work(&lp->irqwork);
-err_gpio_dir:
- if (gpio_is_valid(lp->slp_tr))
- gpio_free(lp->slp_tr);
-err_slp_tr:
- gpio_free(lp->rstn);
-err_rstn:
-err_fill:
- spi_set_drvdata(spi, NULL);
- mutex_destroy(&lp->bmux);
- ieee802154_free_device(lp->dev);
- return rc;
-}
-
-static int __devexit at86rf230_remove(struct spi_device *spi)
-{
- struct at86rf230_local *lp = spi_get_drvdata(spi);
-
- ieee802154_unregister_device(lp->dev);
-
- free_irq(spi->irq, lp);
- flush_work(&lp->irqwork);
-
- if (gpio_is_valid(lp->slp_tr))
- gpio_free(lp->slp_tr);
- gpio_free(lp->rstn);
-
- spi_set_drvdata(spi, NULL);
- mutex_destroy(&lp->bmux);
- ieee802154_free_device(lp->dev);
-
- dev_dbg(&spi->dev, "unregistered at86rf230\n");
- return 0;
-}
-
-static struct spi_driver at86rf230_driver = {
- .driver = {
- .name = "at86rf230",
- .owner = THIS_MODULE,
- },
- .probe = at86rf230_probe,
- .remove = __devexit_p(at86rf230_remove),
- .suspend = at86rf230_suspend,
- .resume = at86rf230_resume,
-};
-
-module_spi_driver(at86rf230_driver);
-
-MODULE_DESCRIPTION("AT86RF230 Transceiver Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c
deleted file mode 100644
index 73d4531..0000000
--- a/drivers/ieee802154/fakehard.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Sample driver for HardMAC IEEE 802.15.4 devices
- *
- * Copyright (C) 2009 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Written by:
- * Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-
-#include <net/af_ieee802154.h>
-#include <net/ieee802154_netdev.h>
-#include <net/ieee802154.h>
-#include <net/nl802154.h>
-#include <net/wpan-phy.h>
-
-struct fakehard_priv {
- struct wpan_phy *phy;
-};
-
-static struct wpan_phy *fake_to_phy(const struct net_device *dev)
-{
- struct fakehard_priv *priv = netdev_priv(dev);
- return priv->phy;
-}
-
-/**
- * fake_get_phy - Return a phy corresponding to this device.
- * @dev: The network device for which to return the wan-phy object
- *
- * This function returns a wpan-phy object corresponding to the passed
- * network device. Reference counter for wpan-phy object is incremented,
- * so when the wpan-phy isn't necessary, you should drop the reference
- * via @wpan_phy_put() call.
- */
-static struct wpan_phy *fake_get_phy(const struct net_device *dev)
-{
- struct wpan_phy *phy = fake_to_phy(dev);
- return to_phy(get_device(&phy->dev));
-}
-
-/**
- * fake_get_pan_id - Retrieve the PAN ID of the device.
- * @dev: The network device to retrieve the PAN of.
- *
- * Return the ID of the PAN from the PIB.
- */
-static u16 fake_get_pan_id(const struct net_device *dev)
-{
- BUG_ON(dev->type != ARPHRD_IEEE802154);
-
- return 0xeba1;
-}
-
-/**
- * fake_get_short_addr - Retrieve the short address of the device.
- * @dev: The network device to retrieve the short address of.
- *
- * Returns the IEEE 802.15.4 short-form address cached for this
- * device. If the device has not yet had a short address assigned
- * then this should return 0xFFFF to indicate a lack of association.
- */
-static u16 fake_get_short_addr(const struct net_device *dev)
-{
- BUG_ON(dev->type != ARPHRD_IEEE802154);
-
- return 0x1;
-}
-
-/**
- * fake_get_dsn - Retrieve the DSN of the device.
- * @dev: The network device to retrieve the DSN for.
- *
- * Returns the IEEE 802.15.4 DSN for the network device.
- * The DSN is the sequence number which will be added to each
- * packet or MAC command frame by the MAC during transmission.
- *
- * DSN means 'Data Sequence Number'.
- *
- * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
- * document.
- */
-static u8 fake_get_dsn(const struct net_device *dev)
-{
- BUG_ON(dev->type != ARPHRD_IEEE802154);
-
- return 0x00; /* DSN are implemented in HW, so return just 0 */
-}
-
-/**
- * fake_get_bsn - Retrieve the BSN of the device.
- * @dev: The network device to retrieve the BSN for.
- *
- * Returns the IEEE 802.15.4 BSN for the network device.
- * The BSN is the sequence number which will be added to each
- * beacon frame sent by the MAC.
- *
- * BSN means 'Beacon Sequence Number'.
- *
- * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
- * document.
- */
-static u8 fake_get_bsn(const struct net_device *dev)
-{
- BUG_ON(dev->type != ARPHRD_IEEE802154);
-
- return 0x00; /* BSN are implemented in HW, so return just 0 */
-}
-
-/**
- * fake_assoc_req - Make an association request to the HW.
- * @dev: The network device which we are associating to a network.
- * @addr: The coordinator with which we wish to associate.
- * @channel: The channel on which to associate.
- * @cap: The capability information field to use in the association.
- *
- * Start an association with a coordinator. The coordinator's address
- * and PAN ID can be found in @addr.
- *
- * Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE
- * 802.15.4-2006 document.
- */
-static int fake_assoc_req(struct net_device *dev,
- struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap)
-{
- struct wpan_phy *phy = fake_to_phy(dev);
-
- mutex_lock(&phy->pib_lock);
- phy->current_channel = channel;
- phy->current_page = page;
- mutex_unlock(&phy->pib_lock);
-
- /* We simply emulate it here */
- return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev),
- IEEE802154_SUCCESS);
-}
-
-/**
- * fake_assoc_resp - Send an association response to a device.
- * @dev: The network device on which to send the response.
- * @addr: The address of the device to respond to.
- * @short_addr: The assigned short address for the device (if any).
- * @status: The result of the association request.
- *
- * Queue the association response of the coordinator to another
- * device's attempt to associate with the network which we
- * coordinate. This is then added to the indirect-send queue to be
- * transmitted to the end device when it polls for data.
- *
- * Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE
- * 802.15.4-2006 document.
- */
-static int fake_assoc_resp(struct net_device *dev,
- struct ieee802154_addr *addr, u16 short_addr, u8 status)
-{
- return 0;
-}
-
-/**
- * fake_disassoc_req - Disassociate a device from a network.
- * @dev: The network device on which we're disassociating a device.
- * @addr: The device to disassociate from the network.
- * @reason: The reason to give to the device for being disassociated.
- *
- * This sends a disassociation notification to the device being
- * disassociated from the network.
- *
- * Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006
- * document, with the reason described in 7.3.3.2.
- */
-static int fake_disassoc_req(struct net_device *dev,
- struct ieee802154_addr *addr, u8 reason)
-{
- return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS);
-}
-
-/**
- * fake_start_req - Start an IEEE 802.15.4 PAN.
- * @dev: The network device on which to start the PAN.
- * @addr: The coordinator address to use when starting the PAN.
- * @channel: The channel on which to start the PAN.
- * @bcn_ord: Beacon order.
- * @sf_ord: Superframe order.
- * @pan_coord: Whether or not we are the PAN coordinator or just
- * requesting a realignment perhaps?
- * @blx: Battery Life Extension feature bitfield.
- * @coord_realign: Something to realign something else.
- *
- * If pan_coord is non-zero then this starts a network with the
- * provided parameters, otherwise it attempts a coordinator
- * realignment of the stated network instead.
- *
- * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
- * document, with 7.3.8 describing coordinator realignment.
- */
-static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
- u8 channel, u8 page,
- u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
- u8 coord_realign)
-{
- struct wpan_phy *phy = fake_to_phy(dev);
-
- mutex_lock(&phy->pib_lock);
- phy->current_channel = channel;
- phy->current_page = page;
- mutex_unlock(&phy->pib_lock);
-
- /* We don't emulate beacons here at all, so START should fail */
- ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER);
- return 0;
-}
-
-/**
- * fake_scan_req - Start a channel scan.
- * @dev: The network device on which to perform a channel scan.
- * @type: The type of scan to perform.
- * @channels: The channel bitmask to scan.
- * @duration: How long to spend on each channel.
- *
- * This starts either a passive (energy) scan or an active (PAN) scan
- * on the channels indicated in the @channels bitmask. The duration of
- * the scan is measured in terms of superframe duration. Specifically,
- * the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each
- * channel.
- *
- * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document.
- */
-static int fake_scan_req(struct net_device *dev, u8 type, u32 channels,
- u8 page, u8 duration)
-{
- u8 edl[27] = {};
- return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type,
- channels, page,
- type == IEEE802154_MAC_SCAN_ED ? edl : NULL);
-}
-
-static struct ieee802154_mlme_ops fake_mlme = {
- .assoc_req = fake_assoc_req,
- .assoc_resp = fake_assoc_resp,
- .disassoc_req = fake_disassoc_req,
- .start_req = fake_start_req,
- .scan_req = fake_scan_req,
-
- .get_phy = fake_get_phy,
-
- .get_pan_id = fake_get_pan_id,
- .get_short_addr = fake_get_short_addr,
- .get_dsn = fake_get_dsn,
- .get_bsn = fake_get_bsn,
-};
-
-static int ieee802154_fake_open(struct net_device *dev)
-{
- netif_start_queue(dev);
- return 0;
-}
-
-static int ieee802154_fake_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-static netdev_tx_t ieee802154_fake_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
-
- /* FIXME: do hardware work here ... */
-
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-
-static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
- int cmd)
-{
- struct sockaddr_ieee802154 *sa =
- (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
- u16 pan_id, short_addr;
-
- switch (cmd) {
- case SIOCGIFADDR:
- /* FIXME: fixed here, get from device IRL */
- pan_id = fake_get_pan_id(dev);
- short_addr = fake_get_short_addr(dev);
- if (pan_id == IEEE802154_PANID_BROADCAST ||
- short_addr == IEEE802154_ADDR_BROADCAST)
- return -EADDRNOTAVAIL;
-
- sa->family = AF_IEEE802154;
- sa->addr.addr_type = IEEE802154_ADDR_SHORT;
- sa->addr.pan_id = pan_id;
- sa->addr.short_addr = short_addr;
- return 0;
- }
- return -ENOIOCTLCMD;
-}
-
-static int ieee802154_fake_mac_addr(struct net_device *dev, void *p)
-{
- return -EBUSY; /* HW address is built into the device */
-}
-
-static const struct net_device_ops fake_ops = {
- .ndo_open = ieee802154_fake_open,
- .ndo_stop = ieee802154_fake_close,
- .ndo_start_xmit = ieee802154_fake_xmit,
- .ndo_do_ioctl = ieee802154_fake_ioctl,
- .ndo_set_mac_address = ieee802154_fake_mac_addr,
-};
-
-static void ieee802154_fake_destruct(struct net_device *dev)
-{
- struct wpan_phy *phy = fake_to_phy(dev);
-
- wpan_phy_unregister(phy);
- free_netdev(dev);
- wpan_phy_free(phy);
-}
-
-static void ieee802154_fake_setup(struct net_device *dev)
-{
- dev->addr_len = IEEE802154_ADDR_LEN;
- memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
- dev->features = NETIF_F_HW_CSUM;
- dev->needed_tailroom = 2; /* FCS */
- dev->mtu = 127;
- dev->tx_queue_len = 10;
- dev->type = ARPHRD_IEEE802154;
- dev->flags = IFF_NOARP | IFF_BROADCAST;
- dev->watchdog_timeo = 0;
- dev->destructor = ieee802154_fake_destruct;
-}
-
-
-static int __devinit ieee802154fake_probe(struct platform_device *pdev)
-{
- struct net_device *dev;
- struct fakehard_priv *priv;
- struct wpan_phy *phy = wpan_phy_alloc(0);
- int err;
-
- if (!phy)
- return -ENOMEM;
-
- dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d", ieee802154_fake_setup);
- if (!dev) {
- wpan_phy_free(phy);
- return -ENOMEM;
- }
-
- memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
- dev->addr_len);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
- /*
- * For now we'd like to emulate 2.4 GHz-only device,
- * both O-QPSK and CSS
- */
- /* 2.4 GHz O-QPSK 802.15.4-2003 */
- phy->channels_supported[0] |= 0x7FFF800;
- /* 2.4 GHz CSS 802.15.4a-2007 */
- phy->channels_supported[3] |= 0x3fff;
-
- phy->transmit_power = 0xbf;
-
- dev->netdev_ops = &fake_ops;
- dev->ml_priv = &fake_mlme;
-
- priv = netdev_priv(dev);
- priv->phy = phy;
-
- wpan_phy_set_dev(phy, &pdev->dev);
- SET_NETDEV_DEV(dev, &phy->dev);
-
- platform_set_drvdata(pdev, dev);
-
- err = wpan_phy_register(phy);
- if (err)
- goto out;
-
- err = register_netdev(dev);
- if (err < 0)
- goto out;
-
- dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
- return 0;
-
-out:
- unregister_netdev(dev);
- return err;
-}
-
-static int __devexit ieee802154fake_remove(struct platform_device *pdev)
-{
- struct net_device *dev = platform_get_drvdata(pdev);
- unregister_netdev(dev);
- return 0;
-}
-
-static struct platform_device *ieee802154fake_dev;
-
-static struct platform_driver ieee802154fake_driver = {
- .probe = ieee802154fake_probe,
- .remove = __devexit_p(ieee802154fake_remove),
- .driver = {
- .name = "ieee802154hardmac",
- .owner = THIS_MODULE,
- },
-};
-
-static __init int fake_init(void)
-{
- ieee802154fake_dev = platform_device_register_simple(
- "ieee802154hardmac", -1, NULL, 0);
- return platform_driver_register(&ieee802154fake_driver);
-}
-
-static __exit void fake_exit(void)
-{
- platform_driver_unregister(&ieee802154fake_driver);
- platform_device_unregister(ieee802154fake_dev);
-}
-
-module_init(fake_init);
-module_exit(fake_exit);
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/ieee802154/fakelb.c b/drivers/ieee802154/fakelb.c
deleted file mode 100644
index e7456fc..0000000
--- a/drivers/ieee802154/fakelb.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Loopback IEEE 802.15.4 interface
- *
- * Copyright 2007-2012 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Written by:
- * Sergey Lapin <slapin@ossfans.org>
- * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/platform_device.h>
-#include <linux/netdevice.h>
-#include <linux/spinlock.h>
-#include <net/mac802154.h>
-#include <net/wpan-phy.h>
-
-static int numlbs = 1;
-
-struct fakelb_dev_priv {
- struct ieee802154_dev *dev;
-
- struct list_head list;
- struct fakelb_priv *fake;
-
- spinlock_t lock;
- bool working;
-};
-
-struct fakelb_priv {
- struct list_head list;
- rwlock_t lock;
-};
-
-static int
-fakelb_hw_ed(struct ieee802154_dev *dev, u8 *level)
-{
- might_sleep();
- BUG_ON(!level);
- *level = 0xbe;
-
- return 0;
-}
-
-static int
-fakelb_hw_channel(struct ieee802154_dev *dev, int page, int channel)
-{
- pr_debug("set channel to %d\n", channel);
-
- might_sleep();
- dev->phy->current_page = page;
- dev->phy->current_channel = channel;
-
- return 0;
-}
-
-static void
-fakelb_hw_deliver(struct fakelb_dev_priv *priv, struct sk_buff *skb)
-{
- struct sk_buff *newskb;
-
- spin_lock(&priv->lock);
- if (priv->working) {
- newskb = pskb_copy(skb, GFP_ATOMIC);
- ieee802154_rx_irqsafe(priv->dev, newskb, 0xcc);
- }
- spin_unlock(&priv->lock);
-}
-
-static int
-fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
-{
- struct fakelb_dev_priv *priv = dev->priv;
- struct fakelb_priv *fake = priv->fake;
-
- might_sleep();
-
- read_lock_bh(&fake->lock);
- if (priv->list.next == priv->list.prev) {
- /* we are the only one device */
- fakelb_hw_deliver(priv, skb);
- } else {
- struct fakelb_dev_priv *dp;
- list_for_each_entry(dp, &priv->fake->list, list) {
- if (dp != priv &&
- (dp->dev->phy->current_channel ==
- priv->dev->phy->current_channel))
- fakelb_hw_deliver(dp, skb);
- }
- }
- read_unlock_bh(&fake->lock);
-
- return 0;
-}
-
-static int
-fakelb_hw_start(struct ieee802154_dev *dev) {
- struct fakelb_dev_priv *priv = dev->priv;
- int ret = 0;
-
- spin_lock(&priv->lock);
- if (priv->working)
- ret = -EBUSY;
- else
- priv->working = 1;
- spin_unlock(&priv->lock);
-
- return ret;
-}
-
-static void
-fakelb_hw_stop(struct ieee802154_dev *dev) {
- struct fakelb_dev_priv *priv = dev->priv;
-
- spin_lock(&priv->lock);
- priv->working = 0;
- spin_unlock(&priv->lock);
-}
-
-static struct ieee802154_ops fakelb_ops = {
- .owner = THIS_MODULE,
- .xmit = fakelb_hw_xmit,
- .ed = fakelb_hw_ed,
- .set_channel = fakelb_hw_channel,
- .start = fakelb_hw_start,
- .stop = fakelb_hw_stop,
-};
-
-/* Number of dummy devices to be set up by this module. */
-module_param(numlbs, int, 0);
-MODULE_PARM_DESC(numlbs, " number of pseudo devices");
-
-static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake)
-{
- struct fakelb_dev_priv *priv;
- int err;
- struct ieee802154_dev *ieee;
-
- ieee = ieee802154_alloc_device(sizeof(*priv), &fakelb_ops);
- if (!ieee)
- return -ENOMEM;
-
- priv = ieee->priv;
- priv->dev = ieee;
-
- /* 868 MHz BPSK 802.15.4-2003 */
- ieee->phy->channels_supported[0] |= 1;
- /* 915 MHz BPSK 802.15.4-2003 */
- ieee->phy->channels_supported[0] |= 0x7fe;
- /* 2.4 GHz O-QPSK 802.15.4-2003 */
- ieee->phy->channels_supported[0] |= 0x7FFF800;
- /* 868 MHz ASK 802.15.4-2006 */
- ieee->phy->channels_supported[1] |= 1;
- /* 915 MHz ASK 802.15.4-2006 */
- ieee->phy->channels_supported[1] |= 0x7fe;
- /* 868 MHz O-QPSK 802.15.4-2006 */
- ieee->phy->channels_supported[2] |= 1;
- /* 915 MHz O-QPSK 802.15.4-2006 */
- ieee->phy->channels_supported[2] |= 0x7fe;
- /* 2.4 GHz CSS 802.15.4a-2007 */
- ieee->phy->channels_supported[3] |= 0x3fff;
- /* UWB Sub-gigahertz 802.15.4a-2007 */
- ieee->phy->channels_supported[4] |= 1;
- /* UWB Low band 802.15.4a-2007 */
- ieee->phy->channels_supported[4] |= 0x1e;
- /* UWB High band 802.15.4a-2007 */
- ieee->phy->channels_supported[4] |= 0xffe0;
- /* 750 MHz O-QPSK 802.15.4c-2009 */
- ieee->phy->channels_supported[5] |= 0xf;
- /* 750 MHz MPSK 802.15.4c-2009 */
- ieee->phy->channels_supported[5] |= 0xf0;
- /* 950 MHz BPSK 802.15.4d-2009 */
- ieee->phy->channels_supported[6] |= 0x3ff;
- /* 950 MHz GFSK 802.15.4d-2009 */
- ieee->phy->channels_supported[6] |= 0x3ffc00;
-
- INIT_LIST_HEAD(&priv->list);
- priv->fake = fake;
-
- spin_lock_init(&priv->lock);
-
- ieee->parent = dev;
-
- err = ieee802154_register_device(ieee);
- if (err)
- goto err_reg;
-
- write_lock_bh(&fake->lock);
- list_add_tail(&priv->list, &fake->list);
- write_unlock_bh(&fake->lock);
-
- return 0;
-
-err_reg:
- ieee802154_free_device(priv->dev);
- return err;
-}
-
-static void fakelb_del(struct fakelb_dev_priv *priv)
-{
- write_lock_bh(&priv->fake->lock);
- list_del(&priv->list);
- write_unlock_bh(&priv->fake->lock);
-
- ieee802154_unregister_device(priv->dev);
- ieee802154_free_device(priv->dev);
-}
-
-static int __devinit fakelb_probe(struct platform_device *pdev)
-{
- struct fakelb_priv *priv;
- struct fakelb_dev_priv *dp;
- int err = -ENOMEM;
- int i;
-
- priv = kzalloc(sizeof(struct fakelb_priv), GFP_KERNEL);
- if (!priv)
- goto err_alloc;
-
- INIT_LIST_HEAD(&priv->list);
- rwlock_init(&priv->lock);
-
- for (i = 0; i < numlbs; i++) {
- err = fakelb_add_one(&pdev->dev, priv);
- if (err < 0)
- goto err_slave;
- }
-
- platform_set_drvdata(pdev, priv);
- dev_info(&pdev->dev, "added ieee802154 hardware\n");
- return 0;
-
-err_slave:
- list_for_each_entry(dp, &priv->list, list)
- fakelb_del(dp);
- kfree(priv);
-err_alloc:
- return err;
-}
-
-static int __devexit fakelb_remove(struct platform_device *pdev)
-{
- struct fakelb_priv *priv = platform_get_drvdata(pdev);
- struct fakelb_dev_priv *dp, *temp;
-
- list_for_each_entry_safe(dp, temp, &priv->list, list)
- fakelb_del(dp);
- kfree(priv);
-
- return 0;
-}
-
-static struct platform_device *ieee802154fake_dev;
-
-static struct platform_driver ieee802154fake_driver = {
- .probe = fakelb_probe,
- .remove = __devexit_p(fakelb_remove),
- .driver = {
- .name = "ieee802154fakelb",
- .owner = THIS_MODULE,
- },
-};
-
-static __init int fakelb_init_module(void)
-{
- ieee802154fake_dev = platform_device_register_simple(
- "ieee802154fakelb", -1, NULL, 0);
- return platform_driver_register(&ieee802154fake_driver);
-}
-
-static __exit void fake_remove_module(void)
-{
- platform_driver_unregister(&ieee802154fake_driver);
- platform_device_unregister(ieee802154fake_dev);
-}
-
-module_init(fakelb_init_module);
-module_exit(fake_remove_module);
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0c2bd80..707ab7b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -107,8 +107,6 @@ config MII
or internal device. It is safe to say Y or M here even if your
ethernet card lacks MII.
-source "drivers/ieee802154/Kconfig"
-
config IFB
tristate "Intermediate Functional Block support"
depends on NET_CLS_ACT
@@ -290,6 +288,8 @@ source "drivers/net/wimax/Kconfig"
source "drivers/net/wan/Kconfig"
+source "drivers/net/ieee802154/Kconfig"
+
config XEN_NETDEV_FRONTEND
tristate "Xen network device frontend driver"
depends on XEN
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 3d375ca..b682a1d 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_SUNGEM_PHY) += sungem_phy.o
obj-$(CONFIG_WAN) += wan/
obj-$(CONFIG_WLAN) += wireless/
obj-$(CONFIG_WIMAX) += wimax/
+obj-$(CONFIG_IEEE802154) += ieee802154/
obj-$(CONFIG_VMXNET3) += vmxnet3/
obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig
new file mode 100644
index 0000000..1fc4eef
--- /dev/null
+++ b/drivers/net/ieee802154/Kconfig
@@ -0,0 +1,36 @@
+menuconfig IEEE802154_DRIVERS
+ tristate "IEEE 802.15.4 drivers"
+ depends on NETDEVICES && IEEE802154
+ default y
+ ---help---
+ Say Y here to get to see options for IEEE 802.15.4 Low-Rate
+ Wireless Personal Area Network device drivers. This option alone
+ does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and
+ disabled.
+
+config IEEE802154_FAKEHARD
+ tristate "Fake LR-WPAN driver with several interconnected devices"
+ depends on IEEE802154_DRIVERS
+ ---help---
+ Say Y here to enable the fake driver that serves as an example
+ of HardMAC device driver.
+
+ This driver can also be built as a module. To do so say M here.
+ The module will be called 'fakehard'.
+
+config IEEE802154_FAKELB
+ depends on IEEE802154_DRIVERS && MAC802154
+ tristate "IEEE 802.15.4 loopback driver"
+ ---help---
+ Say Y here to enable the fake driver that can emulate a net
+ of several interconnected radio devices.
+
+ This driver can also be built as a module. To do so say M here.
+ The module will be called 'fakelb'.
+
+config IEEE802154_AT86RF230
+ depends on IEEE802154_DRIVERS && MAC802154
+ tristate "AT86RF230/231 transceiver driver"
+ depends on SPI
diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile
new file mode 100644
index 0000000..4f4371d
--- /dev/null
+++ b/drivers/net/ieee802154/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
+obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
+obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
new file mode 100644
index 0000000..ba753d8
--- /dev/null
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -0,0 +1,958 @@
+/*
+ * AT86RF230/RF231 driver
+ *
+ * Copyright (C) 2009-2012 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/at86rf230.h>
+#include <linux/skbuff.h>
+
+#include <net/mac802154.h>
+#include <net/wpan-phy.h>
+
+struct at86rf230_local {
+ struct spi_device *spi;
+ int rstn, slp_tr, dig2;
+
+ u8 part;
+ u8 vers;
+
+ u8 buf[2];
+ struct mutex bmux;
+
+ struct work_struct irqwork;
+ struct completion tx_complete;
+
+ struct ieee802154_dev *dev;
+
+ spinlock_t lock;
+ bool irq_disabled;
+ bool is_tx;
+};
+
+#define RG_TRX_STATUS (0x01)
+#define SR_TRX_STATUS 0x01, 0x1f, 0
+#define SR_RESERVED_01_3 0x01, 0x20, 5
+#define SR_CCA_STATUS 0x01, 0x40, 6
+#define SR_CCA_DONE 0x01, 0x80, 7
+#define RG_TRX_STATE (0x02)
+#define SR_TRX_CMD 0x02, 0x1f, 0
+#define SR_TRAC_STATUS 0x02, 0xe0, 5
+#define RG_TRX_CTRL_0 (0x03)
+#define SR_CLKM_CTRL 0x03, 0x07, 0
+#define SR_CLKM_SHA_SEL 0x03, 0x08, 3
+#define SR_PAD_IO_CLKM 0x03, 0x30, 4
+#define SR_PAD_IO 0x03, 0xc0, 6
+#define RG_TRX_CTRL_1 (0x04)
+#define SR_IRQ_POLARITY 0x04, 0x01, 0
+#define SR_IRQ_MASK_MODE 0x04, 0x02, 1
+#define SR_SPI_CMD_MODE 0x04, 0x0c, 2
+#define SR_RX_BL_CTRL 0x04, 0x10, 4
+#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5
+#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6
+#define SR_PA_EXT_EN 0x04, 0x80, 7
+#define RG_PHY_TX_PWR (0x05)
+#define SR_TX_PWR 0x05, 0x0f, 0
+#define SR_PA_LT 0x05, 0x30, 4
+#define SR_PA_BUF_LT 0x05, 0xc0, 6
+#define RG_PHY_RSSI (0x06)
+#define SR_RSSI 0x06, 0x1f, 0
+#define SR_RND_VALUE 0x06, 0x60, 5
+#define SR_RX_CRC_VALID 0x06, 0x80, 7
+#define RG_PHY_ED_LEVEL (0x07)
+#define SR_ED_LEVEL 0x07, 0xff, 0
+#define RG_PHY_CC_CCA (0x08)
+#define SR_CHANNEL 0x08, 0x1f, 0
+#define SR_CCA_MODE 0x08, 0x60, 5
+#define SR_CCA_REQUEST 0x08, 0x80, 7
+#define RG_CCA_THRES (0x09)
+#define SR_CCA_ED_THRES 0x09, 0x0f, 0
+#define SR_RESERVED_09_1 0x09, 0xf0, 4
+#define RG_RX_CTRL (0x0a)
+#define SR_PDT_THRES 0x0a, 0x0f, 0
+#define SR_RESERVED_0a_1 0x0a, 0xf0, 4
+#define RG_SFD_VALUE (0x0b)
+#define SR_SFD_VALUE 0x0b, 0xff, 0
+#define RG_TRX_CTRL_2 (0x0c)
+#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0
+#define SR_RESERVED_0c_2 0x0c, 0x7c, 2
+#define SR_RX_SAFE_MODE 0x0c, 0x80, 7
+#define RG_ANT_DIV (0x0d)
+#define SR_ANT_CTRL 0x0d, 0x03, 0
+#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2
+#define SR_ANT_DIV_EN 0x0d, 0x08, 3
+#define SR_RESERVED_0d_2 0x0d, 0x70, 4
+#define SR_ANT_SEL 0x0d, 0x80, 7
+#define RG_IRQ_MASK (0x0e)
+#define SR_IRQ_MASK 0x0e, 0xff, 0
+#define RG_IRQ_STATUS (0x0f)
+#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0
+#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1
+#define SR_IRQ_2_RX_START 0x0f, 0x04, 2
+#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3
+#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4
+#define SR_IRQ_5_AMI 0x0f, 0x20, 5
+#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6
+#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7
+#define RG_VREG_CTRL (0x10)
+#define SR_RESERVED_10_6 0x10, 0x03, 0
+#define SR_DVDD_OK 0x10, 0x04, 2
+#define SR_DVREG_EXT 0x10, 0x08, 3
+#define SR_RESERVED_10_3 0x10, 0x30, 4
+#define SR_AVDD_OK 0x10, 0x40, 6
+#define SR_AVREG_EXT 0x10, 0x80, 7
+#define RG_BATMON (0x11)
+#define SR_BATMON_VTH 0x11, 0x0f, 0
+#define SR_BATMON_HR 0x11, 0x10, 4
+#define SR_BATMON_OK 0x11, 0x20, 5
+#define SR_RESERVED_11_1 0x11, 0xc0, 6
+#define RG_XOSC_CTRL (0x12)
+#define SR_XTAL_TRIM 0x12, 0x0f, 0
+#define SR_XTAL_MODE 0x12, 0xf0, 4
+#define RG_RX_SYN (0x15)
+#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0
+#define SR_RESERVED_15_2 0x15, 0x70, 4
+#define SR_RX_PDT_DIS 0x15, 0x80, 7
+#define RG_XAH_CTRL_1 (0x17)
+#define SR_RESERVED_17_8 0x17, 0x01, 0
+#define SR_AACK_PROM_MODE 0x17, 0x02, 1
+#define SR_AACK_ACK_TIME 0x17, 0x04, 2
+#define SR_RESERVED_17_5 0x17, 0x08, 3
+#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4
+#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5
+#define SR_RESERVED_17_2 0x17, 0x40, 6
+#define SR_RESERVED_17_1 0x17, 0x80, 7
+#define RG_FTN_CTRL (0x18)
+#define SR_RESERVED_18_2 0x18, 0x7f, 0
+#define SR_FTN_START 0x18, 0x80, 7
+#define RG_PLL_CF (0x1a)
+#define SR_RESERVED_1a_2 0x1a, 0x7f, 0
+#define SR_PLL_CF_START 0x1a, 0x80, 7
+#define RG_PLL_DCU (0x1b)
+#define SR_RESERVED_1b_3 0x1b, 0x3f, 0
+#define SR_RESERVED_1b_2 0x1b, 0x40, 6
+#define SR_PLL_DCU_START 0x1b, 0x80, 7
+#define RG_PART_NUM (0x1c)
+#define SR_PART_NUM 0x1c, 0xff, 0
+#define RG_VERSION_NUM (0x1d)
+#define SR_VERSION_NUM 0x1d, 0xff, 0
+#define RG_MAN_ID_0 (0x1e)
+#define SR_MAN_ID_0 0x1e, 0xff, 0
+#define RG_MAN_ID_1 (0x1f)
+#define SR_MAN_ID_1 0x1f, 0xff, 0
+#define RG_SHORT_ADDR_0 (0x20)
+#define SR_SHORT_ADDR_0 0x20, 0xff, 0
+#define RG_SHORT_ADDR_1 (0x21)
+#define SR_SHORT_ADDR_1 0x21, 0xff, 0
+#define RG_PAN_ID_0 (0x22)
+#define SR_PAN_ID_0 0x22, 0xff, 0
+#define RG_PAN_ID_1 (0x23)
+#define SR_PAN_ID_1 0x23, 0xff, 0
+#define RG_IEEE_ADDR_0 (0x24)
+#define SR_IEEE_ADDR_0 0x24, 0xff, 0
+#define RG_IEEE_ADDR_1 (0x25)
+#define SR_IEEE_ADDR_1 0x25, 0xff, 0
+#define RG_IEEE_ADDR_2 (0x26)
+#define SR_IEEE_ADDR_2 0x26, 0xff, 0
+#define RG_IEEE_ADDR_3 (0x27)
+#define SR_IEEE_ADDR_3 0x27, 0xff, 0
+#define RG_IEEE_ADDR_4 (0x28)
+#define SR_IEEE_ADDR_4 0x28, 0xff, 0
+#define RG_IEEE_ADDR_5 (0x29)
+#define SR_IEEE_ADDR_5 0x29, 0xff, 0
+#define RG_IEEE_ADDR_6 (0x2a)
+#define SR_IEEE_ADDR_6 0x2a, 0xff, 0
+#define RG_IEEE_ADDR_7 (0x2b)
+#define SR_IEEE_ADDR_7 0x2b, 0xff, 0
+#define RG_XAH_CTRL_0 (0x2c)
+#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0
+#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1
+#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4
+#define RG_CSMA_SEED_0 (0x2d)
+#define SR_CSMA_SEED_0 0x2d, 0xff, 0
+#define RG_CSMA_SEED_1 (0x2e)
+#define SR_CSMA_SEED_1 0x2e, 0x07, 0
+#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3
+#define SR_AACK_DIS_ACK 0x2e, 0x10, 4
+#define SR_AACK_SET_PD 0x2e, 0x20, 5
+#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6
+#define RG_CSMA_BE (0x2f)
+#define SR_MIN_BE 0x2f, 0x0f, 0
+#define SR_MAX_BE 0x2f, 0xf0, 4
+
+#define CMD_REG 0x80
+#define CMD_REG_MASK 0x3f
+#define CMD_WRITE 0x40
+#define CMD_FB 0x20
+
+#define IRQ_BAT_LOW (1 << 7)
+#define IRQ_TRX_UR (1 << 6)
+#define IRQ_AMI (1 << 5)
+#define IRQ_CCA_ED (1 << 4)
+#define IRQ_TRX_END (1 << 3)
+#define IRQ_RX_START (1 << 2)
+#define IRQ_PLL_UNL (1 << 1)
+#define IRQ_PLL_LOCK (1 << 0)
+
+#define STATE_P_ON 0x00 /* BUSY */
+#define STATE_BUSY_RX 0x01
+#define STATE_BUSY_TX 0x02
+#define STATE_FORCE_TRX_OFF 0x03
+#define STATE_FORCE_TX_ON 0x04 /* IDLE */
+/* 0x05 */ /* INVALID_PARAMETER */
+#define STATE_RX_ON 0x06
+/* 0x07 */ /* SUCCESS */
+#define STATE_TRX_OFF 0x08
+#define STATE_TX_ON 0x09
+/* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */
+#define STATE_SLEEP 0x0F
+#define STATE_BUSY_RX_AACK 0x11
+#define STATE_BUSY_TX_ARET 0x12
+#define STATE_BUSY_RX_AACK_ON 0x16
+#define STATE_BUSY_TX_ARET_ON 0x19
+#define STATE_RX_ON_NOCLK 0x1C
+#define STATE_RX_AACK_ON_NOCLK 0x1D
+#define STATE_BUSY_RX_AACK_NOCLK 0x1E
+#define STATE_TRANSITION_IN_PROGRESS 0x1F
+
+static int
+__at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data)
+{
+ u8 *buf = lp->buf;
+ int status;
+ struct spi_message msg;
+ struct spi_transfer xfer = {
+ .len = 2,
+ .tx_buf = buf,
+ };
+
+ buf[0] = (addr & CMD_REG_MASK) | CMD_REG | CMD_WRITE;
+ buf[1] = data;
+ dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+ dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ status = spi_sync(lp->spi, &msg);
+ dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+ if (msg.status)
+ status = msg.status;
+
+ dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+ dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+ dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+ return status;
+}
+
+static int
+__at86rf230_read_subreg(struct at86rf230_local *lp,
+ u8 addr, u8 mask, int shift, u8 *data)
+{
+ u8 *buf = lp->buf;
+ int status;
+ struct spi_message msg;
+ struct spi_transfer xfer = {
+ .len = 2,
+ .tx_buf = buf,
+ .rx_buf = buf,
+ };
+
+ buf[0] = (addr & CMD_REG_MASK) | CMD_REG;
+ buf[1] = 0xff;
+ dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ status = spi_sync(lp->spi, &msg);
+ dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+ if (msg.status)
+ status = msg.status;
+
+ dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+ dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+ dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+ if (status == 0)
+ *data = buf[1];
+
+ return status;
+}
+
+static int
+at86rf230_read_subreg(struct at86rf230_local *lp,
+ u8 addr, u8 mask, int shift, u8 *data)
+{
+ int status;
+
+ mutex_lock(&lp->bmux);
+ status = __at86rf230_read_subreg(lp, addr, mask, shift, data);
+ mutex_unlock(&lp->bmux);
+
+ return status;
+}
+
+static int
+at86rf230_write_subreg(struct at86rf230_local *lp,
+ u8 addr, u8 mask, int shift, u8 data)
+{
+ int status;
+ u8 val;
+
+ mutex_lock(&lp->bmux);
+ status = __at86rf230_read_subreg(lp, addr, 0xff, 0, &val);
+ if (status)
+ goto out;
+
+ val &= ~mask;
+ val |= (data << shift) & mask;
+
+ status = __at86rf230_write(lp, addr, val);
+out:
+ mutex_unlock(&lp->bmux);
+
+ return status;
+}
+
+static int
+at86rf230_write_fbuf(struct at86rf230_local *lp, u8 *data, u8 len)
+{
+ u8 *buf = lp->buf;
+ int status;
+ struct spi_message msg;
+ struct spi_transfer xfer_head = {
+ .len = 2,
+ .tx_buf = buf,
+
+ };
+ struct spi_transfer xfer_buf = {
+ .len = len,
+ .tx_buf = data,
+ };
+
+ mutex_lock(&lp->bmux);
+ buf[0] = CMD_WRITE | CMD_FB;
+ buf[1] = len + 2; /* 2 bytes for CRC that isn't written */
+
+ dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+ dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer_head, &msg);
+ spi_message_add_tail(&xfer_buf, &msg);
+
+ status = spi_sync(lp->spi, &msg);
+ dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+ if (msg.status)
+ status = msg.status;
+
+ dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+ dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+ dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+ mutex_unlock(&lp->bmux);
+ return status;
+}
+
+static int
+at86rf230_read_fbuf(struct at86rf230_local *lp, u8 *data, u8 *len, u8 *lqi)
+{
+ u8 *buf = lp->buf;
+ int status;
+ struct spi_message msg;
+ struct spi_transfer xfer_head = {
+ .len = 2,
+ .tx_buf = buf,
+ .rx_buf = buf,
+ };
+ struct spi_transfer xfer_head1 = {
+ .len = 2,
+ .tx_buf = buf,
+ .rx_buf = buf,
+ };
+ struct spi_transfer xfer_buf = {
+ .len = 0,
+ .rx_buf = data,
+ };
+
+ mutex_lock(&lp->bmux);
+
+ buf[0] = CMD_FB;
+ buf[1] = 0x00;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer_head, &msg);
+
+ status = spi_sync(lp->spi, &msg);
+ dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+
+ xfer_buf.len = *(buf + 1) + 1;
+ *len = buf[1];
+
+ buf[0] = CMD_FB;
+ buf[1] = 0x00;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer_head1, &msg);
+ spi_message_add_tail(&xfer_buf, &msg);
+
+ status = spi_sync(lp->spi, &msg);
+
+ if (msg.status)
+ status = msg.status;
+
+ dev_vdbg(&lp->spi->dev, "status = %d\n", status);
+ dev_vdbg(&lp->spi->dev, "buf[0] = %02x\n", buf[0]);
+ dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]);
+
+ if (status) {
+ if (lqi && (*len > lp->buf[1]))
+ *lqi = data[lp->buf[1]];
+ }
+ mutex_unlock(&lp->bmux);
+
+ return status;
+}
+
+static int
+at86rf230_ed(struct ieee802154_dev *dev, u8 *level)
+{
+ might_sleep();
+ BUG_ON(!level);
+ *level = 0xbe;
+ return 0;
+}
+
+static int
+at86rf230_state(struct ieee802154_dev *dev, int state)
+{
+ struct at86rf230_local *lp = dev->priv;
+ int rc;
+ u8 val;
+ u8 desired_status;
+
+ might_sleep();
+
+ if (state == STATE_FORCE_TX_ON)
+ desired_status = STATE_TX_ON;
+ else if (state == STATE_FORCE_TRX_OFF)
+ desired_status = STATE_TRX_OFF;
+ else
+ desired_status = state;
+
+ do {
+ rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
+ if (rc)
+ goto err;
+ } while (val == STATE_TRANSITION_IN_PROGRESS);
+
+ if (val == desired_status)
+ return 0;
+
+ /* state is equal to phy states */
+ rc = at86rf230_write_subreg(lp, SR_TRX_CMD, state);
+ if (rc)
+ goto err;
+
+ do {
+ rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &val);
+ if (rc)
+ goto err;
+ } while (val == STATE_TRANSITION_IN_PROGRESS);
+
+
+ if (val == desired_status)
+ return 0;
+
+ pr_err("unexpected state change: %d, asked for %d\n", val, state);
+ return -EBUSY;
+
+err:
+ pr_err("error: %d\n", rc);
+ return rc;
+}
+
+static int
+at86rf230_start(struct ieee802154_dev *dev)
+{
+ struct at86rf230_local *lp = dev->priv;
+ u8 rc;
+
+ rc = at86rf230_write_subreg(lp, SR_RX_SAFE_MODE, 1);
+ if (rc)
+ return rc;
+
+ return at86rf230_state(dev, STATE_RX_ON);
+}
+
+static void
+at86rf230_stop(struct ieee802154_dev *dev)
+{
+ at86rf230_state(dev, STATE_FORCE_TRX_OFF);
+}
+
+static int
+at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
+{
+ struct at86rf230_local *lp = dev->priv;
+ int rc;
+
+ might_sleep();
+
+ if (page != 0 || channel < 11 || channel > 26) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel);
+ msleep(1); /* Wait for PLL */
+ dev->phy->current_channel = channel;
+
+ return 0;
+}
+
+static int
+at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
+{
+ struct at86rf230_local *lp = dev->priv;
+ int rc;
+ unsigned long flags;
+
+ spin_lock(&lp->lock);
+ if (lp->irq_disabled) {
+ spin_unlock(&lp->lock);
+ return -EBUSY;
+ }
+ spin_unlock(&lp->lock);
+
+ might_sleep();
+
+ rc = at86rf230_state(dev, STATE_FORCE_TX_ON);
+ if (rc)
+ goto err;
+
+ spin_lock_irqsave(&lp->lock, flags);
+ lp->is_tx = 1;
+ INIT_COMPLETION(lp->tx_complete);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ rc = at86rf230_write_fbuf(lp, skb->data, skb->len);
+ if (rc)
+ goto err_rx;
+
+ rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX);
+ if (rc)
+ goto err_rx;
+
+ rc = wait_for_completion_interruptible(&lp->tx_complete);
+ if (rc < 0)
+ goto err_rx;
+
+ rc = at86rf230_start(dev);
+
+ return rc;
+
+err_rx:
+ at86rf230_start(dev);
+err:
+ pr_err("error: %d\n", rc);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ lp->is_tx = 0;
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return rc;
+}
+
+static int at86rf230_rx(struct at86rf230_local *lp)
+{
+ u8 len = 128, lqi = 0;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(len, GFP_KERNEL);
+
+ if (!skb)
+ return -ENOMEM;
+
+ if (at86rf230_read_fbuf(lp, skb_put(skb, len), &len, &lqi))
+ goto err;
+
+ if (len < 2)
+ goto err;
+
+ skb_trim(skb, len - 2); /* We do not put CRC into the frame */
+
+ ieee802154_rx_irqsafe(lp->dev, skb, lqi);
+
+ dev_dbg(&lp->spi->dev, "READ_FBUF: %d %x\n", len, lqi);
+
+ return 0;
+err:
+ pr_debug("received frame is too small\n");
+
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
+static struct ieee802154_ops at86rf230_ops = {
+ .owner = THIS_MODULE,
+ .xmit = at86rf230_xmit,
+ .ed = at86rf230_ed,
+ .set_channel = at86rf230_channel,
+ .start = at86rf230_start,
+ .stop = at86rf230_stop,
+};
+
+static void at86rf230_irqwork(struct work_struct *work)
+{
+ struct at86rf230_local *lp =
+ container_of(work, struct at86rf230_local, irqwork);
+ u8 status = 0, val;
+ int rc;
+ unsigned long flags;
+
+ rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &val);
+ status |= val;
+
+ status &= ~IRQ_PLL_LOCK; /* ignore */
+ status &= ~IRQ_RX_START; /* ignore */
+ status &= ~IRQ_AMI; /* ignore */
+ status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/
+
+ if (status & IRQ_TRX_END) {
+ spin_lock_irqsave(&lp->lock, flags);
+ status &= ~IRQ_TRX_END;
+ if (lp->is_tx) {
+ lp->is_tx = 0;
+ spin_unlock_irqrestore(&lp->lock, flags);
+ complete(&lp->tx_complete);
+ } else {
+ spin_unlock_irqrestore(&lp->lock, flags);
+ at86rf230_rx(lp);
+ }
+ }
+
+ spin_lock_irqsave(&lp->lock, flags);
+ lp->irq_disabled = 0;
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ enable_irq(lp->spi->irq);
+}
+
+static irqreturn_t at86rf230_isr(int irq, void *data)
+{
+ struct at86rf230_local *lp = data;
+
+ disable_irq_nosync(irq);
+
+ spin_lock(&lp->lock);
+ lp->irq_disabled = 1;
+ spin_unlock(&lp->lock);
+
+ schedule_work(&lp->irqwork);
+
+ return IRQ_HANDLED;
+}
+
+
+static int at86rf230_hw_init(struct at86rf230_local *lp)
+{
+ u8 status;
+ int rc;
+
+ rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
+ if (rc)
+ return rc;
+
+ dev_info(&lp->spi->dev, "Status: %02x\n", status);
+ if (status == STATE_P_ON) {
+ rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF);
+ if (rc)
+ return rc;
+ msleep(1);
+ rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
+ if (rc)
+ return rc;
+ dev_info(&lp->spi->dev, "Status: %02x\n", status);
+ }
+
+ rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, 0xff); /* IRQ_TRX_UR |
+ * IRQ_CCA_ED |
+ * IRQ_TRX_END |
+ * IRQ_PLL_UNL |
+ * IRQ_PLL_LOCK
+ */
+ if (rc)
+ return rc;
+
+ /* CLKM changes are applied immediately */
+ rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00);
+ if (rc)
+ return rc;
+
+ /* Turn CLKM Off */
+ rc = at86rf230_write_subreg(lp, SR_CLKM_CTRL, 0x00);
+ if (rc)
+ return rc;
+ /* Wait the next SLEEP cycle */
+ msleep(100);
+
+ rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON);
+ if (rc)
+ return rc;
+ msleep(1);
+
+ rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
+ if (rc)
+ return rc;
+ dev_info(&lp->spi->dev, "Status: %02x\n", status);
+
+ rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status);
+ if (rc)
+ return rc;
+ if (!status) {
+ dev_err(&lp->spi->dev, "DVDD error\n");
+ return -EINVAL;
+ }
+
+ rc = at86rf230_read_subreg(lp, SR_AVDD_OK, &status);
+ if (rc)
+ return rc;
+ if (!status) {
+ dev_err(&lp->spi->dev, "AVDD error\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int at86rf230_suspend(struct spi_device *spi, pm_message_t message)
+{
+ return 0;
+}
+
+static int at86rf230_resume(struct spi_device *spi)
+{
+ return 0;
+}
+
+static int at86rf230_fill_data(struct spi_device *spi)
+{
+ struct at86rf230_local *lp = spi_get_drvdata(spi);
+ struct at86rf230_platform_data *pdata = spi->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&spi->dev, "no platform_data\n");
+ return -EINVAL;
+ }
+
+ lp->rstn = pdata->rstn;
+ lp->slp_tr = pdata->slp_tr;
+ lp->dig2 = pdata->dig2;
+
+ return 0;
+}
+
+static int __devinit at86rf230_probe(struct spi_device *spi)
+{
+ struct ieee802154_dev *dev;
+ struct at86rf230_local *lp;
+ u8 man_id_0, man_id_1;
+ int rc;
+ const char *chip;
+ int supported = 0;
+
+ if (!spi->irq) {
+ dev_err(&spi->dev, "no IRQ specified\n");
+ return -EINVAL;
+ }
+
+ dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops);
+ if (!dev)
+ return -ENOMEM;
+
+ lp = dev->priv;
+ lp->dev = dev;
+
+ lp->spi = spi;
+
+ dev->priv = lp;
+ dev->parent = &spi->dev;
+ dev->extra_tx_headroom = 0;
+ /* We do support only 2.4 Ghz */
+ dev->phy->channels_supported[0] = 0x7FFF800;
+ dev->flags = IEEE802154_HW_OMIT_CKSUM;
+
+ mutex_init(&lp->bmux);
+ INIT_WORK(&lp->irqwork, at86rf230_irqwork);
+ spin_lock_init(&lp->lock);
+ init_completion(&lp->tx_complete);
+
+ spi_set_drvdata(spi, lp);
+
+ rc = at86rf230_fill_data(spi);
+ if (rc)
+ goto err_fill;
+
+ rc = gpio_request(lp->rstn, "rstn");
+ if (rc)
+ goto err_rstn;
+
+ if (gpio_is_valid(lp->slp_tr)) {
+ rc = gpio_request(lp->slp_tr, "slp_tr");
+ if (rc)
+ goto err_slp_tr;
+ }
+
+ rc = gpio_direction_output(lp->rstn, 1);
+ if (rc)
+ goto err_gpio_dir;
+
+ if (gpio_is_valid(lp->slp_tr)) {
+ rc = gpio_direction_output(lp->slp_tr, 0);
+ if (rc)
+ goto err_gpio_dir;
+ }
+
+ /* Reset */
+ msleep(1);
+ gpio_set_value(lp->rstn, 0);
+ msleep(1);
+ gpio_set_value(lp->rstn, 1);
+ msleep(1);
+
+ rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0);
+ if (rc)
+ goto err_gpio_dir;
+ rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1);
+ if (rc)
+ goto err_gpio_dir;
+
+ if (man_id_1 != 0x00 || man_id_0 != 0x1f) {
+ dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n",
+ man_id_1, man_id_0);
+ rc = -EINVAL;
+ goto err_gpio_dir;
+ }
+
+ rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part);
+ if (rc)
+ goto err_gpio_dir;
+
+ rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers);
+ if (rc)
+ goto err_gpio_dir;
+
+ switch (lp->part) {
+ case 2:
+ chip = "at86rf230";
+ /* supported = 1; FIXME: should be easy to support; */
+ break;
+ case 3:
+ chip = "at86rf231";
+ supported = 1;
+ break;
+ default:
+ chip = "UNKNOWN";
+ break;
+ }
+
+ dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers);
+ if (!supported) {
+ rc = -ENOTSUPP;
+ goto err_gpio_dir;
+ }
+
+ rc = at86rf230_hw_init(lp);
+ if (rc)
+ goto err_gpio_dir;
+
+ rc = request_irq(spi->irq, at86rf230_isr, IRQF_SHARED,
+ dev_name(&spi->dev), lp);
+ if (rc)
+ goto err_gpio_dir;
+
+ rc = ieee802154_register_device(lp->dev);
+ if (rc)
+ goto err_irq;
+
+ return rc;
+
+ ieee802154_unregister_device(lp->dev);
+err_irq:
+ free_irq(spi->irq, lp);
+ flush_work(&lp->irqwork);
+err_gpio_dir:
+ if (gpio_is_valid(lp->slp_tr))
+ gpio_free(lp->slp_tr);
+err_slp_tr:
+ gpio_free(lp->rstn);
+err_rstn:
+err_fill:
+ spi_set_drvdata(spi, NULL);
+ mutex_destroy(&lp->bmux);
+ ieee802154_free_device(lp->dev);
+ return rc;
+}
+
+static int __devexit at86rf230_remove(struct spi_device *spi)
+{
+ struct at86rf230_local *lp = spi_get_drvdata(spi);
+
+ ieee802154_unregister_device(lp->dev);
+
+ free_irq(spi->irq, lp);
+ flush_work(&lp->irqwork);
+
+ if (gpio_is_valid(lp->slp_tr))
+ gpio_free(lp->slp_tr);
+ gpio_free(lp->rstn);
+
+ spi_set_drvdata(spi, NULL);
+ mutex_destroy(&lp->bmux);
+ ieee802154_free_device(lp->dev);
+
+ dev_dbg(&spi->dev, "unregistered at86rf230\n");
+ return 0;
+}
+
+static struct spi_driver at86rf230_driver = {
+ .driver = {
+ .name = "at86rf230",
+ .owner = THIS_MODULE,
+ },
+ .probe = at86rf230_probe,
+ .remove = __devexit_p(at86rf230_remove),
+ .suspend = at86rf230_suspend,
+ .resume = at86rf230_resume,
+};
+
+module_spi_driver(at86rf230_driver);
+
+MODULE_DESCRIPTION("AT86RF230 Transceiver Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c
new file mode 100644
index 0000000..73d4531
--- /dev/null
+++ b/drivers/net/ieee802154/fakehard.c
@@ -0,0 +1,449 @@
+/*
+ * Sample driver for HardMAC IEEE 802.15.4 devices
+ *
+ * Copyright (C) 2009 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+
+#include <net/af_ieee802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/ieee802154.h>
+#include <net/nl802154.h>
+#include <net/wpan-phy.h>
+
+struct fakehard_priv {
+ struct wpan_phy *phy;
+};
+
+static struct wpan_phy *fake_to_phy(const struct net_device *dev)
+{
+ struct fakehard_priv *priv = netdev_priv(dev);
+ return priv->phy;
+}
+
+/**
+ * fake_get_phy - Return a phy corresponding to this device.
+ * @dev: The network device for which to return the wan-phy object
+ *
+ * This function returns a wpan-phy object corresponding to the passed
+ * network device. Reference counter for wpan-phy object is incremented,
+ * so when the wpan-phy isn't necessary, you should drop the reference
+ * via @wpan_phy_put() call.
+ */
+static struct wpan_phy *fake_get_phy(const struct net_device *dev)
+{
+ struct wpan_phy *phy = fake_to_phy(dev);
+ return to_phy(get_device(&phy->dev));
+}
+
+/**
+ * fake_get_pan_id - Retrieve the PAN ID of the device.
+ * @dev: The network device to retrieve the PAN of.
+ *
+ * Return the ID of the PAN from the PIB.
+ */
+static u16 fake_get_pan_id(const struct net_device *dev)
+{
+ BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+ return 0xeba1;
+}
+
+/**
+ * fake_get_short_addr - Retrieve the short address of the device.
+ * @dev: The network device to retrieve the short address of.
+ *
+ * Returns the IEEE 802.15.4 short-form address cached for this
+ * device. If the device has not yet had a short address assigned
+ * then this should return 0xFFFF to indicate a lack of association.
+ */
+static u16 fake_get_short_addr(const struct net_device *dev)
+{
+ BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+ return 0x1;
+}
+
+/**
+ * fake_get_dsn - Retrieve the DSN of the device.
+ * @dev: The network device to retrieve the DSN for.
+ *
+ * Returns the IEEE 802.15.4 DSN for the network device.
+ * The DSN is the sequence number which will be added to each
+ * packet or MAC command frame by the MAC during transmission.
+ *
+ * DSN means 'Data Sequence Number'.
+ *
+ * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
+ * document.
+ */
+static u8 fake_get_dsn(const struct net_device *dev)
+{
+ BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+ return 0x00; /* DSN are implemented in HW, so return just 0 */
+}
+
+/**
+ * fake_get_bsn - Retrieve the BSN of the device.
+ * @dev: The network device to retrieve the BSN for.
+ *
+ * Returns the IEEE 802.15.4 BSN for the network device.
+ * The BSN is the sequence number which will be added to each
+ * beacon frame sent by the MAC.
+ *
+ * BSN means 'Beacon Sequence Number'.
+ *
+ * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
+ * document.
+ */
+static u8 fake_get_bsn(const struct net_device *dev)
+{
+ BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+ return 0x00; /* BSN are implemented in HW, so return just 0 */
+}
+
+/**
+ * fake_assoc_req - Make an association request to the HW.
+ * @dev: The network device which we are associating to a network.
+ * @addr: The coordinator with which we wish to associate.
+ * @channel: The channel on which to associate.
+ * @cap: The capability information field to use in the association.
+ *
+ * Start an association with a coordinator. The coordinator's address
+ * and PAN ID can be found in @addr.
+ *
+ * Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE
+ * 802.15.4-2006 document.
+ */
+static int fake_assoc_req(struct net_device *dev,
+ struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap)
+{
+ struct wpan_phy *phy = fake_to_phy(dev);
+
+ mutex_lock(&phy->pib_lock);
+ phy->current_channel = channel;
+ phy->current_page = page;
+ mutex_unlock(&phy->pib_lock);
+
+ /* We simply emulate it here */
+ return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev),
+ IEEE802154_SUCCESS);
+}
+
+/**
+ * fake_assoc_resp - Send an association response to a device.
+ * @dev: The network device on which to send the response.
+ * @addr: The address of the device to respond to.
+ * @short_addr: The assigned short address for the device (if any).
+ * @status: The result of the association request.
+ *
+ * Queue the association response of the coordinator to another
+ * device's attempt to associate with the network which we
+ * coordinate. This is then added to the indirect-send queue to be
+ * transmitted to the end device when it polls for data.
+ *
+ * Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE
+ * 802.15.4-2006 document.
+ */
+static int fake_assoc_resp(struct net_device *dev,
+ struct ieee802154_addr *addr, u16 short_addr, u8 status)
+{
+ return 0;
+}
+
+/**
+ * fake_disassoc_req - Disassociate a device from a network.
+ * @dev: The network device on which we're disassociating a device.
+ * @addr: The device to disassociate from the network.
+ * @reason: The reason to give to the device for being disassociated.
+ *
+ * This sends a disassociation notification to the device being
+ * disassociated from the network.
+ *
+ * Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006
+ * document, with the reason described in 7.3.3.2.
+ */
+static int fake_disassoc_req(struct net_device *dev,
+ struct ieee802154_addr *addr, u8 reason)
+{
+ return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS);
+}
+
+/**
+ * fake_start_req - Start an IEEE 802.15.4 PAN.
+ * @dev: The network device on which to start the PAN.
+ * @addr: The coordinator address to use when starting the PAN.
+ * @channel: The channel on which to start the PAN.
+ * @bcn_ord: Beacon order.
+ * @sf_ord: Superframe order.
+ * @pan_coord: Whether or not we are the PAN coordinator or just
+ * requesting a realignment perhaps?
+ * @blx: Battery Life Extension feature bitfield.
+ * @coord_realign: Something to realign something else.
+ *
+ * If pan_coord is non-zero then this starts a network with the
+ * provided parameters, otherwise it attempts a coordinator
+ * realignment of the stated network instead.
+ *
+ * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
+ * document, with 7.3.8 describing coordinator realignment.
+ */
+static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
+ u8 channel, u8 page,
+ u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+ u8 coord_realign)
+{
+ struct wpan_phy *phy = fake_to_phy(dev);
+
+ mutex_lock(&phy->pib_lock);
+ phy->current_channel = channel;
+ phy->current_page = page;
+ mutex_unlock(&phy->pib_lock);
+
+ /* We don't emulate beacons here at all, so START should fail */
+ ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER);
+ return 0;
+}
+
+/**
+ * fake_scan_req - Start a channel scan.
+ * @dev: The network device on which to perform a channel scan.
+ * @type: The type of scan to perform.
+ * @channels: The channel bitmask to scan.
+ * @duration: How long to spend on each channel.
+ *
+ * This starts either a passive (energy) scan or an active (PAN) scan
+ * on the channels indicated in the @channels bitmask. The duration of
+ * the scan is measured in terms of superframe duration. Specifically,
+ * the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each
+ * channel.
+ *
+ * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document.
+ */
+static int fake_scan_req(struct net_device *dev, u8 type, u32 channels,
+ u8 page, u8 duration)
+{
+ u8 edl[27] = {};
+ return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type,
+ channels, page,
+ type == IEEE802154_MAC_SCAN_ED ? edl : NULL);
+}
+
+static struct ieee802154_mlme_ops fake_mlme = {
+ .assoc_req = fake_assoc_req,
+ .assoc_resp = fake_assoc_resp,
+ .disassoc_req = fake_disassoc_req,
+ .start_req = fake_start_req,
+ .scan_req = fake_scan_req,
+
+ .get_phy = fake_get_phy,
+
+ .get_pan_id = fake_get_pan_id,
+ .get_short_addr = fake_get_short_addr,
+ .get_dsn = fake_get_dsn,
+ .get_bsn = fake_get_bsn,
+};
+
+static int ieee802154_fake_open(struct net_device *dev)
+{
+ netif_start_queue(dev);
+ return 0;
+}
+
+static int ieee802154_fake_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ return 0;
+}
+
+static netdev_tx_t ieee802154_fake_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+
+ /* FIXME: do hardware work here ... */
+
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+
+static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
+ int cmd)
+{
+ struct sockaddr_ieee802154 *sa =
+ (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
+ u16 pan_id, short_addr;
+
+ switch (cmd) {
+ case SIOCGIFADDR:
+ /* FIXME: fixed here, get from device IRL */
+ pan_id = fake_get_pan_id(dev);
+ short_addr = fake_get_short_addr(dev);
+ if (pan_id == IEEE802154_PANID_BROADCAST ||
+ short_addr == IEEE802154_ADDR_BROADCAST)
+ return -EADDRNOTAVAIL;
+
+ sa->family = AF_IEEE802154;
+ sa->addr.addr_type = IEEE802154_ADDR_SHORT;
+ sa->addr.pan_id = pan_id;
+ sa->addr.short_addr = short_addr;
+ return 0;
+ }
+ return -ENOIOCTLCMD;
+}
+
+static int ieee802154_fake_mac_addr(struct net_device *dev, void *p)
+{
+ return -EBUSY; /* HW address is built into the device */
+}
+
+static const struct net_device_ops fake_ops = {
+ .ndo_open = ieee802154_fake_open,
+ .ndo_stop = ieee802154_fake_close,
+ .ndo_start_xmit = ieee802154_fake_xmit,
+ .ndo_do_ioctl = ieee802154_fake_ioctl,
+ .ndo_set_mac_address = ieee802154_fake_mac_addr,
+};
+
+static void ieee802154_fake_destruct(struct net_device *dev)
+{
+ struct wpan_phy *phy = fake_to_phy(dev);
+
+ wpan_phy_unregister(phy);
+ free_netdev(dev);
+ wpan_phy_free(phy);
+}
+
+static void ieee802154_fake_setup(struct net_device *dev)
+{
+ dev->addr_len = IEEE802154_ADDR_LEN;
+ memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+ dev->features = NETIF_F_HW_CSUM;
+ dev->needed_tailroom = 2; /* FCS */
+ dev->mtu = 127;
+ dev->tx_queue_len = 10;
+ dev->type = ARPHRD_IEEE802154;
+ dev->flags = IFF_NOARP | IFF_BROADCAST;
+ dev->watchdog_timeo = 0;
+ dev->destructor = ieee802154_fake_destruct;
+}
+
+
+static int __devinit ieee802154fake_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct fakehard_priv *priv;
+ struct wpan_phy *phy = wpan_phy_alloc(0);
+ int err;
+
+ if (!phy)
+ return -ENOMEM;
+
+ dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d", ieee802154_fake_setup);
+ if (!dev) {
+ wpan_phy_free(phy);
+ return -ENOMEM;
+ }
+
+ memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
+ dev->addr_len);
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ /*
+ * For now we'd like to emulate 2.4 GHz-only device,
+ * both O-QPSK and CSS
+ */
+ /* 2.4 GHz O-QPSK 802.15.4-2003 */
+ phy->channels_supported[0] |= 0x7FFF800;
+ /* 2.4 GHz CSS 802.15.4a-2007 */
+ phy->channels_supported[3] |= 0x3fff;
+
+ phy->transmit_power = 0xbf;
+
+ dev->netdev_ops = &fake_ops;
+ dev->ml_priv = &fake_mlme;
+
+ priv = netdev_priv(dev);
+ priv->phy = phy;
+
+ wpan_phy_set_dev(phy, &pdev->dev);
+ SET_NETDEV_DEV(dev, &phy->dev);
+
+ platform_set_drvdata(pdev, dev);
+
+ err = wpan_phy_register(phy);
+ if (err)
+ goto out;
+
+ err = register_netdev(dev);
+ if (err < 0)
+ goto out;
+
+ dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
+ return 0;
+
+out:
+ unregister_netdev(dev);
+ return err;
+}
+
+static int __devexit ieee802154fake_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ unregister_netdev(dev);
+ return 0;
+}
+
+static struct platform_device *ieee802154fake_dev;
+
+static struct platform_driver ieee802154fake_driver = {
+ .probe = ieee802154fake_probe,
+ .remove = __devexit_p(ieee802154fake_remove),
+ .driver = {
+ .name = "ieee802154hardmac",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int fake_init(void)
+{
+ ieee802154fake_dev = platform_device_register_simple(
+ "ieee802154hardmac", -1, NULL, 0);
+ return platform_driver_register(&ieee802154fake_driver);
+}
+
+static __exit void fake_exit(void)
+{
+ platform_driver_unregister(&ieee802154fake_driver);
+ platform_device_unregister(ieee802154fake_dev);
+}
+
+module_init(fake_init);
+module_exit(fake_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c
new file mode 100644
index 0000000..e7456fc
--- /dev/null
+++ b/drivers/net/ieee802154/fakelb.c
@@ -0,0 +1,294 @@
+/*
+ * Loopback IEEE 802.15.4 interface
+ *
+ * Copyright 2007-2012 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by:
+ * Sergey Lapin <slapin@ossfans.org>
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <net/mac802154.h>
+#include <net/wpan-phy.h>
+
+static int numlbs = 1;
+
+struct fakelb_dev_priv {
+ struct ieee802154_dev *dev;
+
+ struct list_head list;
+ struct fakelb_priv *fake;
+
+ spinlock_t lock;
+ bool working;
+};
+
+struct fakelb_priv {
+ struct list_head list;
+ rwlock_t lock;
+};
+
+static int
+fakelb_hw_ed(struct ieee802154_dev *dev, u8 *level)
+{
+ might_sleep();
+ BUG_ON(!level);
+ *level = 0xbe;
+
+ return 0;
+}
+
+static int
+fakelb_hw_channel(struct ieee802154_dev *dev, int page, int channel)
+{
+ pr_debug("set channel to %d\n", channel);
+
+ might_sleep();
+ dev->phy->current_page = page;
+ dev->phy->current_channel = channel;
+
+ return 0;
+}
+
+static void
+fakelb_hw_deliver(struct fakelb_dev_priv *priv, struct sk_buff *skb)
+{
+ struct sk_buff *newskb;
+
+ spin_lock(&priv->lock);
+ if (priv->working) {
+ newskb = pskb_copy(skb, GFP_ATOMIC);
+ ieee802154_rx_irqsafe(priv->dev, newskb, 0xcc);
+ }
+ spin_unlock(&priv->lock);
+}
+
+static int
+fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
+{
+ struct fakelb_dev_priv *priv = dev->priv;
+ struct fakelb_priv *fake = priv->fake;
+
+ might_sleep();
+
+ read_lock_bh(&fake->lock);
+ if (priv->list.next == priv->list.prev) {
+ /* we are the only one device */
+ fakelb_hw_deliver(priv, skb);
+ } else {
+ struct fakelb_dev_priv *dp;
+ list_for_each_entry(dp, &priv->fake->list, list) {
+ if (dp != priv &&
+ (dp->dev->phy->current_channel ==
+ priv->dev->phy->current_channel))
+ fakelb_hw_deliver(dp, skb);
+ }
+ }
+ read_unlock_bh(&fake->lock);
+
+ return 0;
+}
+
+static int
+fakelb_hw_start(struct ieee802154_dev *dev) {
+ struct fakelb_dev_priv *priv = dev->priv;
+ int ret = 0;
+
+ spin_lock(&priv->lock);
+ if (priv->working)
+ ret = -EBUSY;
+ else
+ priv->working = 1;
+ spin_unlock(&priv->lock);
+
+ return ret;
+}
+
+static void
+fakelb_hw_stop(struct ieee802154_dev *dev) {
+ struct fakelb_dev_priv *priv = dev->priv;
+
+ spin_lock(&priv->lock);
+ priv->working = 0;
+ spin_unlock(&priv->lock);
+}
+
+static struct ieee802154_ops fakelb_ops = {
+ .owner = THIS_MODULE,
+ .xmit = fakelb_hw_xmit,
+ .ed = fakelb_hw_ed,
+ .set_channel = fakelb_hw_channel,
+ .start = fakelb_hw_start,
+ .stop = fakelb_hw_stop,
+};
+
+/* Number of dummy devices to be set up by this module. */
+module_param(numlbs, int, 0);
+MODULE_PARM_DESC(numlbs, " number of pseudo devices");
+
+static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake)
+{
+ struct fakelb_dev_priv *priv;
+ int err;
+ struct ieee802154_dev *ieee;
+
+ ieee = ieee802154_alloc_device(sizeof(*priv), &fakelb_ops);
+ if (!ieee)
+ return -ENOMEM;
+
+ priv = ieee->priv;
+ priv->dev = ieee;
+
+ /* 868 MHz BPSK 802.15.4-2003 */
+ ieee->phy->channels_supported[0] |= 1;
+ /* 915 MHz BPSK 802.15.4-2003 */
+ ieee->phy->channels_supported[0] |= 0x7fe;
+ /* 2.4 GHz O-QPSK 802.15.4-2003 */
+ ieee->phy->channels_supported[0] |= 0x7FFF800;
+ /* 868 MHz ASK 802.15.4-2006 */
+ ieee->phy->channels_supported[1] |= 1;
+ /* 915 MHz ASK 802.15.4-2006 */
+ ieee->phy->channels_supported[1] |= 0x7fe;
+ /* 868 MHz O-QPSK 802.15.4-2006 */
+ ieee->phy->channels_supported[2] |= 1;
+ /* 915 MHz O-QPSK 802.15.4-2006 */
+ ieee->phy->channels_supported[2] |= 0x7fe;
+ /* 2.4 GHz CSS 802.15.4a-2007 */
+ ieee->phy->channels_supported[3] |= 0x3fff;
+ /* UWB Sub-gigahertz 802.15.4a-2007 */
+ ieee->phy->channels_supported[4] |= 1;
+ /* UWB Low band 802.15.4a-2007 */
+ ieee->phy->channels_supported[4] |= 0x1e;
+ /* UWB High band 802.15.4a-2007 */
+ ieee->phy->channels_supported[4] |= 0xffe0;
+ /* 750 MHz O-QPSK 802.15.4c-2009 */
+ ieee->phy->channels_supported[5] |= 0xf;
+ /* 750 MHz MPSK 802.15.4c-2009 */
+ ieee->phy->channels_supported[5] |= 0xf0;
+ /* 950 MHz BPSK 802.15.4d-2009 */
+ ieee->phy->channels_supported[6] |= 0x3ff;
+ /* 950 MHz GFSK 802.15.4d-2009 */
+ ieee->phy->channels_supported[6] |= 0x3ffc00;
+
+ INIT_LIST_HEAD(&priv->list);
+ priv->fake = fake;
+
+ spin_lock_init(&priv->lock);
+
+ ieee->parent = dev;
+
+ err = ieee802154_register_device(ieee);
+ if (err)
+ goto err_reg;
+
+ write_lock_bh(&fake->lock);
+ list_add_tail(&priv->list, &fake->list);
+ write_unlock_bh(&fake->lock);
+
+ return 0;
+
+err_reg:
+ ieee802154_free_device(priv->dev);
+ return err;
+}
+
+static void fakelb_del(struct fakelb_dev_priv *priv)
+{
+ write_lock_bh(&priv->fake->lock);
+ list_del(&priv->list);
+ write_unlock_bh(&priv->fake->lock);
+
+ ieee802154_unregister_device(priv->dev);
+ ieee802154_free_device(priv->dev);
+}
+
+static int __devinit fakelb_probe(struct platform_device *pdev)
+{
+ struct fakelb_priv *priv;
+ struct fakelb_dev_priv *dp;
+ int err = -ENOMEM;
+ int i;
+
+ priv = kzalloc(sizeof(struct fakelb_priv), GFP_KERNEL);
+ if (!priv)
+ goto err_alloc;
+
+ INIT_LIST_HEAD(&priv->list);
+ rwlock_init(&priv->lock);
+
+ for (i = 0; i < numlbs; i++) {
+ err = fakelb_add_one(&pdev->dev, priv);
+ if (err < 0)
+ goto err_slave;
+ }
+
+ platform_set_drvdata(pdev, priv);
+ dev_info(&pdev->dev, "added ieee802154 hardware\n");
+ return 0;
+
+err_slave:
+ list_for_each_entry(dp, &priv->list, list)
+ fakelb_del(dp);
+ kfree(priv);
+err_alloc:
+ return err;
+}
+
+static int __devexit fakelb_remove(struct platform_device *pdev)
+{
+ struct fakelb_priv *priv = platform_get_drvdata(pdev);
+ struct fakelb_dev_priv *dp, *temp;
+
+ list_for_each_entry_safe(dp, temp, &priv->list, list)
+ fakelb_del(dp);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct platform_device *ieee802154fake_dev;
+
+static struct platform_driver ieee802154fake_driver = {
+ .probe = fakelb_probe,
+ .remove = __devexit_p(fakelb_remove),
+ .driver = {
+ .name = "ieee802154fakelb",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int fakelb_init_module(void)
+{
+ ieee802154fake_dev = platform_device_register_simple(
+ "ieee802154fakelb", -1, NULL, 0);
+ return platform_driver_register(&ieee802154fake_driver);
+}
+
+static __exit void fake_remove_module(void)
+{
+ platform_driver_unregister(&ieee802154fake_driver);
+ platform_device_unregister(ieee802154fake_dev);
+}
+
+module_init(fakelb_init_module);
+module_exit(fake_remove_module);
+MODULE_LICENSE("GPL");
--
1.7.2.3
^ permalink raw reply related
* Re: [PATCH 00/19] netfilter: IPv6 NAT
From: Patrick McHardy @ 2012-08-26 18:06 UTC (permalink / raw)
To: Andre Tomt; +Cc: netfilter-devel, netdev
In-Reply-To: <5038278A.6080901@tomt.net>
On Sat, 25 Aug 2012, Andre Tomt wrote:
> On 25. aug. 2012 02:58, Andre Tomt wrote:
>> On 09. aug. 2012 22:08, kaber@trash.net wrote:
>>> The following patches contain an updated version of IPv6 NAT against
>>> Linus' current tree.
>>
>> Hmmm. Looking in my crystal ball (hi #ipv6!), I predict that if this
>> lands in mainline - and thus in consumer CPE/routers eventually - many
>> ISP's will have little incentive to actually implement assigning of
>> blocks to their consumer users like they "have to" today.
>>
>> We have this wonderful chance of fixing a major problem with todays
>> internet, but now we are going down this very slippery slope.
>>
>> I do need this code for a experimental project myself, and acknowledge
>> there may be some valid use cases, but I do not like the global
>> implications one bit.
>>
>> At least some big fat warnings please?
>
> Clarification: This is about the NAT66 port-based 1:n NAT targets.
We can certainly add a warning to the Kconfig text or (better) the
iptables manpage. But only a very small percentage of people who
might end up (unknowingly) using this will ever see them.
Feel free to send a patch though.
^ permalink raw reply
* Re: [RFC PATCH] net: Add support for virtual machine device queues (VMDQ)
From: John Fastabend @ 2012-08-26 19:09 UTC (permalink / raw)
To: Or Gerlitz; +Cc: davem, roland, netdev, ali, sean.hefty, shlomop
In-Reply-To: <CAJZOPZJBhDdQp2-8WG-UsToPHwyawYYVctqjZMT8JN85DK3XYQ@mail.gmail.com>
On 8/26/2012 6:11 AM, Or Gerlitz wrote:
> On Thu, Jul 19, 2012 at 1:05 AM, John Fastabend
> <john.r.fastabend@intel.com> wrote:
>> This adds support to allow virtual net devices to be created. These
>> devices can be managed independently of the physical function but
>> use the same physical link.
>>
>> This is analogous to an offloaded macvlan device. The primary
>> advantage to VMDQ net devices over virtual functions is they can
>> be added and removed dynamically as needed.
>
> Hi John,
>
> When VMDQ devices are opened over a virtual function which is
> assigned to guest, the design should include a way to apply the
> following ndo_set_vf_yyy calls to them
>
> int (*ndo_set_vf_mac)(struct net_device *dev, int vf, u8* mac);
> int (*ndo_set_vf_vlan)(struct net_device *dev, int vf, u16 vlan, u8 qos);
> int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate);
> int (*ndo_set_vf_spoofchk)(struct net_device *dev, int vf, bool setting);
>
>
> Someone here suggested using a sub-index notation, that is m.n
> represents vmdq device index = n on VF index = m where vf.0 is
> the non vmdq VF device, makes sense? other thoughts?
>
> Or.
>
That seems reasonable to me. Adding a 'sub' argument to the set
routines should do it. Also the 'get' routines would need to be
extended to report back these virtual net devices.
int (*ndo_set_vf_mac)(struct net_device *dev, int vf, int sub, u8* mac);
int (*ndo_set_vf_vlan)(struct net_device *dev,
int vf, int sub,
u16 vlan, u8 qos);
int (*ndo_set_vf_tx_rate)(struct net_device *dev,
int vf, int sub,
int rate);
int (*ndo_set_vf_spoofchk)(struct net_device *dev,
int vf, int sub,
bool setting);
int (*ndo_get_vf_config)(struct net_device *dev,
int vf, int sub,
struct fila_vf_info *ivf)
I would need to check if any of the ixgbe/igb supported hardware can
support virtual device queues on virtual functions like this but I
presume if your looking at this you have some hardware that can.
I was hoping to get back to this in September, of course if someone
beats me to it that would be great also.
.John
^ permalink raw reply
* Re: [PATCH 2/3] ipvs: Fix faulty IPv6 extension header handling in IPVS
From: Patrick McHardy @ 2012-08-26 21:13 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: netdev, Hans Schillstrom, lvs-devel, Julian Anastasov,
Simon Horman, Wensong Zhang, netfilter-devel
In-Reply-To: <20120820130840.1509.75794.stgit@dragon>
On Mon, 20 Aug 2012, Jesper Dangaard Brouer wrote:
> Based on patch from: Hans Schillstrom
>
> IPv6 headers must be processed in order of appearance,
> neither can it be assumed that Upper layer headers is first.
> If anything else than L4 is the first header IPVS will throw it.
>
> IPVS will write SNAT & DNAT modifications at a fixed pos which
> will corrupt the message. Proper header position must be found
> before writing modifying packet.
>
> This patch contains a lot of API changes. This is done, to avoid
> the costly scan of finding the IPv6 headers, via ipv6_find_hdr().
> Finding the IPv6 headers is done as early as possible, and passed
> on as a pointer "struct ip_vs_iphdr *" to the affected functions.
How about we change netfilter to set up the skb's transport header
at an early time so we can avoid all (most of) these header scans
in netfilter?
^ permalink raw reply
* Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling
From: Patrick McHardy @ 2012-08-26 21:20 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: netfilter-devel, netdev, Julian Anastasov, Hans Schillstrom,
Hans Schillstrom
In-Reply-To: <1345587697.3069.297.camel@localhost>
On Wed, 22 Aug 2012, Jesper Dangaard Brouer wrote:
> On Sun, 2012-08-19 at 21:44 +0200, Patrick McHardy wrote:
>> On Sun, 19 Aug 2012, Jesper Dangaard Brouer wrote:
>>> On Sat, 2012-08-18 at 14:26 +0200, Patrick McHardy wrote:
> [...]
>
>>> Don't I need to load some of the helper modules, or just the
>>> nf_conntrack_ipv6 module, or perhaps only nf_defrag_ipv6 ?
>>
>> Not with the entire patchset, just IPv6 conntrack is enough. Aith IPv6 NAT
>> the first packet of a connection must always be defragemented, independant
>> of an assigned helper.
>
> When loading "nf_conntrack_ipv6" I run into issues.
>
> When sending a fragmented UDP packet. With these patches, the IPVS
> stack will no longer see the fragmented packets, but instead see one
> large SKB. This will trigger a MTU path check in e.g.
> ip_vs_dr_xmit_v6() and an ICMPv6 too big packet is send back.
>
> IPVS: ip_vs_dr_xmit_v6(): frag needed
>
> Perhaps we could change/fix the MTU check in IPVS?
> (This would also solve issues I've seen with TSO/GSO frames, hitting
> this code path).
I guess this should use the same check as in IPv6 output, check
whether IP6CB(skb)->max_frag_size is != 0 and > MTU and only send
an ICMPv6 error in that case.
^ permalink raw reply
* [PATCH] cs89x0 : packet reception not working
From: Jaccon Bastiaansen @ 2012-08-26 21:39 UTC (permalink / raw)
To: davem, joe
Cc: netdev, s.hauer, festevam, Jaccon Bastiaansen, linux-arm-kernel
The RxCFG register of the CS89x0 could be configured incorrectly
(because of misplaced parentheses), resulting in the disabling
of packet reception.
Signed-off-by: Jaccon Bastiaansen <jaccon.bastiaansen@gmail.com>
---
drivers/net/ethernet/cirrus/cs89x0.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
index 845b202..ea521fa 100644
--- a/drivers/net/ethernet/cirrus/cs89x0.c
+++ b/drivers/net/ethernet/cirrus/cs89x0.c
@@ -1261,10 +1261,10 @@ static void set_multicast_list(struct net_device *dev)
* so we have to enable interrupts on them also
*/
writereg(dev, PP_RxCFG,
- (lp->curr_rx_cfg |
- (lp->rx_mode == RX_ALL_ACCEPT)
- ? (RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL)
- : 0));
+ lp->curr_rx_cfg |
+ (lp->rx_mode == RX_ALL_ACCEPT
+ ? (RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL)
+ : 0));
spin_unlock_irqrestore(&lp->lock, flags);
}
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] cs89x0 : packet reception not working
From: Joe Perches @ 2012-08-26 22:26 UTC (permalink / raw)
To: Jaccon Bastiaansen; +Cc: davem, linux-arm-kernel, netdev, s.hauer, festevam
In-Reply-To: <1346017146-28248-1-git-send-email-jaccon.bastiaansen@gmail.com>
On Sun, 2012-08-26 at 23:39 +0200, Jaccon Bastiaansen wrote:
> The RxCFG register of the CS89x0 could be configured incorrectly
> (because of misplaced parentheses), resulting in the disabling
> of packet reception.
Thanks.
> diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
[]
> @@ -1261,10 +1261,10 @@ static void set_multicast_list(struct net_device *dev)
> * so we have to enable interrupts on them also
> */
> writereg(dev, PP_RxCFG,
> - (lp->curr_rx_cfg |
> - (lp->rx_mode == RX_ALL_ACCEPT)
> - ? (RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL)
> - : 0));
> + lp->curr_rx_cfg |
> + (lp->rx_mode == RX_ALL_ACCEPT
> + ? (RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL)
> + : 0));
> spin_unlock_irqrestore(&lp->lock, flags);
> }
Perhaps it would be better to use something like:
int cfg = lp->curr_rx_cfg;
if (lp->rx_mode == RX_ALL_ACCEPT)
cfg |= RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL;
writereg(dev, PP_RxCFG, cfg);
^ permalink raw reply
* Re: [PATCH v2 01/10] cgroup: net_cls: Use empty task_cls_classid() when !CONFIG_NET_CLS(_MODULE)
From: Li Zefan @ 2012-08-27 2:32 UTC (permalink / raw)
To: Daniel Wagner
Cc: netdev, cgroups, Daniel Wagner, David S. Miller, Gao feng,
Jamal Hadi Salim, John Fastabend, Neil Horman, Tejun Heo
In-Reply-To: <1345816904-21745-2-git-send-email-wagi@monom.org>
task_cls_classid() is called by sock_update_classid().
#ifdef CONFIG_CGROUPS
extern void sock_update_classid(struct sock *sk);
#else
static inline void sock_update_classid(struct sock *sk)
{
}
#endif
Change to define sock_update_classid() only when CONFIG_NET_CLS is enabled, and
then we don't need this patch, and the code will be simpler.
On 2012/8/24 22:01, Daniel Wagner wrote:
> From: Daniel Wagner <daniel.wagner@bmw-carit.de>
>
> Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Gao feng <gaofeng@cn.fujitsu.com>
> Cc: Jamal Hadi Salim <jhs@mojatatu.com>
> Cc: John Fastabend <john.r.fastabend@intel.com>
> Cc: Li Zefan <lizefan@huawei.com>
> Cc: Neil Horman <nhorman@tuxdriver.com>
> Cc: Tejun Heo <tj@kernel.org>
> Cc: netdev@vger.kernel.org
> Cc: cgroups@vger.kernel.org
> ---
> include/net/cls_cgroup.h | 16 ++++++++++++----
> 1 file changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
> index a4dc5b0..e2fe2b9 100644
> --- a/include/net/cls_cgroup.h
> +++ b/include/net/cls_cgroup.h
> @@ -24,7 +24,8 @@ struct cgroup_cls_state
> u32 classid;
> };
>
> -#ifdef CONFIG_NET_CLS_CGROUP
> +#if IS_BUILTIN(CONFIG_NET_CLS_CGROUP)
> +
> static inline u32 task_cls_classid(struct task_struct *p)
> {
> int classid;
> @@ -39,7 +40,9 @@ static inline u32 task_cls_classid(struct task_struct *p)
>
> return classid;
> }
> -#else
> +
> +#elif IS_MODULE(CONFIG_NET_CLS_CGROUP)
> +
> extern int net_cls_subsys_id;
>
> static inline u32 task_cls_classid(struct task_struct *p)
> @@ -60,11 +63,16 @@ static inline u32 task_cls_classid(struct task_struct *p)
>
> return classid;
> }
> -#endif
> +
> #else
> +
> static inline u32 task_cls_classid(struct task_struct *p)
> {
> return 0;
> }
> -#endif
> +
> +#endif /* CONFIG_NET_CLS_CGROUP */
> +
> +#endif /* CONFIG_CGROURPS */
> +
> #endif /* _NET_CLS_CGROUP_H */
>
^ permalink raw reply
* [PATCH] decnet: fix shutdown parameter checking
From: Xi Wang @ 2012-08-27 2:37 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, linux-kernel, Xi Wang
The allowed value of "how" is SHUT_RD/SHUT_WR/SHUT_RDWR (0/1/2),
rather than SHUTDOWN_MASK (3).
Signed-off-by: Xi Wang <xi.wang@gmail.com>
---
net/decnet/af_decnet.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 2ba1a28..307c322 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1313,10 +1313,10 @@ static int dn_shutdown(struct socket *sock, int how)
if (scp->state == DN_O)
goto out;
- if (how != SHUTDOWN_MASK)
+ if (how != SHUT_RDWR)
goto out;
- sk->sk_shutdown = how;
+ sk->sk_shutdown = SHUTDOWN_MASK;
dn_destroy_sock(sk);
err = 0;
--
1.7.9.5
^ permalink raw reply related
* [PATCH] af_unix: fix shutdown parameter checking
From: Xi Wang @ 2012-08-27 2:47 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, linux-kernel, Xi Wang
Return -EINVAL rather than 0 given an invalid "mode" parameter.
Signed-off-by: Xi Wang <xi.wang@gmail.com>
---
Another way to check "mode" is as in inet_shutdown():
mode++;
if ((mode & ~SHUTDOWN_MASK) || !mode)
return -EINVAL;
This patch uses a simpler form, to check if "mode" is in the range
SHUT_RD ... SHUT_RDWR.
---
net/unix/af_unix.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c5ee4ff..8a84ab6 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2060,10 +2060,14 @@ static int unix_shutdown(struct socket *sock, int mode)
struct sock *sk = sock->sk;
struct sock *other;
- mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN);
-
- if (!mode)
- return 0;
+ if (mode < SHUT_RD || mode > SHUT_RDWR)
+ return -EINVAL;
+ /* This maps:
+ * SHUT_RD (0) -> RCV_SHUTDOWN (1)
+ * SHUT_WR (1) -> SEND_SHUTDOWN (2)
+ * SHUT_RDWR (2) -> SHUTDOWN_MASK (3)
+ */
+ ++mode;
unix_state_lock(sk);
sk->sk_shutdown |= mode;
--
1.7.9.5
^ permalink raw reply related
* Re: BUG: soft lockup - CPU#6 stuck for 22s! [httpd2-event:15597]
From: Neal Cardwell @ 2012-08-27 4:02 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Cristian Rodríguez, Netdev, Yuchung Cheng
In-Reply-To: <1345895225.19483.447.camel@edumazet-glaptop>
On Sat, Aug 25, 2012 at 7:47 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Sat, 2012-08-25 at 11:14 +0200, Eric Dumazet wrote:
>> From: Eric Dumazet <edumazet@google.com>
>>
>> On Sat, 2012-08-25 at 10:59 +0200, Eric Dumazet wrote:
>> > On Fri, 2012-08-24 at 20:50 -0400, Cristian Rodríguez wrote:
>> > > Hi, the issue I reported with IPV6 few weeks ago seems to be gone, but
>> > > now I am getting the following crash..
>>
>> > Oh, I now see the bug, I'll send a patch asap
>>
>> Please try the following fix.
>>
>> Thanks !
>
> Well, this v2 seems cleaner :
>
> [PATCH v2] tcp: tcp_slow_start() should not decrease snd_cwnd
>
> Cristian Rodríguez reported various lockups in TCP stack,
> introduced by commit 9dc274151a548 (tcp: fix ABC in tcp_slow_start())
>
> We could exit tcp_slow_start() with a zeroed snd_cwnd,
> and next time we enter tcp_slow_start(), we run an infinite loop.
>
> Reported-by: Cristian Rodríguez <crrodriguez@opensuse.org>
> Cc: Yuchung Cheng <ycheng@google.com>
> Cc: Neal Cardwell <ncardwell@google.com>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> ---
> net/ipv4/tcp_cong.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
> index 1432cdb..e656c72 100644
> --- a/net/ipv4/tcp_cong.c
> +++ b/net/ipv4/tcp_cong.c
> @@ -337,7 +337,7 @@ void tcp_slow_start(struct tcp_sock *tp)
> tp->snd_cwnd_cnt -= tp->snd_cwnd;
> delta++;
> }
> - tp->snd_cwnd = min(tp->snd_cwnd + delta, tp->snd_cwnd_clamp);
> + tp->snd_cwnd = clamp(tp->snd_cwnd + delta, tp->snd_cwnd, tp->snd_cwnd_clamp);
AFAICT if tcp_slow_start() is changing snd_cwnd from non-zero to zero
then this is because snd_cwnd_clamp is zero here, as you theorize may
be happening to races somewhere.
However, AFAICT from reading the min() and clamp() macros, this code
with clamp() will still have the same problem as the existing code
that uses min: if snd_cwnd_clamp is 0 then snd_cwnd will end up 0
here. (This is because the clamp() macro implicitly assumes that the
max value is above the min value, and filters agains the max last.)
neal
^ permalink raw reply
* Re: BUG: soft lockup - CPU#6 stuck for 22s! [httpd2-event:15597]
From: Eric Dumazet @ 2012-08-27 4:06 UTC (permalink / raw)
To: Neal Cardwell; +Cc: Cristian Rodríguez, Netdev, Yuchung Cheng
In-Reply-To: <CADVnQymYXHcqJEgcgH0OHHFfCe6LAMSBZ0E68NWzDZQNTqB+Sg@mail.gmail.com>
On Mon, 2012-08-27 at 00:02 -0400, Neal Cardwell wrote:
> On Sat, Aug 25, 2012 at 7:47 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> > On Sat, 2012-08-25 at 11:14 +0200, Eric Dumazet wrote:
> >> From: Eric Dumazet <edumazet@google.com>
> >>
> >> On Sat, 2012-08-25 at 10:59 +0200, Eric Dumazet wrote:
> >> > On Fri, 2012-08-24 at 20:50 -0400, Cristian Rodríguez wrote:
> >> > > Hi, the issue I reported with IPV6 few weeks ago seems to be gone, but
> >> > > now I am getting the following crash..
> >>
> >> > Oh, I now see the bug, I'll send a patch asap
> >>
> >> Please try the following fix.
> >>
> >> Thanks !
> >
> > Well, this v2 seems cleaner :
> >
> > [PATCH v2] tcp: tcp_slow_start() should not decrease snd_cwnd
> >
> > Cristian Rodríguez reported various lockups in TCP stack,
> > introduced by commit 9dc274151a548 (tcp: fix ABC in tcp_slow_start())
> >
> > We could exit tcp_slow_start() with a zeroed snd_cwnd,
> > and next time we enter tcp_slow_start(), we run an infinite loop.
> >
> > Reported-by: Cristian Rodríguez <crrodriguez@opensuse.org>
> > Cc: Yuchung Cheng <ycheng@google.com>
> > Cc: Neal Cardwell <ncardwell@google.com>
> > Signed-off-by: Eric Dumazet <edumazet@google.com>
> > ---
> > net/ipv4/tcp_cong.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
> > index 1432cdb..e656c72 100644
> > --- a/net/ipv4/tcp_cong.c
> > +++ b/net/ipv4/tcp_cong.c
> > @@ -337,7 +337,7 @@ void tcp_slow_start(struct tcp_sock *tp)
> > tp->snd_cwnd_cnt -= tp->snd_cwnd;
> > delta++;
> > }
> > - tp->snd_cwnd = min(tp->snd_cwnd + delta, tp->snd_cwnd_clamp);
> > + tp->snd_cwnd = clamp(tp->snd_cwnd + delta, tp->snd_cwnd, tp->snd_cwnd_clamp);
>
> AFAICT if tcp_slow_start() is changing snd_cwnd from non-zero to zero
> then this is because snd_cwnd_clamp is zero here, as you theorize may
> be happening to races somewhere.
>
> However, AFAICT from reading the min() and clamp() macros, this code
> with clamp() will still have the same problem as the existing code
> that uses min: if snd_cwnd_clamp is 0 then snd_cwnd will end up 0
> here. (This is because the clamp() macro implicitly assumes that the
> max value is above the min value, and filters agains the max last.)
>
Indeed, so the first patch was better...
Not sure I can investigate this problem this week, as I attend LKS/LPC
in San Diego.
Could be that snd_cwnd is zero as well so we have this infinite loop...
while (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
tp->snd_cwnd_cnt -= tp->snd_cwnd;
delta++;
}
^ permalink raw reply
* [PATCH] openvswitch: using kfree_rcu() to simplify the code
From: Wei Yongjun @ 2012-08-27 4:20 UTC (permalink / raw)
To: jesse-l0M0P4e3n4LQT0dZR+AlfA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: dev-yBygre7rU0TnMu66kgdUjQ, netdev-u79uwXL29TY76Z2rM5mHXA,
yongjun_wei-zrsr2BFq86L20UzCJQGyNP8+0UxHXcjY
From: Wei Yongjun <yongjun_wei-zrsr2BFq86L20UzCJQGyNP8+0UxHXcjY@public.gmane.org>
The callback function of call_rcu() just calls a kfree(), so we
can use kfree_rcu() instead of call_rcu() + callback function.
spatch with a semantic match is used to found this problem.
(http://coccinelle.lip6.fr/)
Signed-off-by: Wei Yongjun <yongjun_wei-zrsr2BFq86L20UzCJQGyNP8+0UxHXcjY@public.gmane.org>
---
net/openvswitch/flow.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index b7f38b1..c7bf2f2 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -427,19 +427,11 @@ void ovs_flow_deferred_free(struct sw_flow *flow)
call_rcu(&flow->rcu, rcu_free_flow_callback);
}
-/* RCU callback used by ovs_flow_deferred_free_acts. */
-static void rcu_free_acts_callback(struct rcu_head *rcu)
-{
- struct sw_flow_actions *sf_acts = container_of(rcu,
- struct sw_flow_actions, rcu);
- kfree(sf_acts);
-}
-
/* Schedules 'sf_acts' to be freed after the next RCU grace period.
* The caller must hold rcu_read_lock for this to be sensible. */
void ovs_flow_deferred_free_acts(struct sw_flow_actions *sf_acts)
{
- call_rcu(&sf_acts->rcu, rcu_free_acts_callback);
+ kfree_rcu(sf_acts, rcu);
}
static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
^ permalink raw reply related
* [PATCHv3 0/4] modem_shm: U8500 SHaRed Memory driver(SHRM)
From: Arun Murthy @ 2012-08-27 5:49 UTC (permalink / raw)
To: linux-kernel, netdev, linux-doc, gregkh, alan; +Cc: arun.murthy
In u8500 platform the communication between the APE(Application Processor) and
the modem subsystem(CMT) is by means of a shared DDR. The series of patches
include a protocol called ShaRed Memory(SHRM) protocol for communicating
between the APE and the CMT.
Interrupt generation registers in CMT and PRCMU on APE side are used to support
the shrm protocol.
v2 - Included netdev mailing list
v3 - Implemented comments from Alan Cox and Greg KH
Arun Murthy (4):
modem_shm: Add Modem Access Framework
modem_shm: Register u8500 client for MAF
modem_shm: u8500-shm: U8500 Shared Memory Driver
Doc: Add u8500_shrm document
Documentation/DocBook/Makefile | 2 +-
Documentation/DocBook/shrm.tmpl | 125 +++
Documentation/modem_shm/u8500_shrm.txt | 254 +++++
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/modem_shm/Kconfig | 22 +
drivers/modem_shm/Makefile | 3 +
drivers/modem_shm/modem_access.c | 413 +++++++
drivers/modem_shm/modem_u8500.c | 96 ++
drivers/modem_shm/u8500_shm/Kconfig | 43 +
drivers/modem_shm/u8500_shm/Makefile | 7 +
drivers/modem_shm/u8500_shm/shrm.h | 23 +
drivers/modem_shm/u8500_shm/shrm_char.c | 816 ++++++++++++++
drivers/modem_shm/u8500_shm/shrm_config.h | 114 ++
drivers/modem_shm/u8500_shm/shrm_driver.c | 733 ++++++++++++
drivers/modem_shm/u8500_shm/shrm_driver.h | 226 ++++
drivers/modem_shm/u8500_shm/shrm_fifo.c | 838 ++++++++++++++
drivers/modem_shm/u8500_shm/shrm_ioctl.h | 43 +
drivers/modem_shm/u8500_shm/shrm_net.c | 313 ++++++
drivers/modem_shm/u8500_shm/shrm_net.h | 46 +
drivers/modem_shm/u8500_shm/shrm_private.h | 184 +++
drivers/modem_shm/u8500_shm/shrm_protocol.c | 1591 +++++++++++++++++++++++++++
include/linux/modem_shm/modem.h | 64 ++
include/linux/modem_shm/modem_client.h | 55 +
24 files changed, 6013 insertions(+), 1 deletions(-)
create mode 100644 Documentation/DocBook/shrm.tmpl
create mode 100644 Documentation/modem_shm/u8500_shrm.txt
create mode 100644 drivers/modem_shm/Kconfig
create mode 100644 drivers/modem_shm/Makefile
create mode 100644 drivers/modem_shm/modem_access.c
create mode 100644 drivers/modem_shm/modem_u8500.c
create mode 100644 drivers/modem_shm/u8500_shm/Kconfig
create mode 100644 drivers/modem_shm/u8500_shm/Makefile
create mode 100644 drivers/modem_shm/u8500_shm/shrm.h
create mode 100644 drivers/modem_shm/u8500_shm/shrm_char.c
create mode 100644 drivers/modem_shm/u8500_shm/shrm_config.h
create mode 100644 drivers/modem_shm/u8500_shm/shrm_driver.c
create mode 100644 drivers/modem_shm/u8500_shm/shrm_driver.h
create mode 100644 drivers/modem_shm/u8500_shm/shrm_fifo.c
create mode 100644 drivers/modem_shm/u8500_shm/shrm_ioctl.h
create mode 100644 drivers/modem_shm/u8500_shm/shrm_net.c
create mode 100644 drivers/modem_shm/u8500_shm/shrm_net.h
create mode 100644 drivers/modem_shm/u8500_shm/shrm_private.h
create mode 100644 drivers/modem_shm/u8500_shm/shrm_protocol.c
create mode 100644 include/linux/modem_shm/modem.h
create mode 100644 include/linux/modem_shm/modem_client.h
--
1.7.4.3
^ permalink raw reply
* [PATCHv3 1/4] modem_shm: Add Modem Access Framework
From: Arun Murthy @ 2012-08-27 5:49 UTC (permalink / raw)
To: linux-kernel, netdev, linux-doc, gregkh, alan; +Cc: arun.murthy
In-Reply-To: <1346046569-8050-1-git-send-email-arun.murthy@stericsson.com>
Adds Modem Access Framework, which allows for registering platform specific
modem access mechanisms. The framework also exposes APIs for client drivers
for getting and releasing access to modem, regardless of the underlying
platform specific access mechanism.
Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
---
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/modem_shm/Kconfig | 9 +
drivers/modem_shm/Makefile | 1 +
drivers/modem_shm/modem_access.c | 413 ++++++++++++++++++++++++++++++++
include/linux/modem_shm/modem.h | 64 +++++
include/linux/modem_shm/modem_client.h | 55 +++++
7 files changed, 545 insertions(+), 0 deletions(-)
create mode 100644 drivers/modem_shm/Kconfig
create mode 100644 drivers/modem_shm/Makefile
create mode 100644 drivers/modem_shm/modem_access.c
create mode 100644 include/linux/modem_shm/modem.h
create mode 100644 include/linux/modem_shm/modem_client.h
diff --git a/drivers/Kconfig b/drivers/Kconfig
index ece958d..dc7c14a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -152,4 +152,6 @@ source "drivers/vme/Kconfig"
source "drivers/pwm/Kconfig"
+source "drivers/modem_shm/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 5b42184..902dfec 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -139,3 +139,4 @@ obj-$(CONFIG_EXTCON) += extcon/
obj-$(CONFIG_MEMORY) += memory/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_VME_BUS) += vme/
+obj-$(CONFIG_MODEM_SHM) += modem_shm/
diff --git a/drivers/modem_shm/Kconfig b/drivers/modem_shm/Kconfig
new file mode 100644
index 0000000..f4b7e54
--- /dev/null
+++ b/drivers/modem_shm/Kconfig
@@ -0,0 +1,9 @@
+config MODEM_SHM
+ bool "Modem Access Framework"
+ default n
+ help
+ Add support for Modem Access Framework. It allows different
+ platform specific drivers to register modem access mechanisms
+ and allows transparent access to modem to the client drivers.
+
+ If unsure, say N.
diff --git a/drivers/modem_shm/Makefile b/drivers/modem_shm/Makefile
new file mode 100644
index 0000000..b77bcc0
--- /dev/null
+++ b/drivers/modem_shm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MODEM_SHM) := modem_access.o
diff --git a/drivers/modem_shm/modem_access.c b/drivers/modem_shm/modem_access.c
new file mode 100644
index 0000000..b4bb4b7
--- /dev/null
+++ b/drivers/modem_shm/modem_access.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi
+ * Arun Murthy <arun.murthy@stericsson.com>
+ *
+ * Heavily adapted from Regulator framework.
+ * Provides mechanisms for registering platform specific access
+ * mechanisms for modem.
+ * Also, exposes APIs for gettng/releasing the access and even
+ * query the access status, and the modem usage status.
+ */
+#include <linux/module.h>
+#include <linux/modem_shm/modem.h>
+#include <linux/modem_shm/modem_client.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+static DEFINE_MUTEX(modem_list_mutex);
+static LIST_HEAD(modem_list);
+
+struct modem {
+ struct device *dev;
+ struct list_head list;
+ char *modem_name;
+ struct device_attribute dev_attr;
+ struct modem_dev *mdev;
+ atomic_t use;
+};
+
+static enum mod_state {
+ MOD_RELEASED,
+ MOD_ACCESSED,
+};
+
+static const char *mdev_get_name(struct modem_dev *mdev)
+{
+ if (mdev->desc->name)
+ return mdev->desc->name;
+ else
+ return "";
+}
+
+static int _modem_is_requested(struct modem_dev *mdev)
+{
+ /* If we don't know then assume that the modem is always on */
+ if (!mdev->desc->ops->is_requested)
+ return 0;
+
+ return mdev->desc->ops->is_requested(mdev);
+}
+
+/**
+ * modem_is_requested - check if modem access is requested
+ * @modem: modem device
+ *
+ * Checks whether modem is accessed or not by querying
+ * the underlying platform specific modem access
+ * implementation.
+ */
+int modem_is_requested(struct modem *modem)
+{
+ int ret;
+
+ mutex_lock(&modem->mdev->mutex);
+ ret = _modem_is_requested(modem->mdev);
+ mutex_unlock(&modem->mdev->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(modem_is_requested);
+
+static int _modem_request(struct modem_dev *mdev)
+{
+ int ret;
+
+ if (++mdev->use_count == 1) {
+ ret = _modem_is_requested(mdev);
+ if (ret == 0)
+ mdev->desc->ops->request(mdev);
+ }
+
+ return 0;
+}
+
+/**
+ * modem_request - Request access the modem
+ * @modem: modem device
+ *
+ * API to access the modem. It keeps a client
+ * specific check on whether the particular modem
+ * requested is accessed or not.
+ */
+int modem_request(struct modem *modem)
+{
+ struct modem_dev *mdev = modem->mdev;
+ int ret = 0;
+
+
+ mutex_lock(&mdev->mutex);
+ if (atomic_read(&modem->use) == 1) {
+ mutex_unlock(&mdev->mutex);
+ return ret;
+ }
+ ret = _modem_request(mdev);
+ if (ret == 0)
+ atomic_set(&modem->use, 1);
+ mutex_unlock(&mdev->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(modem_request);
+
+static int _modem_release(struct modem_dev *mdev)
+{
+ if (WARN(mdev->use_count <= 0,
+ "unbalanced releases for %s\n",
+ mdev_get_name(mdev)))
+ return -EIO;
+
+ if (--mdev->use_count == 0)
+ mdev->desc->ops->release(mdev);
+
+ return 0;
+}
+
+/**
+ * modem_release - Release access to modem
+ * @modem: modem device
+ *
+ * Releases accesss to the modem. It keeps a client
+ * specific check on whether a particular modem
+ * is released or not.
+ */
+void modem_release(struct modem *modem)
+{
+ struct modem_dev *mdev = modem->mdev;
+ int ret = 0;
+
+ mutex_lock(&mdev->mutex);
+ if (atomic_read(&modem->use) == 0) {
+ mutex_unlock(&mdev->mutex);
+ return;
+ }
+ ret = _modem_release(mdev);
+ if (ret == 0)
+ atomic_set(&modem->use, 0);
+ mutex_unlock(&mdev->mutex);
+}
+EXPORT_SYMBOL_GPL(modem_release);
+
+/**
+ * modem_get_usage - Check if particular client is using modem
+ * @modem: modem device
+ *
+ * Checks whether the particular client is using access to modem.
+ * This API could be used by client drivers in making their
+ * suspend decisions.
+ */
+int modem_get_usage(struct modem *modem)
+{
+ return atomic_read(&modem->use);
+}
+EXPORT_SYMBOL_GPL(modem_get_usage);
+
+static struct modem *create_modem(struct modem_dev *mdev,
+ struct device *dev,
+ const char *id)
+{
+ struct modem *modem;
+
+ modem = kzalloc(sizeof(*modem), GFP_KERNEL);
+ if (modem == NULL)
+ return NULL;
+
+ mutex_lock(&mdev->mutex);
+ modem->mdev = mdev;
+ modem->dev = dev;
+ list_add(&modem->list, &mdev->client_list);
+
+ mutex_unlock(&mdev->mutex);
+ return modem;
+
+}
+
+static struct modem *_modem_get(struct device *dev, const char *id,
+ int exclusive)
+{
+ struct modem_dev *mdev_ptr;
+ struct modem *modem = ERR_PTR(-ENODEV);
+ int ret;
+
+ if (id == NULL) {
+ pr_err("modem_get with no identifier\n");
+ return modem;
+ }
+
+ mutex_lock(&modem_list_mutex);
+ list_for_each_entry(mdev_ptr, &modem_list, modem_list) {
+ if (strcmp(mdev_get_name(mdev_ptr), id) == 0)
+ goto found;
+ }
+
+ goto out;
+
+found:
+ if (!try_module_get(mdev_ptr->owner))
+ goto out;
+
+ modem = create_modem(mdev_ptr, dev, id);
+ if (modem == NULL) {
+ modem = ERR_PTR(-ENOMEM);
+ module_put(mdev_ptr->owner);
+ }
+
+ mdev_ptr->open_count++;
+ ret = _modem_is_requested(mdev_ptr);
+ if (ret)
+ mdev_ptr->use_count = 1;
+ else
+ mdev_ptr->use_count = 0;
+
+out:
+ mutex_unlock(&modem_list_mutex);
+ return modem;
+
+}
+
+/**
+ * modem_get - Get reference to a particular platform specific modem
+ * @dev: device
+ * @id: modem device name
+ *
+ * Get reference to a particular modem device.
+ */
+struct modem *modem_get(struct device *dev, const char *id)
+{
+ return _modem_get(dev, id, 0);
+}
+EXPORT_SYMBOL_GPL(modem_get);
+
+/**
+ * modem_put - Release reference to a modem device
+ * @modem: modem device
+ *
+ * Release reference to a modem device.
+ */
+void modem_put(struct modem *modem)
+{
+ struct modem_dev *mdev;
+
+ if (modem == NULL || IS_ERR(modem))
+ return;
+
+ mutex_lock(&modem_list_mutex);
+ mdev = modem->mdev;
+
+ list_del(&modem->list);
+ kfree(modem);
+
+ mdev->open_count--;
+
+ module_put(mdev->owner);
+ mutex_unlock(&modem_list_mutex);
+}
+EXPORT_SYMBOL_GPL(modem_put);
+
+static ssize_t modem_print_state(char *buf, int state)
+{
+ if (state > MOD_ACCESSED)
+ return sprintf(buf, "accessed\n");
+ else if (state == MOD_RELEASED)
+ return sprintf(buf, "released\n");
+ else
+ return sprintf(buf, "unknown\n");
+}
+
+static ssize_t modem_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct modem_dev *mdev = dev_get_drvdata(dev);
+ ssize_t ret;
+
+ mutex_lock(&mdev->mutex);
+ ret = modem_print_state(buf, _modem_is_requested(mdev));
+ mutex_unlock(&mdev->mutex);
+
+ return ret;
+}
+static DEVICE_ATTR(state, (S_IWUSR | S_IRGRP | S_IROTH),
+ modem_state_show, NULL);
+
+static ssize_t modem_use_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct modem_dev *mdev = dev_get_drvdata(dev);
+ struct modem *mod;
+ size_t size = 0;
+
+ list_for_each_entry(mod, &mdev->client_list, list) {
+ if (mod->dev != NULL)
+ size += sprintf((buf + size), "%s (%d)\n",
+ dev_name(mod->dev), atomic_read(&mod->use));
+ else
+ size += sprintf((buf + size), "unknown (%d)\n",
+ atomic_read(&mod->use));
+ }
+ size += sprintf((buf + size), "\n");
+
+ return size;
+}
+static DEVICE_ATTR(use, (S_IWUSR | S_IRGRP | S_IROTH), modem_use_show, NULL);
+
+static ssize_t modem_num_active_users_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct modem_dev *mdev = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", mdev->use_count);
+}
+static DEVICE_ATTR(num_active_users, (S_IWUSR | S_IRGRP | S_IROTH),
+ modem_num_active_users_show, NULL);
+
+static int add_modem_attributes(struct modem_dev *mdev)
+{
+ struct device *dev = &mdev->dev;
+ struct modem_ops *ops = mdev->desc->ops;
+ int status = 0;
+
+ status = device_create_file(dev, &dev_attr_use);
+ if (status < 0)
+ return status;
+
+ status = device_create_file(dev, &dev_attr_num_active_users);
+ if (status < 0)
+ return status;
+
+ if (ops->is_requested) {
+ status = device_create_file(dev, &dev_attr_state);
+ if (status < 0)
+ return status;
+ }
+
+ return 0;
+}
+
+/**
+ * modem_register - register a modem
+ * @modem_desc: - description for modem
+ * @dev: - device
+ * @driver_data:- driver specific data
+ *
+ * Register a modem with the modem access framework, so that
+ * it could be used by client drivers for accessing the
+ * modem.
+ */
+struct modem_dev *modem_register(struct modem_desc *modem_desc,
+ struct device *dev,
+ void *driver_data)
+{
+ static atomic_t modem_no = ATOMIC_INIT(0);
+ struct modem_dev *mdev;
+ int ret;
+
+ if (modem_desc == NULL)
+ return ERR_PTR(-EINVAL);
+
+ if (modem_desc->name == NULL || modem_desc->ops == NULL)
+ return ERR_PTR(-EINVAL);
+
+ mdev = kzalloc(sizeof(struct modem_dev), GFP_KERNEL);
+ if (mdev == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_lock(&modem_list_mutex);
+
+ mutex_init(&mdev->mutex);
+ mdev->modem_data = driver_data;
+ mdev->owner = modem_desc->owner;
+ mdev->desc = modem_desc;
+ INIT_LIST_HEAD(&mdev->client_list);
+ INIT_LIST_HEAD(&mdev->modem_list);
+ BLOCKING_INIT_NOTIFIER_HEAD(&mdev->notifier);
+
+ /* mdev->dev.class = &modem_class;*/
+ mdev->dev.parent = dev;
+ dev_set_name(&mdev->dev, "modem.%d", atomic_inc_return(&modem_no) - 1);
+ ret = device_register(&mdev->dev);
+ if (ret != 0)
+ goto clean;
+
+ dev_set_drvdata(&mdev->dev, mdev);
+
+ ret = add_modem_attributes(mdev);
+ if (ret < 0)
+ goto backoff;
+
+ list_add(&mdev->modem_list, &modem_list);
+
+out:
+ mutex_unlock(&modem_list_mutex);
+ return mdev;
+
+backoff:
+ device_unregister(&mdev->dev);
+ mdev = ERR_PTR(ret);
+ goto out;
+
+clean:
+ kfree(mdev);
+ mdev = ERR_PTR(ret);
+ goto out;
+}
+EXPORT_SYMBOL_GPL(modem_register);
diff --git a/include/linux/modem_shm/modem.h b/include/linux/modem_shm/modem.h
new file mode 100644
index 0000000..aab636a
--- /dev/null
+++ b/include/linux/modem_shm/modem.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi
+ * Arun Murthy <arun.murthy@stericsson.com>
+ *
+ * Heavily adapted from Regulator framework
+ */
+#ifndef __MODEM_H__
+#define __MODEM_H__
+
+#include <linux/device.h>
+
+struct modem_dev;
+
+struct modem_ops {
+ int (*request)(struct modem_dev *);
+ void (*release)(struct modem_dev *);
+ int (*is_requested)(struct modem_dev *);
+};
+
+struct modem_desc {
+ const char *name;
+ int id;
+ struct modem_ops *ops;
+ struct module *owner;
+};
+
+struct modem_dev {
+ struct modem_desc *desc;
+ int use_count;
+ int open_count;
+ int exclusive;
+
+ struct list_head modem_list;
+
+ struct list_head client_list;
+
+ struct blocking_notifier_head notifier;
+ struct mutex mutex;
+ struct module *owner;
+ struct device dev;
+ void *modem_data;
+};
+
+#ifdef CONFIG_MODEM_SHM
+struct modem_dev *modem_register(struct modem_desc *modem_desc,
+ struct device *dev,
+ void *driver_data);
+void modem_unregister(struct modem_dev *mdev);
+
+#else
+static inline struct modem_dev *modem_register(struct modem_desc *modem_desc,
+ struct device *dev, void *driver_data)
+{
+ return NULL;
+}
+
+static inline void modem_unregister(struct modem_dev *mdev)
+{
+}
+#endif
+#endif /* __MODEM_H__ */
diff --git a/include/linux/modem_shm/modem_client.h b/include/linux/modem_shm/modem_client.h
new file mode 100644
index 0000000..ad7406a
--- /dev/null
+++ b/include/linux/modem_shm/modem_client.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi
+ * Arun Murthy <arun.murthy@stericsson.com>
+ *
+ * Heavily adapted from Regulator framework
+ */
+#ifndef __MODEM_CLIENT_H__
+#define __MODEM_CLIENT_H__
+
+#include <linux/device.h>
+
+struct modem;
+
+#ifdef CONFIG_MODEM_SHM
+struct modem *modem_get(struct device *dev, const char *id);
+void modem_put(struct modem *modem);
+int modem_request(struct modem *modem);
+void modem_release(struct modem *modem);
+int modem_is_requested(struct modem *modem);
+int modem_get_usage(struct modem *modem);
+
+#else
+
+static inline struct modem *modem_get(struct device *dev, const char *id)
+{
+ return NULL;
+}
+
+static inline void modem_put(struct modem *modem)
+{
+}
+
+static inline int modem_request(struct modem *modem)
+{
+ return 0;
+}
+
+static inline void modem_release(struct modem *modem)
+{
+}
+
+static inline int modem_is_requested(struct modem *modem)
+{
+ return 0;
+}
+
+static inline int modem_get_usage(struct modem *modem)
+{
+ return 0;
+}
+#endif
+#endif /* __MODEM_CLIENT_H__ */
--
1.7.4.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox