240 lines
6.1 KiB
C
240 lines
6.1 KiB
C
/*
|
|
* Copyright 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
|
|
*
|
|
* 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.
|
|
*
|
|
* Compatibility file for Linux wireless for kernels 2.6.23.
|
|
*/
|
|
|
|
#include <net/compat.h>
|
|
|
|
/* On net/core/dev.c as of 2.6.24 */
|
|
int __dev_addr_delete(struct dev_addr_list **list, int *count,
|
|
void *addr, int alen, int glbl)
|
|
{
|
|
struct dev_addr_list *da;
|
|
|
|
for (; (da = *list) != NULL; list = &da->next) {
|
|
if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
|
|
alen == da->da_addrlen) {
|
|
if (glbl) {
|
|
int old_glbl = da->da_gusers;
|
|
da->da_gusers = 0;
|
|
if (old_glbl == 0)
|
|
break;
|
|
}
|
|
if (--da->da_users)
|
|
return 0;
|
|
|
|
*list = da->next;
|
|
kfree(da);
|
|
(*count)--;
|
|
return 0;
|
|
}
|
|
}
|
|
return -ENOENT;
|
|
}
|
|
EXPORT_SYMBOL(__dev_addr_delete);
|
|
|
|
/* On net/core/dev.c as of 2.6.24. This is not yet used by mac80211 but
|
|
* might as well add it */
|
|
int __dev_addr_add(struct dev_addr_list **list, int *count,
|
|
void *addr, int alen, int glbl)
|
|
{
|
|
struct dev_addr_list *da;
|
|
|
|
for (da = *list; da != NULL; da = da->next) {
|
|
if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
|
|
da->da_addrlen == alen) {
|
|
if (glbl) {
|
|
int old_glbl = da->da_gusers;
|
|
da->da_gusers = 1;
|
|
if (old_glbl)
|
|
return 0;
|
|
}
|
|
da->da_users++;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
da = kmalloc(sizeof(*da), GFP_ATOMIC);
|
|
if (da == NULL)
|
|
return -ENOMEM;
|
|
memcpy(da->da_addr, addr, alen);
|
|
da->da_addrlen = alen;
|
|
da->da_users = 1;
|
|
da->da_gusers = glbl ? 1 : 0;
|
|
da->next = *list;
|
|
*list = da;
|
|
(*count)++;
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(__dev_addr_add);
|
|
|
|
|
|
/* Part of net/core/dev_mcast.c as of 2.6.23. This is a slightly different version.
|
|
* Since da->da_synced is not part of 2.6.22 we need to take longer route when
|
|
* syncing */
|
|
|
|
/**
|
|
* dev_mc_sync - Synchronize device's multicast list to another device
|
|
* @to: destination device
|
|
* @from: source device
|
|
*
|
|
* Add newly added addresses to the destination device and release
|
|
* addresses that have no users left. The source device must be
|
|
* locked by netif_tx_lock_bh.
|
|
*
|
|
* This function is intended to be called from the dev->set_multicast_list
|
|
* function of layered software devices.
|
|
*/
|
|
int dev_mc_sync(struct net_device *to, struct net_device *from)
|
|
{
|
|
struct dev_addr_list *da, *next, *da_to;
|
|
int err = 0;
|
|
|
|
netif_tx_lock_bh(to);
|
|
da = from->mc_list;
|
|
while (da != NULL) {
|
|
int synced = 0;
|
|
next = da->next;
|
|
da_to = to->mc_list;
|
|
/* 2.6.22 does not have da->da_synced so lets take the long route */
|
|
while (da_to != NULL) {
|
|
if (memcmp(da_to->da_addr, da->da_addr, da_to->da_addrlen) == 0 &&
|
|
da->da_addrlen == da_to->da_addrlen)
|
|
synced = 1;
|
|
break;
|
|
}
|
|
if (!synced) {
|
|
err = __dev_addr_add(&to->mc_list, &to->mc_count,
|
|
da->da_addr, da->da_addrlen, 0);
|
|
if (err < 0)
|
|
break;
|
|
da->da_users++;
|
|
} else if (da->da_users == 1) {
|
|
__dev_addr_delete(&to->mc_list, &to->mc_count,
|
|
da->da_addr, da->da_addrlen, 0);
|
|
__dev_addr_delete(&from->mc_list, &from->mc_count,
|
|
da->da_addr, da->da_addrlen, 0);
|
|
}
|
|
da = next;
|
|
}
|
|
if (!err)
|
|
__dev_set_rx_mode(to);
|
|
netif_tx_unlock_bh(to);
|
|
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL(dev_mc_sync);
|
|
|
|
|
|
/* Part of net/core/dev_mcast.c as of 2.6.23. This is a slighty different version.
|
|
* Since da->da_synced is not part of 2.6.22 we need to take longer route when
|
|
* unsyncing */
|
|
|
|
/**
|
|
* dev_mc_unsync - Remove synchronized addresses from the destination
|
|
* device
|
|
* @to: destination device
|
|
* @from: source device
|
|
*
|
|
* Remove all addresses that were added to the destination device by
|
|
* dev_mc_sync(). This function is intended to be called from the
|
|
* dev->stop function of layered software devices.
|
|
*/
|
|
void dev_mc_unsync(struct net_device *to, struct net_device *from)
|
|
{
|
|
struct dev_addr_list *da, *next, *da_to;
|
|
|
|
netif_tx_lock_bh(from);
|
|
netif_tx_lock_bh(to);
|
|
|
|
da = from->mc_list;
|
|
while (da != NULL) {
|
|
bool synced = false;
|
|
next = da->next;
|
|
da_to = to->mc_list;
|
|
/* 2.6.22 does not have da->da_synced so lets take the long route */
|
|
while (da_to != NULL) {
|
|
if (memcmp(da_to->da_addr, da->da_addr, da_to->da_addrlen) == 0 &&
|
|
da->da_addrlen == da_to->da_addrlen)
|
|
synced = true;
|
|
break;
|
|
}
|
|
if (!synced) {
|
|
da = next;
|
|
continue;
|
|
}
|
|
__dev_addr_delete(&to->mc_list, &to->mc_count,
|
|
da->da_addr, da->da_addrlen, 0);
|
|
__dev_addr_delete(&from->mc_list, &from->mc_count,
|
|
da->da_addr, da->da_addrlen, 0);
|
|
da = next;
|
|
}
|
|
__dev_set_rx_mode(to);
|
|
|
|
netif_tx_unlock_bh(to);
|
|
netif_tx_unlock_bh(from);
|
|
}
|
|
EXPORT_SYMBOL(dev_mc_unsync);
|
|
|
|
/* Added as of 2.6.23 on net/core/dev.c. Slightly modifed, no dev->set_rx_mode on
|
|
* 2.6.22 so ignore that. */
|
|
|
|
/*
|
|
* Upload unicast and multicast address lists to device and
|
|
* configure RX filtering. When the device doesn't support unicast
|
|
* filtering it is put in promiscous mode while unicast addresses
|
|
* are present.
|
|
*/
|
|
void __dev_set_rx_mode(struct net_device *dev)
|
|
{
|
|
/* dev_open will call this function so the list will stay sane. */
|
|
if (!(dev->flags&IFF_UP))
|
|
return;
|
|
|
|
if (!netif_device_present(dev))
|
|
return;
|
|
|
|
/* This needs to be ported to 2.6.22 framework */
|
|
#if 0
|
|
/* Unicast addresses changes may only happen under the rtnl,
|
|
* therefore calling __dev_set_promiscuity here is safe.
|
|
*/
|
|
if (dev->uc_count > 0 && !dev->uc_promisc) {
|
|
__dev_set_promiscuity(dev, 1);
|
|
dev->uc_promisc = 1;
|
|
} else if (dev->uc_count == 0 && dev->uc_promisc) {
|
|
__dev_set_promiscuity(dev, -1);
|
|
dev->uc_promisc = 0;
|
|
}
|
|
#endif
|
|
|
|
if (dev->set_multicast_list)
|
|
dev->set_multicast_list(dev);
|
|
}
|
|
|
|
/**
|
|
* pci_try_set_mwi - enables memory-write-invalidate PCI transaction
|
|
* @dev: the PCI device for which MWI is enabled
|
|
*
|
|
* Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND.
|
|
* Callers are not required to check the return value.
|
|
*
|
|
* RETURNS: An appropriate -ERRNO error value on error, or zero for success.
|
|
*/
|
|
int pci_try_set_mwi(struct pci_dev *dev)
|
|
{
|
|
int rc = 0;
|
|
#ifdef HAVE_PCI_SET_MWI
|
|
rc = pci_set_mwi(dev);
|
|
#endif
|
|
return rc;
|
|
}
|
|
EXPORT_SYMBOL(pci_try_set_mwi);
|
|
#endif
|
|
|