Main Page | Data Structures | File List | Data Fields | Globals

libmac_impl.h File Reference

Implementation details of all the functions in this library. More...

Go to the source code of this file.


Detailed Description

FUNCTIONS DEALING WITH THE INTERFACE INFORMATION:
  1. int mac_get_ifinfo(struct mac_ifinfo **mac_ptr);
    1. Open a connection to the system logger.
    2. Open a dummy socket. Socket descriptor returned by this call is passed to all ioctl function calls that follow.
      • On error, return errno.
    3. Get list of configured devices using the ioctl call with the SIOGIFCONF flag.
      • This ioctl call fills in the ifconf struct. with ifreq structs for all the interfaces present. For each ifreq struct, call function mac_memalloc_ifinfo.
        • On error, return errno.
        • On success, proceed to next ifreq struct.
    4. Close socket.
    5. return 0.
  2. static int mac_memalloc_ifinfo(struct mac_ifinfo **mac_ptr, int *skfd, char *ifname);
    1. Check argument list.
      • if either socket descriptor is NULL or if device name is NULL, return errno.
    2. Check whether the pointer stored in mac_ifinfo struct pointer is NULL. This check is to see whether the function is being called for the first time.
      • if pointer is NULL, then allocate memory for the mac_ifinfo struct.
        • On error, return errno.
        • On success, initialize version number field of struct.
        • On success, allocate memory for struct mac_ifinfo_list that stores information about a particular interface.
          • On error, return errno.
          • On success, call function mac_store_ifinfo.
            • On error, return errno.
            • On success, return 0.
      • if pointer is not NULL, then proceed to end of the linked list of structures of type mac_ifinfo_list.
        • allocate memory for struct mac_ifinfo_list that stores information about a particular interface.
          • On error, return errno.
          • On success, call function mac_store_ifinfo.
            • On error, return errno.
            • On success, return 0.
  3. static int mac_store_ifinfo(struct mac_ifinfo_list *node_ptr, int *skfd, char *ifname)
    1. Check argument list.
      • if either socket descriptor is NULL or if device name is NULL or pointer to struct mac_ifinfo_list is NULL, return errno.
    2. Initialize the structs, ifr and iwr that will be used by the ioctl function calls that follow.
    3. Make ioctl function call to check whether the interface corresponding to the name is a wireless interface.
      • On error, make another ioctl function call to check the flags.
        • On error, return errno.
        • On success, reset mac_flag member of struct mac_ifinfo_list to indicate that the interface is not wireless.
      • On success, set mac_flag member of struct mac_ifinfo_list to indicate that the interface is wireless.
    4. Make ioctl call to obtain hardware address of interface.
      • On error, return errno.
      • On success, store MAC addr of interface in struct mac_ifinfo_list.
    5. Make ioctl call to obtain IP address of interface.
      • On error, make another ioctl function call to check the flags.
        • On error, return errno.
        • On success, reset ip_addr member of struct mac_ifinfo_list to -1 to indicate that the interface does not have an IP address.
      • On success, store IP address of interface in struct mac_ifinfo_list.
    6. Initialize libnet and libpcap pointers to NULL.
    7. Initialize the bitmaps and also the variable that indicates the number of supported parameters to 0.
    8. Make ioctl call that returns supported parameters information.
      • On error, return errno.
      • On success, set the corresponding supported_params bits and the mode_params bits in struct mac_ifinfo_list.
    9. Initialize the mac_recv_frame_info struct to 0.
    10. return 0.
  4. void mac_free_ifinfo(struct mac_ifinfo **mac_ptr);
    1. Check to see whether *mac_ptr is NULL. If it is, then return from this function as there is nothing left to do.
    2. Start at the head of the linked list of structs, mac_ifinfo::mac_ifinfo_list, passed in through the first argument. Free memory allocated for the libnet and libpcap library pointers using the respective libnet and libpcap functions.
    3. Free memory for this member of the list and move to the next member.
    4. Repeat the above two steps in the same order till memory allocated for each member of the linked list is deallocated.
    5. Free memory allocated for the struct mac_ifinfo.
    6. Set *mac_ptr to NULL.
    7. return.
  5. int iw_sockets_open(void);
    1. From the families, AF_INET, AF_IPX, AF_AX25, AF_APPLETALK, return the datagram socket for the first successful socket call.
    2. If socket call fails for all families, return -1.
  6. char *pr_ether(unsigned char *ptr);
    1. Check whether the ptr passed as argument is NULL.
      • return NULL if it is.
    2. Store is a character buffer of maximum size 64, formatted MAC address in hexadecimal notation.
    3. return pointer to character buffer.

