|
|
|
@ -0,0 +1,382 @@
|
|
|
|
|
## DP: maclist interface
|
|
|
|
|
## DP: Patch author: John Bowler <jbowler@acm.org>
|
|
|
|
|
## DP: Upstream status: not yet submitted!
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
--- linux-2.6.15/include/net/maclist.h 1970-01-01 00:00:00.000000000 +0000
|
|
|
|
|
+++ linux-2.6.15/include/net/maclist.h 1970-01-01 00:00:00.000000000 +0000
|
|
|
|
|
@@ -0,0 +1,23 @@
|
|
|
|
|
+#ifndef _MACLIST_H
|
|
|
|
|
+#define _MACLIST_H 1
|
|
|
|
|
+/*
|
|
|
|
|
+ * Interfaces to the MAC repository
|
|
|
|
|
+ */
|
|
|
|
|
+/*
|
|
|
|
|
+ * Add a single entry, returns 0 on success else an error
|
|
|
|
|
+ * code. Must *not* be called from an interrupt handler.
|
|
|
|
|
+ */
|
|
|
|
|
+extern int maclist_add(const u8 id_to_add[6]);
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Return the current entry count (valid in any context).
|
|
|
|
|
+ */
|
|
|
|
|
+extern int maclist_count(void);
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Return the ID from the n'th entry (valid in any context),
|
|
|
|
|
+ * returns 0 on success, -EINVAL if 'n' is out of range.
|
|
|
|
|
+ */
|
|
|
|
|
+extern int maclist_read(u8 (*buffer_for_id)[6], int index_of_id_to_return);
|
|
|
|
|
+
|
|
|
|
|
+#endif /*_MACLIST_H*/
|
|
|
|
|
--- linux-2.6.15/drivers/net/maclist.c 1970-01-01 00:00:00.000000000 +0000
|
|
|
|
|
+++ linux-2.6.15/drivers/net/maclist.c 1970-01-01 00:00:00.000000000 +0000
|
|
|
|
|
@@ -0,0 +1,314 @@
|
|
|
|
|
+/*
|
|
|
|
|
+ * drivers/net/maclist.c
|
|
|
|
|
+ *
|
|
|
|
|
+ * a simple driver to remember ethernet MAC values
|
|
|
|
|
+ *
|
|
|
|
|
+ * Some Ethernet hardware implementations have no built-in
|
|
|
|
|
+ * storage for allocated MAC values - an example is the Intel
|
|
|
|
|
+ * IXP420 chip which has support for Ethernet but no defined
|
|
|
|
|
+ * way of storing allocated MAC values. With such hardware
|
|
|
|
|
+ * different board level implementations store the allocated
|
|
|
|
|
+ * MAC (or MACs) in different ways. Rather than put board
|
|
|
|
|
+ * level code into a specific Ethernet driver this driver
|
|
|
|
|
+ * provides a generally accessible repository for the MACs
|
|
|
|
|
+ * which can be written by board level code and read by the
|
|
|
|
|
+ * driver.
|
|
|
|
|
+ *
|
|
|
|
|
+ * The implementation also allows user level programs to
|
|
|
|
|
+ * access the MAC information in /proc/net/maclist. This is
|
|
|
|
|
+ * useful as it allows user space code to use the MAC if it
|
|
|
|
|
+ * is not used by a built-in driver.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Copyright (C) 2005 John Bowler
|
|
|
|
|
+ * Author: John Bowler <jbowler@acm.org>
|
|
|
|
|
+ * Maintainers: http://www.nslu2-linux.org/
|
|
|
|
|
+ *
|
|
|
|
|
+ * 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.
|
|
|
|
|
+ *
|
|
|
|
|
+ * External interfaces:
|
|
|
|
|
+ * Interfaces to linux kernel (and modules)
|
|
|
|
|
+ * maclist_add: add a single MAC
|
|
|
|
|
+ * maclist_count: total number of MACs stored
|
|
|
|
|
+ * maclist_read: read a MAC 0..(maclist_count-1)
|
|
|
|
|
+ */
|
|
|
|
|
+#include <linux/module.h>
|
|
|
|
|
+#include <linux/moduleparam.h>
|
|
|
|
|
+#include <linux/etherdevice.h>
|
|
|
|
|
+#include <linux/proc_fs.h>
|
|
|
|
|
+#include <linux/errno.h>
|
|
|
|
|
+
|
|
|
|
|
+#include <net/maclist.h>
|
|
|
|
|
+
|
|
|
|
|
+#define MACLIST_NAME "maclist"
|
|
|
|
|
+
|
|
|
|
|
+MODULE_AUTHOR("John Bowler <jbowler@acm.org>");
|
|
|
|
|
+MODULE_DESCRIPTION("MAC list repository");
|
|
|
|
|
+MODULE_LICENSE("GPL");
|
|
|
|
|
+
|
|
|
|
|
+typedef struct maclist_entry {
|
|
|
|
|
+ struct maclist_entry *next; /* Linked list, first first */
|
|
|
|
|
+ u8 id[6]; /* 6 byte Ethernet MAC */
|
|
|
|
|
+} maclist_entry_t;
|
|
|
|
|
+
|
|
|
|
|
+/* Access to this list is possible at any time - entries in
|
|
|
|
|
+ * the list are never destroyed. Modification of the list is
|
|
|
|
|
+ * safe only from the init code (i.e. modification must be
|
|
|
|
|
+ * single threaded), but read from an interrupt at the same
|
|
|
|
|
+ * time is possible and safe.
|
|
|
|
|
+ */
|
|
|
|
|
+static maclist_entry_t *maclist_list = 0;
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * External interfaces.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Add a single entry, returns 0 on success else an error
|
|
|
|
|
+ * code. Must be single threaded.
|
|
|
|
|
+ */
|
|
|
|
|
+int maclist_add(const u8 new_id[6]) {
|
|
|
|
|
+ maclist_entry_t *new_entry, **tail;
|
|
|
|
|
+
|
|
|
|
|
+ if (new_id == 0 || !is_valid_ether_addr(new_id)) {
|
|
|
|
|
+ printk(KERN_ERR MACLIST_NAME ": invalid ethernet address\n");
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
+ }
|
|
|
|
|
+ new_entry = kmalloc(sizeof *new_entry, GFP_KERNEL);
|
|
|
|
|
+ if (new_entry == 0)
|
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
+ new_entry->next = 0;
|
|
|
|
|
+ memcpy(new_entry->id, new_id, sizeof new_entry->id);
|
|
|
|
|
+
|
|
|
|
|
+ tail = &maclist_list;
|
|
|
|
|
+ while (*tail != 0)
|
|
|
|
|
+ tail = &(*tail)->next;
|
|
|
|
|
+ *tail = new_entry;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+EXPORT_SYMBOL(maclist_add);
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Return the current entry count (valid in any context).
|
|
|
|
|
+ */
|
|
|
|
|
+int maclist_count(void) {
|
|
|
|
|
+ maclist_entry_t *tail = maclist_list;
|
|
|
|
|
+ int count = 0;
|
|
|
|
|
+
|
|
|
|
|
+ while (tail != 0) {
|
|
|
|
|
+ tail = tail->next;
|
|
|
|
|
+ ++count;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return count;
|
|
|
|
|
+}
|
|
|
|
|
+EXPORT_SYMBOL(maclist_count);
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Return the ID from the n'th entry (valid in any context),
|
|
|
|
|
+ * returns 0 on success, -EINVAL if 'n' is out of range.
|
|
|
|
|
+ */
|
|
|
|
|
+int maclist_read(u8 (*id)[6], int n) {
|
|
|
|
|
+ maclist_entry_t *entry = maclist_list;
|
|
|
|
|
+
|
|
|
|
|
+ while (n > 0 && entry != 0) {
|
|
|
|
|
+ --n;
|
|
|
|
|
+ entry = entry->next;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (n == 0 && entry != 0) {
|
|
|
|
|
+ memcpy(id, entry->id, sizeof *id);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ printk(KERN_ERR MACLIST_NAME ": id does not exist\n");
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
+}
|
|
|
|
|
+EXPORT_SYMBOL(maclist_read);
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Parameter parsing. The option string is a list of MAC
|
|
|
|
|
+ * addresses, comma separated. (The parsing really should
|
|
|
|
|
+ * be somewhere central...)
|
|
|
|
|
+ */
|
|
|
|
|
+static int __init maclist_setup(char *param) {
|
|
|
|
|
+ int bytes = 0, seen_a_digit = 0;
|
|
|
|
|
+ u8 id[6];
|
|
|
|
|
+
|
|
|
|
|
+ memset(id, 0, sizeof id);
|
|
|
|
|
+
|
|
|
|
|
+ if (param) do {
|
|
|
|
|
+ int digit = -1;
|
|
|
|
|
+ switch (*param) {
|
|
|
|
|
+ case '0': digit = 0; break;
|
|
|
|
|
+ case '1': digit = 1; break;
|
|
|
|
|
+ case '2': digit = 2; break;
|
|
|
|
|
+ case '3': digit = 3; break;
|
|
|
|
|
+ case '4': digit = 4; break;
|
|
|
|
|
+ case '5': digit = 5; break;
|
|
|
|
|
+ case '6': digit = 6; break;
|
|
|
|
|
+ case '7': digit = 7; break;
|
|
|
|
|
+ case '8': digit = 8; break;
|
|
|
|
|
+ case '9': digit = 9; break;
|
|
|
|
|
+ case 'a': case 'A': digit = 10; break;
|
|
|
|
|
+ case 'b': case 'B': digit = 11; break;
|
|
|
|
|
+ case 'c': case 'C': digit = 12; break;
|
|
|
|
|
+ case 'd': case 'D': digit = 13; break;
|
|
|
|
|
+ case 'e': case 'E': digit = 14; break;
|
|
|
|
|
+ case 'f': case 'F': digit = 15; break;
|
|
|
|
|
+ case ':':
|
|
|
|
|
+ if (seen_a_digit)
|
|
|
|
|
+ bytes = (bytes+1) & ~1;
|
|
|
|
|
+ else
|
|
|
|
|
+ bytes += 2; /* i.e. ff::ff is ff:00:ff */
|
|
|
|
|
+ seen_a_digit = 0;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 0:
|
|
|
|
|
+ if (bytes == 0) /* nothing new seen so far */
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ /*fall through*/
|
|
|
|
|
+ case ',': case ';':
|
|
|
|
|
+ if (bytes > 0)
|
|
|
|
|
+ bytes = 12; /* i.e. all trailing bytes 0 */
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ printk(KERN_ERR MACLIST_NAME ": invalid character <%c[%d]>\n",
|
|
|
|
|
+ *param, *param);
|
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (digit >= 0) {
|
|
|
|
|
+ id[bytes>>1] = (id[bytes>>1] << 4) + digit; break;
|
|
|
|
|
+ ++bytes;
|
|
|
|
|
+ seen_a_digit = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (bytes >= 12) {
|
|
|
|
|
+ int rc = maclist_add(id);
|
|
|
|
|
+ if (rc)
|
|
|
|
|
+ return rc;
|
|
|
|
|
+ bytes = 0;
|
|
|
|
|
+ seen_a_digit = 0;
|
|
|
|
|
+ memset(id, 0, sizeof id);
|
|
|
|
|
+ if (*param == 0)
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ ++param;
|
|
|
|
|
+ } while (1);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * procfs support, if compiled in.
|
|
|
|
|
+ */
|
|
|
|
|
+#ifdef CONFIG_PROC_FS
|
|
|
|
|
+/*
|
|
|
|
|
+ * Character device read
|
|
|
|
|
+ */
|
|
|
|
|
+static int maclist_getchar(off_t n) {
|
|
|
|
|
+ static char xdigit[16] = "0123456789abcdef";
|
|
|
|
|
+ maclist_entry_t *head = maclist_list;
|
|
|
|
|
+ int b;
|
|
|
|
|
+
|
|
|
|
|
+ do {
|
|
|
|
|
+ if (head == 0)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ if (n < 18)
|
|
|
|
|
+ break;
|
|
|
|
|
+ head = head->next;
|
|
|
|
|
+ n -= 18;
|
|
|
|
|
+ } while (1);
|
|
|
|
|
+
|
|
|
|
|
+ if (n == 17)
|
|
|
|
|
+ return '\n';
|
|
|
|
|
+
|
|
|
|
|
+ b = n/3;
|
|
|
|
|
+ switch (n - b*3) {
|
|
|
|
|
+ case 0: return xdigit[head->id[b] >> 4];
|
|
|
|
|
+ case 1: return xdigit[head->id[b] & 0xf];
|
|
|
|
|
+ default: return ':';
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * The extensively undocumented proc_read_t callback is implemented here.
|
|
|
|
|
+ * Go look in fs/proc/generic.c:
|
|
|
|
|
+ *
|
|
|
|
|
+ * Prototype:
|
|
|
|
|
+ * int f(char *buffer, char **start, off_t offset,
|
|
|
|
|
+ * int count, int *peof, void *dat)
|
|
|
|
|
+ *
|
|
|
|
|
+ * Assume that the buffer is "count" bytes in size.
|
|
|
|
|
+ *
|
|
|
|
|
+ * 2) Set *start = an address within the buffer.
|
|
|
|
|
+ * Put the data of the requested offset at *start.
|
|
|
|
|
+ * Return the number of bytes of data placed there.
|
|
|
|
|
+ * If this number is greater than zero and you
|
|
|
|
|
+ * didn't signal eof and the reader is prepared to
|
|
|
|
|
+ * take more data you will be called again with the
|
|
|
|
|
+ * requested offset advanced by the number of bytes
|
|
|
|
|
+ * absorbed.
|
|
|
|
|
+ */
|
|
|
|
|
+static int maclist_proc_read(char *buffer, char **start, off_t offset,
|
|
|
|
|
+ int count, int *peof, void *dat) {
|
|
|
|
|
+ int total;
|
|
|
|
|
+
|
|
|
|
|
+ *start = buffer;
|
|
|
|
|
+ total = 0;
|
|
|
|
|
+
|
|
|
|
|
+ while (total < count) {
|
|
|
|
|
+ int ch = maclist_getchar(offset++);
|
|
|
|
|
+ if (ch == -1) {
|
|
|
|
|
+ *peof = 1;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ *buffer++ = ch;
|
|
|
|
|
+ ++total;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return total;
|
|
|
|
|
+}
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * Finally, the init/exit functions.
|
|
|
|
|
+ */
|
|
|
|
|
+static void __exit maclist_exit(void)
|
|
|
|
|
+{
|
|
|
|
|
+ maclist_entry_t *list;
|
|
|
|
|
+
|
|
|
|
|
+ remove_proc_entry(MACLIST_NAME, proc_net);
|
|
|
|
|
+
|
|
|
|
|
+ list = maclist_list;
|
|
|
|
|
+ maclist_list = 0;
|
|
|
|
|
+
|
|
|
|
|
+ while (list != 0) {
|
|
|
|
|
+ maclist_entry_t *head = list;
|
|
|
|
|
+ list = head->next;
|
|
|
|
|
+ kfree(head);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#ifdef MODULE
|
|
|
|
|
+static char ids[256];
|
|
|
|
|
+module_param_string(ids, ids, sizeof ids, 0);
|
|
|
|
|
+MODULE_PARM_DESC(ids, "comma separated list of MAC ids\n");
|
|
|
|
|
+#else
|
|
|
|
|
+__setup("maclist_ids=", maclist_setup);
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+static int __init maclist_init(void)
|
|
|
|
|
+{
|
|
|
|
|
+# ifdef MODULE
|
|
|
|
|
+ if (ids[0])
|
|
|
|
|
+ maclist_setup(ids);
|
|
|
|
|
+# endif
|
|
|
|
|
+
|
|
|
|
|
+ /* Ignore failure, the module will still work. */
|
|
|
|
|
+ (void)create_proc_read_entry(MACLIST_NAME, S_IRUGO, proc_net, maclist_proc_read, NULL);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+module_init(maclist_init);
|
|
|
|
|
+module_exit(maclist_exit);
|
|
|
|
|
--- linux-2.6.15/drivers/net/Makefile 1970-01-01 00:00:00.000000000 +0000
|
|
|
|
|
+++ linux-2.6.15/drivers/net/Makefile 1970-01-01 00:00:00.000000000 +0000
|
|
|
|
|
@@ -70,6 +70,7 @@ obj-$(CONFIG_RIONET) += rionet.o
|
|
|
|
|
# end link order section
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
+obj-$(CONFIG_MACLIST) += maclist.o
|
|
|
|
|
obj-$(CONFIG_MII) += mii.o
|
|
|
|
|
obj-$(CONFIG_PHYLIB) += phy/
|
|
|
|
|
|
|
|
|
|
--- linux-2.6.15/drivers/net/Kconfig 1970-01-01 00:00:00.000000000 +0000
|
|
|
|
|
+++ linux-2.6.15/drivers/net/Kconfig 1970-01-01 00:00:00.000000000 +0000
|
|
|
|
|
@@ -166,6 +166,21 @@ config NET_ETHERNET
|
|
|
|
|
kernel: saying N will just cause the configurator to skip all
|
|
|
|
|
the questions about Ethernet network cards. If unsure, say N.
|
|
|
|
|
|
|
|
|
|
+config MACLIST
|
|
|
|
|
+ tristate "Ethernet MAC repository"
|
|
|
|
|
+ depends on NET_ETHERNET
|
|
|
|
|
+ help
|
|
|
|
|
+ Some ethernet controllers have no built-in way of obtaining an
|
|
|
|
|
+ appropriate Ethernet MAC address. Such controllers have to be
|
|
|
|
|
+ initialised in a board-specific way, depending on how the allocated
|
|
|
|
|
+ MAC is stored. The MAC repository provides a set of APIs and a
|
|
|
|
|
+ proc entry (/proc/net/maclist) to store MAC values from the board
|
|
|
|
|
+ so that such drivers can obtain a MAC address without board-specific
|
|
|
|
|
+ code. You do not need to enable this device - it will be selected
|
|
|
|
|
+ automatically by any device which requires it. It is only useful
|
|
|
|
|
+ to enable it manually when building a device driver independently
|
|
|
|
|
+ of the kernel build.
|
|
|
|
|
+
|
|
|
|
|
config MII
|
|
|
|
|
tristate "Generic Media Independent Interface device support"
|
|
|
|
|
depends on NET_ETHERNET
|