--- a/driver/nvram_stub.c +++ b/driver/nvram_stub.c @@ -5,6 +5,7 @@ #include #include #include +#include #ifdef BCMDBG_ERR #define NVR_MSG(x) printf x @@ -24,6 +25,7 @@ typedef struct _vars { static vars_t *vars = NULL; static int nvram_init_done = 0; extern char *nvram_buf[]; +static void fixup_mac_addr(vars_t *new); int BCMATTACHFN(nvram_init)(void *si) @@ -55,6 +57,7 @@ BCMATTACHFN(nvram_init)(void *si) vars = new; bcopy((char *)(&nvh[1]), new->vars, nvs); + fixup_mac_addr(new); return 0; } @@ -164,3 +167,65 @@ nvram_getall(char *buf, int count) *buf = '\0'; return 0; } + +static bool nvram_is_valid_mac(struct ether_addr *mac) +{ + return mac && !(mac->octet[0] == 0x00 && mac->octet[1] == 0x90 && mac->octet[2] == 0x4c); +} + +static int nvram_increase_mac_addr(struct ether_addr *mac, u8 num) +{ + u8 *oui = mac->octet + ETHER_ADDR_LEN/2 - 1; + u8 *p = mac->octet + ETHER_ADDR_LEN - 1; + + do { + (*p) += num; + if (*p > num) + break; + p--; + num = 1; + } while (p != oui); + + if (p == oui) { + pr_err("unable to fetch mac address\n"); + return -ENOENT; + } + return 0; +} + +static void nvram_change_mac_addr(vars_t *new, struct ether_addr *valid, const char *name) +{ + char *macaddr_c; + struct ether_addr macaddr; + + macaddr_c = findvar(new->vars, new->vars + new->size, name); + if (!macaddr_c) + return; + + bcm_ether_atoe(macaddr_c, &macaddr); + if (nvram_is_valid_mac(&macaddr)) + return; + nvram_increase_mac_addr(valid, 1); + bcm_ether_ntoa(valid, macaddr_c); +} + +static void fixup_mac_addr(vars_t *new) +{ + char *macaddr_base_c; + struct ether_addr macaddr_base; + + macaddr_base_c = findvar(new->vars, new->vars + new->size, "et0macaddr"); + if (!macaddr_base_c) + return; + + bcm_ether_atoe(macaddr_base_c, &macaddr_base); + if (!nvram_is_valid_mac(&macaddr_base)) + return; + + /* jump over the first free address so it can be used for wan */ + nvram_increase_mac_addr(&macaddr_base, 1); + nvram_change_mac_addr(new, &macaddr_base, "sb/1/macaddr"); + nvram_change_mac_addr(new, &macaddr_base, "pci/1/1/macaddr"); + nvram_change_mac_addr(new, &macaddr_base, "pci/1/2/macaddr"); + nvram_change_mac_addr(new, &macaddr_base, "pci/2/1/macaddr"); +}