FUNCTIONS DEALING WITH SENDING A FRAME:

Since the frames are sent using the libnet library interface, the payload will first be packaged as an ethernet frame and then the driver will package this ethernet frame into an 802.11 frame. On the application's request, the driver will also append parameter information onto the frame. The generic format for frames sent by the send functions in this library will be as follows:

                           # of params appended      
       30     14   <1500    * len (each param)        
    |======|======|=======|====================|=========|
    |802.11| ETH  |Payload|Params.             |802.11   |
    |Header|Header|       |appended by driver  |trailer  |
    |======|======|=======|====================|=========|
    
    The number on top of each field is the size of that field in bytes.
    
  1. int mac_send_broadcast(unsigned char *payload, short len, struct mac_ifinfo_list *q);
    1. Check whether there are any parameters to be appended to outgoing frames.
      • Increment a local variable, initialized to zero for each bit that is set in the append_params_outgng bitmap member of the mac_ifinfo_list struct.
      • Calculate size in bytes of the parameters appended based on the length of the length field, the value field and the key field.
      • Calculate adjusted maximum frame size by subtracting the size of outgng. parameters calculated from MAX_FRAME_SIZE (1500).
    2. CHECKING PROPER USAGE: Check whether the two pointer arguments are not NULL and the integer argument is non-zero and non-negative. Check whether the length of the payload is greater than adjusted max. frame size:
      • On error, return errno.
    3. LIBNET FUNCTION CALLS:
      • Initialize libnet context only if not done before using the libnet_init function.
        • On error, return errno.
        • On success, store value in the link_struct member of the mac_ifinfo_list *q.
      • Statically allocate memory for the 6-byte unsigned char broadcast MAC address and initialize it to all 1s.
      • Create new payload buffer that holds the length of the payload ahead of the payload.
      • Build ethernet frame using the libnet_build_ethernet function. The first time this function is called, use value zero for libnet protocol block tag or id to request libnet to allocate a new memory block for the frame. On subsequent calls, use the value returned by the first call to the libnet_build_ethernet function, stored in ((q->link_struct)->protocol_blocks)->ptag. This is to prevent a new protocol block from being created each time this function is called. The above code ensures that only one protocol block is created for the frame and each time this function is called, the payload overwrites the previous payload contents.
        • On error, return errno.
      • Write frame to the wire using the libnet_write function.
        • On error, return errno.
      • On success, return 0.
  2. int mac_send_unicast(u_char *payload, short len, struct mac_ifinfo_list *q, unsigned char *ucast_mac);
    1. Check whether there are any parameters to be appended to outgoing frames.
      • Increment a local variable, initialized to zero for each bit that is set in the append_params_outgng bitmap member of the mac_ifinfo_list struct.
      • Calculate size in bytes of the parameters appended based on the length of the length field, the value field and the key field.
      • Calculate adjusted maximum frame size by subtracting the size of outgng. parameters calculated from MAX_FRAME_SIZE (1500).
    2. CHECKING PROPER USAGE: Check whether the two pointer arguments are not NULL and the integer argument is non-zero and non-negative. Check whether the length of the payload is greater than adjusted max. frame size:
      • On error, return errno.
    3. LIBNET FUNCTION CALLS:
      • Initialize libnet context only if not done before using the libnet_init function.
        • On error, return errno.
        • On success, store value in the link_struct member of the mac_ifinfo_list *q.
      • Create new payload buffer that holds the length of the payload ahead of the payload.
      • Build ethernet frame using the libnet_build_ethernet function exactly the same as in the broadcast function except that here, we use the unicast MAC address provided as argument.
        • On error, return errno.
      • Write frame to the wire using the libnet_write function.
        • On error, return errno.
      • On success, return 0.

