Privacy, please!
• Our ‘xmit1000.c’ driver transmits all of its
packets to every node on our LAN, and
our ‘recv1000.c’ driver receives all of the
packets transmitted by any of the nodes!
• Is this what we really want to happen?
Receive address filtering
• Nowadays any network interface controller
has a “filtering” capability which allows any
packet NOT to be received by nodes that
the packet’s sender didn’t intend it to go to
15 trang |
Chia sẻ: candy98 | Lượt xem: 941 | Lượt tải: 0
Bạn đang xem nội dung tài liệu Advanced Systems Programming - Lesson 26: Hardware-address filtering, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
Hardware-address filtering
How can we send packets to just
one node on our ‘anchor’ cluster?
Privacy, please!
• Our ‘xmit1000.c’ driver transmits all of its
packets to every node on our LAN, and
our ‘recv1000.c’ driver receives all of the
packets transmitted by any of the nodes!
• Is this what we really want to happen?
anchor01
anchor02
anchor03
anchor04
anchor05
anchor06
anchor07
anchor00
Receive address filtering
• Nowadays any network interface controller
has a “filtering” capability which allows any
packet NOT to be received by nodes that
the packet’s sender didn’t intend it to go to
Receive
buffer
Host memory
Transmit
FIFO
Receive
FIFO
Network Interface Controller
to/from
LANfiltering
engine
Our new ‘nic.c’ module
• This device-driver combines the ‘write()’
and ‘read()’ methods from our ‘xmit1000.c’
and ‘recv1000.c’ modules, but it adds an
‘ioctl()’ method that lets applications setup
any ethernet-packet’s destination-address,
as is illustrated in our companion program
(named ‘sendto.cpp’) which finds a node’s
hardware-address in our ‘ethers’ database
The ‘sendto’ algorithm
• Here are the steps which our ‘sendto.cpp’
demo-program performs:
Find the destination’s node-name on the command-line
Search our ‘ethers’ file for a line with that node’s name
Convert that node’s MAC-address from ascii to numeric
Open the ‘/dev/nic’ device-file
Call our driver’s ‘ioctl()’ method to setup packets’ destination
Write our application’s test-message to the ‘dev/nic’ device-file
Print a message confirming the destination and bytes written
Notes on library functions
• Use ‘fopen()’ to open the ‘ethers’ textfile,
so you can use the ‘fgets()’ function to
read in its contents one-line-at-a-time:
#include // for fopen(), fgets(), puts()
#include // for strstr()
int main( int argc, char *argv[ ] )
{
if ( argc == 1 ) exit(1); // missing command-line argument
FILE *fd = fopen( “ethers”, “ro” );
if ( fd == NULL ) exit(1); // file not found in current directory
char line[ 80 ];
while ( fgets( line, 80, fd ) ) if ( strstr( line, argv[1] ) puts( line );
/* additional processing goes here */
}
‘ascii-to-numeric’
• Use ‘strstr( string, substring )’ to find line
in ‘ethers’ file with name of specified node
• Use ‘strtol( string, NULL, 16 )’ to convert a
hexadecimal digit-string to a numeric value
unsigned char dstn[ 6 ]; // storage for 6-byte MAC-address
// loop converts colon-formatted hex-string to array of numbers
for (int i = 0; i < 6; i++) dstn[ i ] = strtol( line+3*i, NULL, 16 );
Our ‘ioctl()’ function
• Our ‘nic.c’ driver implements an ‘ioctl()’
service allowing a user-program to setup
the network hardware-address that will be
used in the destination-field of any packet
that the driver’s ‘write()’ function transmits
// open the network interface controller’s device-file
int fp = open( “/dev/nic”, O_RDWR );
if ( fp < 0 ) { perror( “/dev/nic” ); exit(1); }
// setup packet-destination to be used when transmittting
if ( ioctl( fp, 0, dstn ) < 0 ) { perror( “ioctl” ); exit(1); }
Driver’s ‘ioctl()’ function
char mac[ 6 ]; // packet source-address gets filled in by ‘module_init()’
char dstn[ 6 ]; // packet destination-address gets filled in by our ‘ioctl()’
int my_ioctl( struct inode *, struct file*, unsigned int cmd, unsigned long address )
{
unsigned char *from = (unsigned char *)address;
switch ( cmd )
{
case 0: // set the driver’s ethernet-packet destination-address
if ( copy_from_user( dstn, from, 6 ) ) return –EFAULT;
return 0; //SUCCESS
default: break;
}
return –EINVAL; // requested command not implemented
}
Change in ‘write()’
• Our device-driver’s ‘write()’ method needs
only a tiny change in order to make use of
the user-supplied destination-address:
ssize_t my_write( struct file *file, char *buf, size_t len, loff_t *pos )
{
int tail = ioread32( io + E1000_TDT ); // next tx-ring index
char *packet = phys_to_virt( txdesc[ tail ].base_addr );
// memset( packet+0, 0xFF, 6 ); // broadcast-address (NO!)
memcpy( packet+0, dstn, 6 ); // user-supplied MAC-address
memcpy( packet+6, mac, 6 ); // source MAC-address (ours!)
/* other processing same as before */
}
Change in ‘init()’
• To prevent reception of ethernet packets
whose destination-address doesn’t match
our device’s address, we need to alter the
way we program our nic’s RCTL register:
0000 0100 0000 0000 1000 0000 0000 0110RCTL
(0x0100)
31 26 15 4 3 2 1 0
SECRC (Strip Ethernet CRC) BAM (Broadcast Accept Mode)
MPE (Multicast Promiscuous Enable)
UPE (Unicast Promiscuous Enable)
SBP (Store Bad Packets)
EN (Enable receive engine)
A change in memory-usage
RxBuf
0
RxBuf
1
RxBuf
2
RxBuf
3
RxBuf
4
RxBuf
5
RxBuf
6
RxBuf
7
TxBuf
R
X
D
E
S
C
T
X
D
E
S
C
4 pages of kernel memory
physaddr descaddr
Eight receive-buffers (0x600 bytes each)
One ‘shared’ transmit-buffer (0x600 bytes)
Eight receive-descriptors (0x80 bytes)
Eight transmit-descriptors (0x80 bytes)
When we “merged” the code from our two previous device-drivers,
we needed to make sure that receive-buffers and transmit-buffers
do not overlap, and likewise that the Rx and Tx descriptor-queues
occupy distinct regions within the allocated kernel-memory region
Is 00:00:00:00:00:00 legal?
• If you comment out all the lines of code in
our ‘sendto.cpp’ application that precede
the ‘open()’ statement, then our driver’s
‘dstn[ 6 ]’ array will remain all zeros, and
hence packets will be sent with a ‘zero’
destinatin-address (normally not legal)
• EXERCISE: Try this out and see if your
test-message gets received any node
Receive-filter Array
Filter-address 0
Filter-address 1
Filter-address 2
Filter-address 3
Filter-address 4
Filter-address 5
Filter-address 6
Filter-address 7
0x5400
0x5408
0x5410
0x5418
0x5420
0x5428
0x5430
0x5438
quadword (64-bits)
1
0
0
0
0
0
0
0
‘valid’-bit (1=yes, 0=no)
The NIC’s own unique
hardware-address
gets programmed into
this initial array-entry
during initialization
Other addresses may
be added later by
driver software
In-class exercise
• Apply your knowledge of the Intel 82573L
‘Receive-filter Array’ to add the quadword
0x8000000000000000 at offset 0x5408 in
the NIC’s i/o-memory space
• Then test your modified ‘sendto.cpp’ code
to see if you can ‘receive’ a packet which
has ‘zero’ as its destination-address