Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Mar 2001 12:27:28 -0800 (PST)
From:      wpaul@FreeBSD.ORG (Bill Paul)
To:        jj.walker@auckland.ac.nz (Jamie Walker)
Cc:        ajh3@chmod.ath.cx, edward_gess@hotmail.com, freebsd-questions@FreeBSD.ORG
Subject:   Re: MAC
Message-ID:  <20010328202728.EF06837B719@hub.freebsd.org>
In-Reply-To: <20010329074036.C16495@auckland.ac.nz> from Jamie Walker at "Mar 29, 2001 07:40:36 am"

next in thread | previous in thread | raw e-mail | index | archive | help
> On Wed, Mar 28, 2001 at 09:35:19AM -0600, Andrew Hesford wrote:
> 
> > The MAC address of a network card is hard-wired. Occassionally, the card
> > manufacturer will let you change a few digits, but this is dangerous and
> > can lead to network problems.
> > 
> > I'm not sure who grants blocks of MAC addresses to card manufacturers,
> > it might be the FCC, or it might be ICANN.
> > 
> > The idea behind a MAC address is to give a unique identifier to the
> > card, so protocols like TCP can figure out where to send packets.
> 
> from the man pages - ifconfig(8)
> 
>      lladdr addr
>              Set the link-level address on an interface. This can be used to
>              e.g. set a new MAC address on an ethernet interface, though the
>              mechanism used is not ethernet-specific. The address addr is
>              specified as a series of colon-separated hex digits.  If the in-
>              terface is already up when this option is used, it will be
>              briefly brought down and then brought back up again in order to
>              insure that the receive filter in the underlying ethernet hard-
>              ware is properly reprogrammed.
> 
> This usually means the card must be placed in promiscuous mode.

No, I'm sorry, you're both wrong. With all currently available ethernet
cards, the station address is stored in an EEPROM chip which is separate
from the actual ethernet controller chip. The ethernet controller itself
has a receive filter which can be programmed to accept or discard frames
in a couple of different ways. The exact types of filter capabilities and
programming method varies a bit from one chip design to another, but the
basics are usually the same:

- You can program the filter to accept all frames with a specific
  unicast distination address. This is usually the station address
  stored in the EEPROM. The station address is programmed into the
  filter by the driver when the interface is initialized.
- You can program the filter to accept frames sent to a multicast
  group. The usual method is to use a hash table that is 64, 128, 256
  or 512 bits wide. (Cheaper cards usually only use 64 bits.) The driver
  checks the list of multicast groups that it needs to listen to, runs
  the multicast address through a hash routine which generates a number
  between 0 and 63, then it sets the corresponding bit in the chip's
  hash table. When the chip receives a frame sent to a multicast group,
  it runs the same hash routine on it, computes the same bit index, then
  checks to see if the driver set the bit for that index in the hash table.
  If the bit is set, the chip hands the frame to the host, otherwise it
  discards it. This is not perfect filtering: sometimes unwanted frames
  will get through, but the OS is required to perform additional filtering
  on multicast packets according to the RFCs.
- You can program the chip to receive *all* frames regardless of the
  destination address. This is called promiscuous mode.

More complex (and expensive) chips offer other features, such as filtering
all broadcast packets, ARP packets, or packets with VLAN tags. Some of them
also let you do perfect multicast filtering rather than the hash table
method (i.e. you can specify exactly the groups you want to listen for,
although there's a limit to how many you can listen for at once, usually
16 or so). The DEC/Intel 21143 actually supports several different
driver-selectable filtering methods, which allows the programmer to
tailor its behavior depending on application needs.

It is the driver's responsibility to read the station address from the
EEPROM. In FreeBSD, this happens during in a driver's 'attach' routine,
which is called when the driver loads. The address is saved in two places
inside the kernel. Later, when the interface is brought up, the driver's
'init' routine will load this address into the chip's receive filter and
start the interface running. All you have to do to make the NIC use a
different station address is to change what's stored in the kernel, then
call the 'init' routine again to reprogram the filter. You do *not*
need to put the interface in promiscuous mode, nor do you have to change
the contents of the EEPROM. This is not a new idea: anybody who's run
SunOS on a SPARC can tell you that you can override the station address
on an ethernet interface using 'ifconfig le0 ether <blah>' even as far
back as SunOS 4.1.x.

That said, there are some *very* old ethernet cards which do not provide
a mechanism for programming the unicast/station address filter. These
cards load the station address from the EEPROM themselves, and their
design simply doesn't offer a way to change it once loaded since the
designers didn't deem it necessary. With cards like this, you are forced
to use promiscuous mode and software filtering in order to receive
packets not meant for your station address. There aren't any cards like
this in production today, however: while some chips are able to autoload
the station address from the EEPROM (the VIA Rhine is one), the driver
can change it later simply by loading a new address into the filter
registers.

Now, with FreeBSD 4.2 and later, you can do this:

# ifconfig foo0 ether 00:00:e8:01:02:03
or
# ifconfig foo0 lladdr 00:00:e8:01:02:03

To change the station address on any interface that supports it (which
is most of them). For older versions of FreeBSD, you can download:

http://www.freebsd.org/~wpaul/mac.tar.gz

This is a kernel module and command line utility that lets you do the
same thing that ifconfig does now. The module can be built for FreeBSD
2.2.x, FreeBSD 3.0, and FreeBSD 3.2 and up. To use it, do the following:

- Unpack the tarball.
- For FreeBSD 2.2.x:
	# cd setmac/module
	# make; make load
- For FreeBSD 3.0:
	# cd setmac/module_3.0
	# make; make load
- For FreeBSD 3.2 and later:
	# cd setmac/module_3.2
	# make; make load
- Build the setmac utility:
	# cd setmac/setmac
	# make
- Set the station address:
	# ./setmac foo0 00:00:e8:01:02:03

This module was originally written for a friend who needed to implement
failover support for a custom server application: one machine needed to
assume the identity of another machine which had crashed or become
unavailable.

-Bill

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010328202728.EF06837B719>