FUNCTION DEALING WITH RECEIVING A FRAME:

The frames are received using the libpcap "packet capture" library. Functions in this library set errno, return NULL or -1 on error and return an error string. Unlike previous versions, the last argument of the function need not always be set such that only frames of type 0x0900 are picked up. Other kinds of filter arguments can be used as well, provided that they are within the framework of the pcap filters. The frame format seen by the recv. function of this library for 0x0900 frames is:

                                           # of params appended            
       14               <1500               * len (each param)  
    |======|==============================|====================| 
    | ETH  |Payload (prepended length     |Params              |
    |Header|+ payload)                    |appended by driver  |
    |======|==============================|====================|

    The number on top of each field is the size of that field in bytes.
    
The frame format for frames of type other than 0x0900 is:
                     # of params appended            
       14    <1500    * len (each param)          2
    |======|========|====================|===================| 
    | ETH  |Payload |Params              |Length of payload  |
    |Header|        |appended by driver  |appended by driver |
    |======|========|====================|===================|

    The number on top of each field is the size of that field in bytes.
    
The Params. field appended by the driver, for all frames, after the payload, is in the following format:

    |==============|===============|==============|===============|
    |# of send-side|send-side      |# of recv-side|recv-side      |   
    |params        |key-value pairs|params        |key-value pairs|  
    |==============|===============|==============|===============|
    

