"Driven learning - process analysis ifconfig to call the kernel, the kernel to achieve start up automatically set MAC address (the original)"

Kernel version: Linux Version 3.10.14

1. As each development board boot card physical address of eth0 are random

Then the line can be found on the Internet to achieve physical address set mac command:

ifconfig eth0 down
ifconfig eth0 hw ether 1234567890ab
ifconfig eth0 up

Then take curious to see how the kernel command line ifconfig is interacting with, I want to try how to automatically set the MAC directly by the kernel .


2. Analysis Introduction

Because the command is ifconfig, the code is busybox, but we find in the documentation directory of the kernel of the ifconfig introduction, introduce the code files are located in: documentation \ Networking \ ifenslave.c

2.1 shown below, and the corresponding ifconfig eth0 down ifconfig eth0 up function is:

 

 

 For example, when we knock ifconfig eth0 down time, but in reality it is to call:

set_if_down("eth0", master_flags.ifr_flags);

In addition to the file on the map, there are used the following functions:

set_if_addr ();            // Set the address (including IP, mask, broadcast, the destination) 
set_master_hwaddr ();      // set the physical address mac

Next we eth0, for example, to track ifconfig up / down and ifconfig eth0 hw ether how to call the kernel

3. Analyze set_if_up () function

3.1 Analysis set_if_up ()

set_if_up () function will be called set_if_flags ( "eth0", flags | IFF_UP) , to add ifname (eth0) open flag

 

 

3.2 分析set_if_up()->set_if_flags("eth0", flags | IFF_UP)

The function is as follows:

static int set_if_flags(char *ifname, short flags)
{
         struct ifreq ifr;
         int res = 0;
         ifr.ifr_flags = flags;                                            
         strncpy (ifr.ifr_name, ifname, IFNAMSIZ);     // ifr.ifr_name = "eth0" 

         RES = the ioctl (skfd, SIOCSIFFLAGS, & ifr);     // by ioctl () command is transmitted to the kernel variable SIOCSIFFLAGS and ifr Socket 
         IF (RES < 0 ) {
                  saved_errno = errno;
                  v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n",
                          ifname, strerror(saved_errno));
         } else {
                  v_print("Interface '%s': flags set to %04X.\n", ifname, flags);
         }
         return res;
}

3.3 macro SIOCSIFFLAGS looking to see where in the kernel to achieve it

Locate the net \ core \ Dev_ioctl.c of dev_ioctl () function

The important part of the function code is as follows:

int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
         struct ifreq ifr;
         int ret;
         char *colon;
         //… …

         switch (cmd) {
         //… …

         Case SIOCSIFFLAGS:    // flag is set up such as the ifconfig / Down 
         Case SIOCSIFMETRIC:    
          Case SIOCSIFMTU:      // Set MUT length 
         Case SIOCSIFHWADDR:   // set the physical address mac
          // ... ... 

         dev_load (NET, ifr.ifr_name);            // by ifr .ifr_name (eth0) name to load the card 
         rtnl_lock ();                            // to net_device be locked, to avoid conflict with the operation of 
         RET = dev_ifsioc (NET, & IFR, cmd);       // ultimately call the function

rtnl_unlock();
         Return the right;
         // ... ... 
}

As can be seen from the above, we set the mac flow when the physical address is also running here, eventually they will call dev_ifsioc (net, & ifr, cmd ) function

4. The back is very simple, and ultimately ifconfig eth0 up call the kernel process:

set_if_up()->

  set_if_flags("eth0", flags | IFF_UP)->

   dev_ifsioc(net, &ifr, cmd)->

      dev_change_flags(dev, ifr->ifr_flags)-> 

           __dev_change_flags(dev, flags);

Then 4.1 __dev_change_flags (dev, flags) function, is determined by the value of the flag whether the bit IFF_UP contrary, calling achieved __dev_close () or __dev_open () to switch eth0

As shown below:

Member function in net_device_ops structure 4.2 and __dev_open () will call the NIC driver to achieve open

 

__dev_open(dev):
   dev -> netdev_ops-> ndo_validate_addr (dev); // test dev-> dev_addr (hw addr) is valid, usually calling eth_validate_addr () function, you need to pay attention to hw_addr [0] is the least significant bit is not 1 
   dev-> netdev_ops -> ndo_open (dev);           // call open () function to achieve ifconfig up

4.3 Similarly __dev_close () member function calls the following achieve closure:

dev-> netdev_ops-> ndo_stop (dev);                 // call the stop () function to achieve ifconfig down

4.4 Where to find net_device_ops structure member functions located

Mentioned above is the struct net_device dev variable types, and struct net_device represent one of our network card driver equipment, registration documents are in the variable kernel drivers / net directory, to register by register_netdev () kernel function in the kernel.

We have our board dm9000 card, for example, the file is located in drivers / net / Ethernet / davicom / dm9000.c, then you can find it ndo_open ():

5. For ifconfig eth0 hw ether NIC setting process are as follows:

 

set_master_hwaddr(master_ifname,&(slave_hwaddr.ifr_hwaddr))->

  ioctl (skfd, SIOCSIFHWADDR, &ifr) ->                  

       dev_ifsioc(net, &ifr, cmd)->

            dev_set_mac_address (dev, & ifr-> ifr_hwaddr) ->              // set the MAC address 

                  dev -> netdev_ops-> ndo_set_mac_address (dev, & ifr-> ifr_hwaddr);  
                // final call net_device ops member functions to achieve the set

6. Implement kernel boot automatically set fixed MAC address

After the analysis process, then we have to implement it.

6.1 dm9000 card to our board as an example

We find register_netdev () location in the drivers / net / Ethernet / davicom / dm9000.c of dm9000_probe function in:

 

Then 6.2 register_netdev () function to add the code below:

struct        the sockaddr HWaddr;                    // to store the MAC address structure

rtnl_lock();
RET = dev_close (jz_ndev);                           // first need to close the card, in case 
rtnl_unlock ();

hwaddr.sa_family = ndev->type; 

hwaddr.sa_data [ 0 ] = 0x12 ;                       // note, data [0] is the least significant bit is not 1, that is not the first odd 
hwaddr.sa_data [ 1 ] = 0x34 ;
hwaddr.sa_data [ 2 ] = 0x56 ;
hwaddr.sa_data [ 3 ] = 0x78 ;
hwaddr.sa_data [ 4 ] = 0x90 ;
hwaddr.sa_data [ 5 ] = 0xab ;              

rtnl_lock();
RET = dev_set_mac_address (jz_ndev, & HWaddr);   // call the function to our analysis, to set the mac address 
rtnl_unlock ();

6.3 Compile - Test

 After starting the input ifconfig , you can see the kernel has helped me set up:

 

Guess you like

Origin www.cnblogs.com/zhuangquan/p/11707262.html