For frames of type 0x0900, this function, will look at the length field specified in the first 2 bytes of the payload to obtain length of the payload. For all other frames, this function will look for the length of the payload in the last 2 bytes of the received frame. Based on where the length is stored, the function will calculate the starting address of the payload and store this information in the appropriate argument. It will then jump to the start of the Params field. It will read the first byte of this field to obtain information on the number of send-side params that have been appended. It will calculate the length of this field in bytes. After obtaining the address of the sender side params., it will jump to the start of the recv-side params field and store its address. Finally, it will return these pointers to the calling function.

  1. int mac_recv(struct ether_header **header, char **payload, unsigned short *len, unsigned char **send_params, unsigned char **recv_params, struct mac_ifinfo_list *q, char *filter);
    1. CHECKING PROPER USAGE: Check whether the pointer arguments, header, payload, len, send_params, recv_params, q and filter are not NULL.
      • On error, return errno.
    2. Initialize the pointer to be passed to the pcap_loop callback function to point to frame_info member of q. We do this so that the information filled by the handle_ethernet function is stored in a location that is accessible once the function exits.
    3. LIBPCAP FUNCTION CALLS:
      • Initialize libpcap context only if not done before. The first time this function is called, open the interface, specified in the third argument (mac_ifinfo_list->if_name), to "sniff" frames based on the value of the filter argument. Open the device for sniffing using the pcap_open_live() function.
        • On error, return errno.
        • On success, a "packet capture descriptor" is returned by this function that is used by all following pcap functions. Fill the field mac_ifinfo_list->pcap_descr with the packet capture descriptor value obtained.
      • The pcap_setfilter function that helps us set up the filter specified by the filter argument, needs the network address of the interface. Further, it needs the network address to be represented as type bpf_u_int32. We use the pcap_lookupnet() function to obtain the network address for this interface. We do not use information from the mac_ifinfo_list struct since we need the network address value to be of a specific type.
        • On error, return errno.
      • Dynamically allocate memory for pointer to struct bpf_program. This struct holds the compiled filter program.
        • On error, return errno.
      • Set up a filter associated with the interface we are "sniffing" on, using the functions pcap_compile() and pcap_setfilter(), so as to process frames based on the last argument.
        • On error, free allocated memory for the struct bpf_program using function pcap_freecode().
        • On error, return errno.
      • Free up allocated memory for the struct bpf_program using function pcap_freecode() as it is no longer needed. This function does not return any value.
    4. LIBPCAP FUNCTION CALL TO CAPTURE A FRAME: Use function pcap_loop(), to capture a frame. Control is transferred to the handle_ethernet function.
      • On error, return errno.
    5. PARSE THE RECEIVED FRAME: When pcap_loop returns, control returns from handle_ethernet.
      • Save the pointer to the ethernet frame header in the first argument.
      • For frames of type 0x0900,
        • Save the extracted length in the second argument. Calculate the size of the length field in bytes. Move to the payload portion of the frame.
        • Save the starting address of the payload, in the frame received, in the first argument.
        • Check to see whether parameter information has been appended by comparing the difference of the total payload length, the size of the length field and the length of the payload with 0. If the difference is greater than zero, parameter information has been appended.
        • Check the append_params_incmg bitmap to see whether parameters are appended on incoming frames and count the number of these.
        • Calculate the size of these incoming parameters. Then check again whether the total payload length still exceeds the sum of the size of the length field, the length of the payload and the size of the incmg. parameter information. If so, then sender-side parameter information is also present. Store the appropriate addresses in the send_params and recv_params pointers.
        • If the total payload length indicates that only receive side parameters are present, then store the appropriate address in the recv_params pointer and store NULL in the send_params pointer.
        • If incoming parameter information is not appended and if the total payload length indicates that parameters are present, it means that only send-side parameters are available. Store the appropriate address in the send_params pointer and store NULL in the recv_params pointer.
        • If no parameter information is appended, just return payload and length of payload in appropriate pointers.
      • For all other frame types,
        • Save the starting address of the payload, in the frame received, in the first argument.
        • For frames that have not been sent by this receiver,
          • Save the length, appended at the end of the data, in the second argument.
          • Check to see whether parameter information has been appended by calculating the difference of the total payload length, the size of the length field (2 bytes) and the length of the payload. If this difference is greater than zero, parameter information has been appended. NOTE: PARAMETER INFORMATION IS APPENDED ON THESE FRAMES ONLY AT THE RECEIVER. There is no send-side parameter information in this case.
          • Check the append_params_incmg bitmap to see whether parameters are appended on incoming frames and count the number of these.
          • If the number exceeds one, then store the appropriate address in the recv_params pointer and store NULL in the send_params pointer.
          • If there are no receive-side parameters appended, then store NULL in both send-params pointer and recv_params pointer. Just return payload and length of payload in appropriate pointers.
        • For frames that have been sent by this receiver,
          • Store NULL in both send-params pointer and recv_params pointer. Just return payload and length of payload in appropriate pointers.
    6. END OF FUNCTION AND RETURN: return 0.
  2. int mac_promisc_recv(unsigned char **frame, unsigned short *frame_len, unsigned char **send_params, unsigned char **recv_params, struct mac_ifinfo_list *q);
    1. CHECKING PROPER USAGE: Check whether the pointer arguments, frame, frame_len, send_params, recv_params and q are not NULL.
      • On error, return errno.
    2. Initialize the pointer to be passed to the pcap_loop callback function to point to promisc_frame_info member of q. We do this so that the information filled by the handle_80211 function is stored in a location that is accessible once the function exits.
    3. LIBPCAP FUNCTION CALLS:
      • Initialize libpcap context only if not done before. The first time this function is called, open the interface, specified in the third argument (mac_ifinfo_list->if_name), to "sniff" frames. Open the device for sniffing using the pcap_open_live() function.
        • On error, return errno.
        • On success, a "packet capture descriptor" is returned by this function that is used by all following pcap functions. Fill the field mac_ifinfo_list->pcap_descr with the packet capture descriptor value obtained.
    4. LIBPCAP FUNCTION CALL TO CAPTURE A FRAME: Use function pcap_loop(), to capture a frame. Control is transferred to the handle_80211 function.
      • On error, return errno.
    5. PARSE THE RECEIVED FRAME: When pcap_loop returns, control returns from handle_80211.
      • Save the starting address of the frame in the first argument.
      • Save the length, returned in promisc_frame_info member by handle_80211, in the second argument.
      • Check to see whether parameter information has been appended by calculating the difference of the total frame length, the size of the length field (2 bytes) and the length appended at the end of the frame. If this difference is greater than zero, parameter information has been appended.
      • Check the append_params_incmg bitmap to see whether parameters are appended on incoming frames and count the number of these.
      • If the number exceeds one, then store the appropriate address in the recv_params pointer and store NULL in the send_params pointer.
      • If there are no receive-side parameters appended, then store NULL in both send-params pointer and recv_params pointer. Just return payload and length of payload in appropriate pointers. NOTE: The current version does not parse the received frame for send-side parameter information.
    6. END OF FUNCTION AND RETURN: return 0.
  3. static void handle_80211(unsigned char *mac_userdata, const struct pcap_pkthdr* pkthdr, const u_char* packet);
    1. Store pointer to the 802.11 frame and its length in the first argument, which is actually a pointer to struct mac_promisc_recv_frame_info.
  4. static void handle_ethernet(unsigned char *mac_userdata, const struct pcap_pkthdr* pkthdr, const u_char* packet);
    1. Typecast pointer packet to struct ether_header.
    2. Calculate length of payload, i.e. subtract total length by the length of ethernet header (14 bytes).
    3. Store pointer to the ethernet header, length and pointer to the start of the payload in the first argument, which is actually a pointer to struct mac_recv_frame_info.

FUNCTIONS DEALING WITH THE PARAMETERS:

For setting/getting/appending parameter information, the application proceeds in the manner specified below:

  1. From userspace, the application allocates memory for mac_params and mac_params_flags using the mac_init_params function.
  2. It calls the functions mac_set_params, mac_get_params and the mac_append_params functions depending on its requirements. The functions mac_set_params and mac_get_params store the parameter key, value pair information in the mac_params structure.
  3. After specifying its request/s,
  4. The calling function also needs to call the function mac_free_params before it exits.

For retrieving parameters appended in the received frame, the application proceeds in the manner specified below:

  1. From userspace, the application allocates memory for mac_params and mac_params_flags using the mac_init_params function.
  2. It calls the functions mac_set_params, mac_get_params and the mac_append_params functions depending on its requirements. The functions mac_set_params and mac_get_params store the parameter key, value pair information in the mac_params structure.
  3. Receive the frame using the mac_recv function. For the double pointers, initialize a pointer to NULL and then pass the address of that pointer to the mac_recv function, i.e. pass the address of a NULL pointer. The code will seg. fault otherwise.
  4. Free memory allocated using the mac_free_params struct once the application is done.

Driver-level support issues:

On the sending side as well as the receiving side, parameters are appended to frames by the respective drivers. Listed below are the requirements that need to be satisfied by the driver for appending parameters:

  1. the parameters need to be appended to frames of all types,
  2. this operation should not affect/interfere with the normal operation of other applications and
  3. an application built using the library should be able to process parameter information on every frame.

Currently, the library and drivers support send-side appending of parameters only for frames of type 0x0900. However, receive-side parameter appending is supported for all frame types. The drivers append parameters AFTER the payload of the ethernet frame or an 802.11 frame.

The format of the appended parameters at the sender and the receiver is the same and is shown below:

    |=========================|==============|==============|=====|
    | number of params        |<key1, value1>|<key2, value2>| ... |
    | requested to be appended|              |              |     |
    |=========================|==============|==============|=====|
    
The entire params. field, before being parsed and after recv-side parameters have been appended can be represented as follows:

    |==============|===============|==============|===============|
    |# of send-side|send-side      |# of recv-side|recv-side      |   
    |params        |key-value pairs|params        |key-value pairs|  
    |==============|===============|==============|===============|
    
  1. int mac_init_params(mac_params **h, mac_params_flags **g);
    1. Allocate memory for the mac_params struct.
      • On error, return errno.
    2. Initialize all members of the key array and the value array to INIT_VAL(-1).
    3. Initialize the lib_version field to the current version of this library.
    4. Allocate memory for the mac_params_flags struct.
      • On error, return errno.
    5. Initialize all flag members to 0.
    6. Initialize the lib_version field to the current version of this library.
    7. return 0.
  2. void mac_free_params(mac_params **h, mac_params_flags **g);
    1. Check argument list to see if *h and *g are NULL. If they are, then return immediately as there is nothing to do.
    2. Free memory allocated for the struct mac_params and struct mac_params_flags.
    3. return.
  3. int mac_get_params (struct mac_params *h, struct mac_ifinfo_list *if_ptr, int argc, ...);
    1. Check whether the mac_flag variable in the mac_ifinfo_list struct is set.
      • if not set, return errno = EOPNOTSUPP, i.e. operation not supported for wired interfaces.
    2. Check whether the two pointer arguments are not NULL and the integer argument is not less than or equal to zero.
      • On error, return errno.
    3. Open a dummy socket. Socket descriptor returned by this call is passed to ioctl function call that follows.
      • On error, return errno.
    4. Proceed to go through the variable argument list. The number of variable arguments (keys) should be specified in the third argument.
      • Check to see if the parameter key is one of those specified in the enum mac_parameter_keys.
        • if not, it means that rogue argument values have been specified either for the third argument or the ones after that.
        • if not, break from the loop since it is the third argument that is most likely the faulty one.
      • Check to see if the parameter corresponding to the key argument is supported.
        • if not supported, store UNSUPPORTED value in the mac_params struct.
      • If supported, call the ioctl function with the respective request.
        • On error, return errno.
        • On success, store value returned in the mac_params struct.
    5. Close socket and return 0.
  4. int mac_set_params (struct mac_params *h, struct mac_ifinfo_list *if_ptr, int argc, ...);
    1. Check whether the mac_flag variable in the mac_ifinfo_list struct is set.
      • if not set, return errno = EOPNOTSUPP, i.e. operation not supported for wired interfaces.
    2. Check whether the two pointer arguments are not NULL and the integer argument is not less than or equal to zero.
      • On error, return errno.
    3. Open a dummy socket. Socket descriptor returned by this call is passed to ioctl function call that follows.
      • On error, return errno.
    4. Proceed to go through the variable argument list. The number of variable arguments (key, value pair) should be specified in the third argument.
      • Check to see if the parameter key is one of those specified in the enum mac_parameter_keys.
        • if not, it means that rogue argument values have been specified either for the third argument or the ones after that.
        • if not, break from the loop since it is the third argument that is most likely the faulty one.
      • Check to see if the parameter corresponding to the key argument is supported.
        • if not supported, store UNSUPPORTED value in the mac_params struct and move on to next <key, value> pair.
      • If supported, check whether the parameter corresponding to the key can be set.
        • if parameter cannot be set, store READ_ONLY value in mac_params struct. and move on to next <key, value> pair.
      • If parameter can be set, check whether the interface name starts with a 'w'. We do this because for the eth2 (aironet) interfaces, we want to set tx power & tx rate using the /proc interface. All other parameters are set using the ioctl function.
        • On error, return errno.
        • On success, store value returned in the mac_params struct.
    5. Close socket and return 0.
  5. int mac_append_params (struct mac_ifinfo_list *if_ptr, unsigned char direction, int argc, ...);
    1. Check whether the mac_flag variable in the mac_ifinfo_list struct is set.
      • if not set, return errno = EOPNOTSUPP, i.e. operation not supported for wired interfaces.
    2. Check whether the pointer argument is NULL, the char argument is lesser than 2 and the integer argument is not less than or equal to zero.
      • On error, return errno.
    3. Open a dummy socket. Socket descriptor returned by this call is passed to ioctl function call that follows.
      • On error, return errno.
    4. Initialize mac_params_list struct to 0.
    5. Initialize iwr struct.
    6. For direction == OUTGOING or INCOMING,
      • For each argument in the variable argument list,
      • Check to see if the parameter key is one of those specified in the enum mac_parameter_keys.
        • if not, it means that rogue argument values have been specified either for the third argument or the ones after that.
        • if not, break from the loop since it is the third argument that is most likely the faulty one.
      • Check to see if the parameter corresponding to the key argument is supported.
        • if not supported, move on to next key.
      • If supported, switch based on the direction byte. Store the appropriate ioctl request and store the key in the mac_params_list struct. Set the bit flag corresponding to the parameter in the append_params_outgng member of the mac_ifinfo_list struct.
      • After parsing through the variable argument list, store the number of keys in the len member of mac_params_list.
    7. For direction == APPEND_OFF,
      • set request to appropriate value.
    8. Store the mac_params_list struct in the iwr struct.
    9. Make the ioctl function call.
      • On error, return errno.
    10. Close socket and return 0.

Generated on Tue Aug 24 17:01:41 2004 for libmac by doxygen 1.3.8