DHCP Client

Jump to: navigation, search

Table of Contents >> Optional Protocols

Dynamic Host Configuration Protocol (DHCP) allows a network interface to obtain a useful IP address without having any knowledge about the subnet to which the interface is connected. In some cases, the interface can choose an IP address from many offers tendered by more than one DHCP server. In such cases, it may be preferable to select one offer over all others.

The current Treck DHCP implementation selects the first offer received from any DHCP server. This is the quickest way the user can open an interface using DHCP and will continue to be the default operation for future Treck applications.

For those users that require more control, the Multiple DHCP Offers section describes a method whereby the user's application can remain in a selecting state while it collects offers from various DHCP servers. The user decides which offer to accept and when to accept it.

The Treck DHCP client also supports the DHCPINFORM message, which allows the user to obtain static configuration information (e.g. IP addresses for routers and DNS servers) from the DHCP server without having an IP address dynamically allocated by the server. Presumably, the user would obtain an IP address in some other manner and configure the address manually.


DHCP Code Configuration

If you have purchased the Treck DHCP client, the associated code will be enabled by default. You can adjust the Treck DHCP behavior and code size by defining or commenting out the following DHCP macros in your trsystem.h.

TM_USE_DHCP Enable DHCP. Comment out this macro in trsystem.h to eliminate all Treck DHCP code from your build.

Default: defined

TM_USE_DHCP_FQDN Enable the DHCP Client Fully Qualified Domain Name feature (see below). Uncomment this macro in trsystem.h if you need FQDN support.

Default: undefined

TM_DISABLE_DHCP_COLLECT Disable DHCP multiple offer collection/selection (see main section below). By default, Treck will select the first offer it gets from a DHCP server. This feature (enabled by default) allows you to delay the offer selection process and choose from multiple servers. Uncomment this macro in trsystem.h if you always want to accept the first offer and you wish to eliminate the code that provides multiple offer collection/selection.

Default: undefined (feature enabled)

TM_USE_DHCP_SEND_OVERLOAD Uncomment this macro in trsystem.h to enable DHCP option overload on send. If enabled, Treck will try to limit the length of outbound DHCP messages to 548 bytes or less by moving options to the unused sname and file message fields, if necessary. You can override the default limit by setting TM_DHCP_SEND_OVERLOAD_THRESHOLD (see below).
Beware, some DHCP servers do not support option overload.

Default: undefined (option overload disabled)

TM_DHCP_SEND_OVERLOAD_THRESHOLD Set the threshold beyond which Treck will apply option overloading to shrink the DHCP message before sending it. This macro has no effect if TM_USE_DHCP_SEND_OVERLOAD is not defined.
You can also call tfInterfaceSetOptions() at runtime with option TM_DEV_OPTIONS_DHCP_MIN_OVERLOAD to change the option overload threshold for an interface.

Default: 548
Minimum: 548

TM_USE_DHCP_DOMAIN_SEARCH Enable DHCP Domain Search option support. By default, Treck will not request the Domain Search Option (RFC 3397) from the server. Uncomment this macro to add the code to support this option. See the Domain Search Option section below.

Default: undefined

TM_DHCP_CB_WITH_MHOME Uncomment this macro to receive the multihome index as an additional parameter to your address notification callback function. See tfUseDhcp() for the prototype.

Default: undefined

TM_DHCP_CB_RELEASE Uncomment this macro to allow time for the DHCP Release message to be sent when unconfiguring a DHCP autoconfigured address (via tfNgUnConfigInterface(), for example). You will receive notification by way of a TM_ENETDOWN error passed to your DHCP callback function (see tfUseDhcp()) when the send is complete (successful or not). This does not guarantee receipt of the message by the DHCP server.

Default: undefined

DHCP Automatic Configuration

Description

The DHCP user interface allows the user to query directly a DHCP server, for IP addresses that the user can use. The Treck stack allows the user to retrieve the DHCP addresses automatically.

When the user configures an interface/multihome, the Treck stack automatically queries a DHCP server for an IP address and parameters, and finishes configuring the interface/multihome with the IP address and default router given by the DHCP server. Up to TM_MAX_IPS_PER_IF multihomes per interface can be configured that way.

In that case, the following steps are needed (after having called linkLayerHandle = tfUseEthernet()):

interfaceHandle = tfAddInterface(namePtr, linkLayerHandle, ...);
 
errorCode = tfUseDhcp(interfaceHandle, myNotifyFunction);
 
errorCode = tfOpenInterface(interfaceHandle,
                            0UL,
                            0UL,
                            TM_DEV_IP_DHCP,
                            1);

Note that we have called tfOpenInterface() with the TM_DEV_IP_DHCP flag set. (Note other flags such as TM_DEV_IP_FORW_ENB could be OR'ed to TM_DEV_IP_DHCP as needed.)

Note Note: The user needs to wait for the DHCP configuration to complete. During the wait, ensure tfTimerUpdate() (or tfTimerUpdateIsr()), and tfTimerExecute() get called.


Alternatively, you can manually set an IP address on an interface and have the Treck DHCP client use the DHCPINFORM message to gather other useful information, like the default router and DNS servers for the link. You must add the TM_DEV_DHCP_INFO_ONLY flag and a non-zero IP address, as shown below.

interfaceHandle = tfAddInterface(namePtr, linkLayerHandle, ...);
 
errorCode = tfUseDhcp(interfaceHandle, myNotifyFunction);
 
errorCode = tfOpenInterface(interfaceHandle,
                            inet_addr("1.2.3.4"),
                            inet_addr("255.255.255.0"),
                            TM_DEV_IP_DHCP | TM_DEV_DHCP_INFO_ONLY,
                            1);
 
/* . . . wait for DHCP notification via myNotifyFunction() . . . */
 
bootInfoPtr = tfConfGetBootEntry(interfaceHandle, 0);
 
errorCode = tfDnsSetServer(bootInfoPtr->btuDns1ServerIpAddress, TM_DNS_PRI_SERVER);

The Treck DHCP client will automatically configure the default router for the interface when a positive response is received from the DHCP server.

The static DHCP configuration information associated with the TM_DEV_DHCP_INFO_ONLY flag is permanent. If necessary, the user can restart the DHCPINFORM message exchange and (hopefully) refresh the configuration information by calling tfDhcpConfInformRefresh() as in the example below.

errorCode = tfDhcpConfInformRefresh(interfaceHandle, multihomeIndex);

Upon completion of the DHCPINFORM exchange, the user will be notified via callback (myNotifyFunction() in the example above) of the success or failure. If successful, the new information can be retrieved by calling tfConfGetBootEntry()

User controlled configuration parameters

A user API tfDhcpConfSet() is provided to allow the user to:

  • Set the DHCP initial state to INIT_REBOOT (instead of the default INIT state) with a user specified requested IP address, and client ID.
  • Set a user specified requested IP address, and/or Client ID while DHCP is in the INIT state.
  • Allow the user to suppress the client ID option.

Additionally the tfDhcpConfSetAttributes() API allows the user to change the default values for the following attributes for an individual multi-homed index on an interface:

  • Set a timeout value to limit the length of time spent in the selecting phase.
  • Set an upper limit on the number of DHCP offers that the interface will cache (only valid when using the callback feature).
  • Specify the preferred IP address that will automatically be accepted.
  • Control what is to happen if the preferred IP address has not been offered within the timeout period:
    • accept any other offer , or
    • cancel DHCP.
  • Select an offer that is currently in the cache (only valid when using the callback feature).
  • Remove an offer that is currently in the cache (only valid when using the callback feature). Use this feature to create space in the offer cache so that other, more important offers are not bumped from the cache.
  • Revert back to legacy mode of operation, as discussed earlier.


Note Note: You cannot mix use of preferred IP address or legacy mode with the user callback feature on the same interface. The user's offer callback function is global to all indices on an interface and, at the moment you register your callback function, will become the sole mode of operation across all multi-home indices. Conversely, when you specify a preferred IP address or select legacy mode for a multi-home index, any previously registered offer callback will be undone for all indices.

Default values for time limit and cache size are inherited from the interface, as set with tfInterfaceSetOptions() or as defined by macros TM_DHCP_DEF_COLLECT_TIMEOUT and TM_DHCP_DEF_COLLECT_CACHE.

ARP probes sent by the DHCP client

The DHCP client will send several ARP Probes (i.e. ARP request with a sender net address set to 0) to make sure that no other node has been configured with the same IP address. If a node responds, then the DHCP client would decline the IP address, and restart the discovery process in the INIT state after 10 seconds have elapsed.

Checking on completion of an automatic DHCP configuration

  • Synchronous check: The user can make multiple calls to tfOpenInterface() to determine when the IP address configuration has completed. Additional calls to tfOpenInterface() will return TM_EINPROGRESS as long as the DHCP server has not replied and the IP address has not been configured by some other means. tfOpenInterface() will return TM_ENOERROR when IP address configuration has completed.

    If you use the TM_DEV_DHCP_INFO_ONLY flag, you will also be manually configuring an IP address. The return code from tfOpenInterface() will indicate the result of IP address configuration only. To synchronously determine when your DHCP information request has successfully completed, check for a non-null pointer return from tfConfGetBootEntry():

myDhcpInfoPtr = tfConfGetBootEntry(interfaceHandle, 0);
  • Asynchronous check: To avoid this synchronous poll, the user can provide a user call back function to tfUseDhcp() as shown above. This function will be called upon completion of tfOpenInterface(). The notifyFunc is called as follows:
myNotifyFunction(interfaceHandle, errorCode);
where 'errorCode' is as follows:
  • TM_ENOERROR: the configuration (or lease renewal) was successful
  • TM_ETIMEDOUT: the initial DHCP request timed out, or the address expired while the Rebind operation was in progress
  • TM_EHOSTDOWN: the Renew operation failed because the server did not respond
  • TM_EPERM: the Renew operation failed because a NAK was received from the server
Note Note: If you use the TM_DEV_DHCP_INFO_ONLY flag, the manually configured IP address will probably be ready before the DHCPINFORM response is received from the DHCP server. In this case, you should use the asynchronous check to determine when the DHCP information becomes available or the Treck client times out waiting for the server to respond.

Automatic DHCP Configuration parameters

When the DHCP configuration has completed successfully as shown above, the user can retrieve the DHCP configuration parameters by calling:

userBtEntryPtr = tfConfGetBootEntry(ethernetInterfaceHandle, multiHomeIndex);

If the DHCP configuration has been successful, this function will return a pointer to a boot structure (null otherwise).

The userBtEntryPtr is a pointer to a structure defined in <trsocket.h>. In particular, the userBtEntryPtr will contain:

  • The allocated IP address in the field userBtEntryPtr->btuYiaddr.
  • The subnet mask in the field userBtEntryPtr->btuNetMask.
  • Default router entry in the field userBtEntryPtr->btuDefRouter.
  • Primary Domain name server userBtEntryPtr->btuDns1ServerIpAddress.
  • Secondary Domain name server userBtEntryPtr->btuDns2ServerIpAddress.
  • An array of up to TM_DHCP_NBNS_NUM_SERVER NetBios name servers (IPv4 addresses) returned in the NBNS option userBtEntryPtr->btuNetBiosNameServers[].
By default TM_DHCP_NBNS_NUM_SERVER is equal to 2 - allowing the storage of 2 name servers.
  • The actual number of NetBios name servers saved in the array above is in field userBtEntryPtr->btuNetBiosNumNameServers.

Configuring additional automatic DHCP IP addresses on the same interface

To configure additional automatic DHCP IP addresses on the same interface (multi homing), use tfConfigInterface() instead of tfOpenInterface().

Unscheduled renewal of automatic DHCP IP address leases

The DHCP server typically leases an IP address to a client for a limited length of time. The IP address and the lease time are determined by the server. The Treck DHCP client will attempt to renew the IP address lease automatically, by communicating with one or more DHCP servers at the appropriate time.

If the user has knowledge of events external to Treck's DHCP client that suggest an IP address may no longer be valid (e.g. Ethernet or wireless link disconnect/reconnect), the user can manually initiate the IP address lease renewal by calling tfDhcpConfRenewLease(), as shown below.

errorCode = tfDhcpConfRenewLease(interfaceHandle, multihomeIndex, timeoutMilliSecs, retries);

Upon completion, the user will be notified via callback of the success or failure of the lease renewal. If successful, the new information can be retrieved by calling tfConfGetBootEntry().

DHCP FQDN Option

FQDN is DHCP option 81. The FQDN option enables DHCP clients and DHCP servers to exchange the DHCP client domain name information for the purpose of dynamically updating this information in the DNS (Domain Name System).

The FQDN option consists of a domain name and a set of flags. This option, when enabled, is sent in the DHCPREQUEST and DHCPACK messages by both the client and the server.

The DHCP client sends its domain name to the DHCP server during the exchange and the server acknowledges it if it supports this feature.

At the end of the DHCP transaction, both the client and the server know the client's domain name. Flags are used to negotiate which part of the DNS update will be performed by the DHCP server and which part by the DHCP client. The Treck DHCP client always fully delegates the DNS "A" and "AAAA" resource record updates to the DHCP server (the DHCP server will update the "PTR" reverse-lookup resource record).

To use FQDN, #define TM_USE_DHCP_FQDN in <trsystem.h> and rebuild the Treck stack.

Your application can then enable the use of FQDN with DHCP client by specifying the TM_DHCPF_FQDN_ENABLE flag when calling the APIs tfDhcpConfSet()/tfDhcpUserSet(), and passing the desired domain name in the clientIdPtr and clientIdLength parameters.

Function tfUserSetFqdn() can be called to set the default system-wide FQDN that will be used unless the FQDN is set with tfDhcpConfSet() or tfDhcpUserSet().

If DHCP FQDN is enabled, userBtEntry will also contain the FQDN option-related parameters:

  • The FQDN domain name returned by the server in userBtEntryPtr->btuServerFqdn.
  • The FQDN domain name length in userBtEntryPtr->btuServerFqdnLen.
  • DNS error codes RCode1 and RCode2 returned by the DHCP server in userBtEntryPtr->btuFqdnRCode1 and userBtEntryPtr->btuFqdnRCode2.
  • Flags that indicate the FQDN update status in userBtEntryPtr->btuFqdnStatus.

Possible values for the flags are a combination of:

  • TM_FQDNF_PARTIAL if the received domain name was partial
  • TM_FQDNF_MALFORMED if the DHCP server returned a malformed domain name
  • TM_FQDNF_NOT_SUPPORTED if the DHCP server does not support the FQDN option
  • TM_FQDNF_NAMEREPLY if the DHCP server FQDN option reply contained a domain name.

Domain Search Option (RFC 3397)

The DHCP server supplies this option so that the client may try alternative domain names when attempting to use DNS to resolve a hostname. Uncomment the following configuration macro in your trsystem.h to enable support for the Domain Search Option.

#define TM_USE_DHCP_DOMAIN_SEARCH

When this feature is enabled, the Treck DHCP client will request the Domain Search Option from the server and, after DHCP completes, you can call function tfDhcpGetDomainSearch(), as shown below, to extract each domain name for the respective DHCP auto-configured multihome address.

    for (i = 0; ; ++i)
    {
/* Get the next domain name for multihome index 0 */
        bufLen = sizeof(buf) - 1;
        errorCode = tfDhcpGetDomainSearch(interfaceHandle,
                                          TM_BT_CONF,
                                          0,
                                          i,
                                          buf,
                                          &bufLen);
        if (errorCode == TM_ENOENT)
        {
/* End of list */
            break;
        }
        if (errorCode != TM_ENOERROR)
        {
            printf("Error on index %d: %d\n", i, errorCode);
            break;
        }
        buf[bufLen] = '\0';
        printf("Domain name for index %d: %s\n", i, buf);
    }
Note Note: This feature is closely related to the DNS Domain Search feature, which allows DHCP domain information to automatically be employed when trying to resolve partial hostnames.

Other Options

Some options are not inherently supported in the boot entry structure or through the conventional configuration API (e.g. tfDhcpConfSet). Treck provides functions for handling options that would otherwise be unsupported and inaccessible. Table 1 shows some examples of options you may wish to send or view.

Table 1 - Examples of custom DHCP options
Option Description
43 Vendor-specific information (RFC 2132, section 8.4).
56 Human-readable message (e.g. error message) (RFC 2132, section 9.9).
60 Vendor class identifier (RFC 2132, section 9.13).
124 Vendor-identifying vendor class option (RFC 3925, section 3).
125 Vendor-identifying vendor-specific information option (RFC 3925, section 4).

The following functions allow you to send custom options to a DHCP server. Treck will automatically insert the DHCP option header ahead of the option data. The option is specific to one multihome index on one interface but you can call the functions again for another interface or index. Once set, the option will persist until you clear it (i.e. even if the interface is closed and reopened).

  • tfDhcpConfSetOption() - Set the data for a custom, non-native option that you want to send to a server. This function supports option lengths up to and including 255 bytes.
  • tfNgDhcpSetOption() - Set the data for a custom, non-native option that you want to send to a server. Specify an indexType of TM_BT_CONF. Options longer than 255 bytes will be split into multiple options (see RFC 3396). Note that not all servers support concatenation of long options.
  • tfDhcpClearOptions() - Clear all custom options set for a multihome index on an interface. Specify an indexType of TM_BT_CONF.

The following functions allow you to retrieve custom options received from a DHCP server. Treck will automatically remove the DHCP option header and concatenate options as required (see RFC 3396).

  • tfDhcpConfGetOption() - Retrieve the data for a custom, non-native option that was sent by a server. This function supports option lengths up to and including 255 bytes.
  • tfNgDhcpGetOption() - Retrieve the data for a custom, non-native option that was sent by a server. Specify an indexType of TM_BT_CONF.

Function Calls

DHCP User Configured

Description

With the user-controlled configuration, the user can query a DHCP server directly without automatically configuring an interface. This is useful for example on a box that has an Ethernet interface, serial lines, and acts as a PPP server for the serial lines. The user could get IP addresses from a DHCP server via the Ethernet interface and then assign those IP addresses to PPP clients on its serial lines.

Those IP addresses should also be added to the box proxy ARP table, so that the box can respond to ARP requests on behalf of its PPP clients.

The following steps are needed:

tfInitTreckOptions() must be called before tfStartTreck() is called in order to reserve numberSerialLines DHCP user entries.

errorCode = tfInitTreckOptions(TM_OPTION_DHCP_MAX_ENTRIES,
                               (unsigned long)numberSerialLines);

If no error:

errorCode = tfStartTreck();

Add all your link layers, and interfaces. For Ethernet, call:

ethernetLinkLayerHandle = tfUseEthernet();
 
ethernetInterfaceHandle = tfAddInterface(namePtr, ethernetLinkLayerhandle, ...);

For PPP, call tfUseAsyncServerPpp() once, and tfAddInterface() for each serial line. Save each PPP serial lines interface handle returned by each tfAddInterface() in a table.

Configure the Ethernet interface with either a static IP address and IP netmask, or using DHCP as shown in the Automatic Configuration paragraph above. If using DHCP, wait for the tfOpenInterface() to complete.

Ask for a DHCP address on the Ethernet interface for one PPP interface client.

errorCode = tfDhcpUserStart(ethernetInterfaceHandle,
                            userIndex,
                            dhcpNotifyFunc);

'userIndex' must be initialized to zero for the first query (first PPP interface), 1 for a second query, etc..

A zero return value indicates that the DHCP request has completed successfully. A TM_EINPROGRESS return value indicates that a DHCP configure or request has been sent, and this is OK.

A TM_EALREADY return value indicates that a DHCP discover/request has already been sent because of a previous call to tfDhcpUserStart().

If 'errorCode' is TM_EINPROGRESS, or TM_EALREADY, wait for the DHCP configuration to complete (i.e. for dhcpNotifyFunc to be called). During the wait, ensure tfTimerUpdate() (or tfTimerUpdateIsr()), and tfTimerExecute() are called. When the DHCP request has completed or timed out, the dhcpNotifyFunc will be called as follows:

dhcpNotifyFunc(ethernetInterfaceHandle, errorCode, userIndex);

The 'userIndex' corresponds to the second parameter of tfDhcpUserStart(), and 'errorCode' indicates whether the DHCP request has been successful (i.e errorCode == TM_ENOERROR), the server responded with a NAK (errorCode == TM_EPERM), or timed out (errorCode == TM_ETIMEDOUT).

User controlled configuration parameters

A user API tfDhcpUserSet() is provided to allow the user to:

  • Set the DHCP initial state to INIT_REBOOT (instead of the default INIT state) with a user specified requested IP address, and client ID.
  • Set a user specified requested IP address, and/or Client ID while DHCP is in the INIT state.
  • Allow the user to suppress the client ID option.
  • Tell the DHCP server to return static configuration information without allocating an IP address (i.e. send a DHCPINFORM message instead of sending DHCPDISCOVER and DHCPREQUEST messages).

When calling tfDhcpUserSet() with the TM_DHCPF_INFO_ONLY flag, the static DHCP configuration information returned is not automatically renewed. If necessary, the user can restart the DHCPINFORM message exchange and (hopefully) refresh the configuration information by calling tfDhcpUserInformRefresh() as in the example below.

errorCode = tfDhcpUserInformRefresh(interfaceHandle, userIndex);

Upon completion of the DHCPINFORM exchange, the user will be notified via callback of the success or failure. If successful, the new information can be retrieved by calling tfDhcpUserGetBootEntry().

Additionally, the tfDhcpUserSetAttributes() API allows the user to change the default values for the following attributes for an individual multi-homed index on an interface:

  • Set a timeout value to limit the length of time spent in the selecting phase.
  • Set an upper limit on the number of DHCP offers that the interface will cache (only valid when using the callback feature).
  • Specify the preferred IP address that will automatically be accepted.
  • Control what is to happen if the preferred IP address has not been offered within the timeout period:
    • accept any other offer , or
    • cancel DHCP.
  • Select an offer that is currently in the cache (only valid when using the callback feature).
  • Remove an offer that is currently in the cache (only valid when using the callback feature). Use this feature to create space in the offer cache so that other, more important offers are not bumped from the cache.
  • Revert back to legacy mode of operation, as discussed earlier.


Note Note: You cannot mix use of preferred IP address or legacy mode with the user callback feature on the same interface. The user's offer callback function is global to all indices on an interface and, at the moment you register your callback function, will become the sole mode of operation across all multi-home indices. Conversely, when you specify a preferred IP address or select legacy mode for a multi-home index, any previously registered offer callback will be undone for all indices.

Default values for time limit and cache size are inherited from the interface, as set with tfInterfaceSetOptions() or as defined by macros TM_DHCP_DEF_COLLECT_TIMEOUT and TM_DHCP_DEF_COLLECT_CACHE.

ARP probes sent by the DHCP client

If the TM_USE_AUTO_IP macro is defined in <trsystem.h>, and the AUTO IP option has been purchased, then the DHCP client will send several ARP Probes (i.e. ARP request with a sender net address set to 0) to make sure that no other node has been configured with the same IP address. If a node responds, then the DHCP client would decline the IP address, and restart the discovery process in the INIT state after 10 seconds have elapsed.

When the DHCP request is successful, the user can retrieve the IP address and parameters given by the DHCP server:

userBtEntryPtr = tfDhcpUserGetBootEntry(ethernetInterfaceHandle, userIndex);


If the DHCP configuration has been successful, this function will return a pointer to a boot structure (null otherwise).

The 'userBtEntryPtr' is a pointer to a structure defined in <trsocket.h>. In particular, the 'userBtEntryPtr' will contain:

  • The allocated IP address in the field userBtEntryPtr->btuYiaddr.
  • The subnet mask in the field userBtEntryPtr->btuNetMask.
  • Default router entry in the field userBtEntryPtr->btuDefRouter.
  • Primary Domain name server userBtEntryPtr->btuDns1ServerIpAddress.
  • Secondary Domain name server userBtEntryPtr->btuDns2ServerIpAddress.
  • An array of TM_DHCP_NBNS_NUM_SERVER NetBios name servers (IPv4 addresses) returned in the NBNS option userBtEntryPtr->btuNetBiosNumNameServers[].
By default TM_DHCP_NBNS_NUM_SERVER is equal to 2 - allowing the storage of 2 name servers.
  • The number of NetBios name servers userBtEntryPtr->btuNetBiosNumNameServers.


The user should save the 'userBtEntryPtr' in its PPP table (where it previously stored the corresponding PPP interface handle, 'pppInterfaceId').

The user can now assign that IP address to its future serial line PPP client, by calling:

errorCode = tfPppSetOption(pppInterfaceId,
                           TM_PPP_IPCP_PROTOCOL,
                           TM_PPP_OPT_ALLOW,
                           TM_IPCP_IP_ADDRESS,
                           (const char TM_FAR *)&userBtEntryPtr->btuYiaddr,
                           4);

The user can then configure that PPP interface calling tfOpenInterface() with this pppInterfaceId parameter, using a static IP address for its interface. In the link layer call back function (set in tfUseAsyncServerPpp()), if the flag is TM_LL_OPEN_COMPLETE, then the user can add the PROXY ARP entry:

tfAddProxyArpEntry(userBtEntryPtr->btuYiaddr);

In the link layer call back function, if the flag is TM_LL_CLOSE_STARTED then the user can delete the PROXY ARP entry:

tfDelProxyArpEntry(userBtEntryPtr->btuYiaddr);

The user can request for additional DHCP IP addresses for additional PPP serial lines, repeating this process starting at tfDhcpUserStart() above with different userIndex, and pppInterfaceId values.

If the user were to close the Ethernet interface, then all the DHCP addresses that were allocated with the tfDhcpUserStart() calls should be released prior to closing the Ethernet interface, by calling:

tfDhcpUserRelease(ethernetInterfaceHandle, userIndex);

This must be done for each userIndex that was used in a successful tfDhcpUserStart().

Unscheduled renewal of user-controlled DHCP IP address leases

The DHCP server typically leases an IP address to a client for a limited length of time. The IP address and the lease time are determined by the server. The Treck DHCP client will attempt to renew the IP address lease automatically, by communicating with one or more DHCP servers at the appropriate time.

If the user has knowledge of events external to Treck's DHCP client that suggest an IP address may no longer be valid (e.g. Ethernet or wireless link disconnect/reconnect), the user can manually initiate the IP address lease renewal by calling tfDhcpUserRenewLease(), as shown below.

errorCode = tfDhcpUserRenewLease(interfaceHandle, userIndex, timeoutMilliSecs, retries);

Upon completion, the user will be notified via callback of the success or failure of the lease renewal. If successful, the new information can be retrieved by calling tfDhcpUserGetBootEntry().

DHCP FQDN Option

FQDN is DHCP option 81. The FQDN option enables DHCP clients and DHCP servers to exchange the DHCP client domain name information for the purpose of dynamically updating this information in the DNS (Domain Name System).

The FQDN option consists of a domain name and a set of flags. This option, when enabled, is sent in the DHCPREQUEST and DHCPACK messages by both the client and the server.

The DHCP client sends its domain name to the DHCP server during the exchange and the server acknowledges it if it supports this feature.

At the end of the DHCP transaction, both the client and the server know the client's domain name. Flags are used to negotiate which part of the DNS update will be performed by the DHCP server and which part by the DHCP client. The Treck DHCP client always fully delegates the DNS "A" and "AAAA" resource record updates to the DHCP server (the DHCP server will update the "PTR" reverse-lookup resource record).

To use FQDN, #define TM_USE_DHCP_FQDN in <trsystem.h> and rebuild the Treck stack.

Your application can then enable the use of FQDN with DHCP client by specifying the TM_DHCPF_FQDN_ENABLE flag when calling the APIs tfDhcpConfSet()/tfDhcpUserSet(), and passing the desired domain name in the clientIdPtr and clientIdLength parameters.

If DHCP FQDN is enabled, userBtEntry will also contain the FQDN option-related parameters:

  • The FQDN domain name returned by the server in userBtEntryPtr->btuServerFqdn.
  • The FQDN domain name length in userBtEntryPtr->btuServerFqdnLen.
  • DNS error codes RCode1 and RCode2 returned by the DHCP server in userBtEntryPtr->btuFqdnRCode1 and userBtEntryPtr->btuFqdnRCode2.
  • Flags that indicate the FQDN update status in userBtEntryPtr->btuFqdnStatus.

Possible values for the flags are a combination of:

  • TM_FQDNF_PARTIAL if the received domain name was partial
  • TM_FQDNF_MALFORMED if the DHCP server returned a malformed domain name
  • TM_FQDNF_NOT_SUPPORTED if the DHCP server does not support the FQDN option
  • TM_FQDNF_NAMEREPLY if the DHCP server FQDN option reply contained a domain name.

Domain Search Option (RFC 3397)

The DHCP server supplies this option so that the client may try alternative domain names when attempting to use DNS to resolve a hostname. Uncomment the following configuration macro in your trsystem.h to enable support for the Domain Search Option.

#define TM_USE_DHCP_DOMAIN_SEARCH

When this feature is enabled, the Treck DHCP client will request the Domain Search Option from the server and, after DHCP completes, you can call function tfDhcpGetDomainSearch(), as shown below, to extract each domain name for the respective DHCP user configured address.

    for (i = 0; ; ++i)
    {
/* Get the next domain name for user configured index 0 */
        bufLen = sizeof(buf) - 1;
        errorCode = tfDhcpGetDomainSearch(interfaceHandle,
                                          TM_BT_USER,
                                          0,
                                          i,
                                          buf,
                                          &bufLen);
        if (errorCode == TM_ENOENT)
        {
/* End of list */
            break;
        }
        if (errorCode != TM_ENOERROR)
        {
            printf("Error on index %d: %d\n", i, errorCode);
            break;
        }
        buf[bufLen] = '\0';
        printf("Domain name for index %d: %s\n", i, buf);
    }

Other Options

Some options are not inherently supported in the boot entry structure or through the conventional configuration API (e.g. tfDhcpUserSet). Treck provides functions for handling options that would otherwise be unsupported and inaccessible. Table 1 above shows some examples of options you may wish to send or view.

The following functions allow you to send custom options to a DHCP server. Treck will automatically insert the DHCP option header ahead of the option data. The option is specific to one multihome index on one interface but you can call the functions again for another interface or index. Once set, the option will persist until you clear it (i.e. even if the interface is closed and reopened).

  • tfDhcpUserSetOption() - Set the data for a custom, non-native option that you want to send to a server. This function supports option lengths up to and including 255 bytes.
  • tfNgDhcpSetOption() - Set the data for a custom, non-native option that you want to send to a server. Specify an indexType of TM_BT_USER. Options longer than 255 bytes will be split into multiple options (see RFC 3396). Note that not all servers support concatenation of long options.
  • tfDhcpClearOptions() - Clear all custom options set for a multihome index on an interface. Specify an indexType of TM_BT_USER.

The following functions allow you to retrieve custom options received from a DHCP server. Treck will automatically remove the DHCP option header and concatenate options as required (see RFC 3396).

  • tfDhcpUserGetOption() - Retrieve the data for a custom, non-native option that was sent by a server. This function supports option lengths up to and including 255 bytes.
  • tfNgDhcpGetOption() - Retrieve the data for a custom, non-native option that was sent by a server. Specify an indexType of TM_BT_USER.

Function Calls

Multiple DHCP Offers

If there is more than one DHCP server on a network, the first DHCPOFFER supplied may not always be the best fit. As suggested in RFC 2131, the DHCP client may wait for multiple DHCPOFFER responses before choosing an offer from one particular server.

Treck offers the following alternatives for managing DHCPOFFER responses from multiple servers:

  • Legacy mode. Treck selects the first offer received from any DHCP server. This is the default mode of operation.
  • User-defined IP address, if available. Wait for an offer containing the specified IP address. If the IP address is not offered within a reasonable length of time, take any other offer.
  • User-defined IP address, exclusively. Wait for the specified IP address and, if is not offered within a reasonable length of time, cancel the DHCP operation on the interface.
  • Full control. You supply a callback function that can examine each offer and select the one that is suitable.

You can adjust the maximum length of time that Treck will collect offers which, by default, is 15 seconds. If you register a callback function, you can also adjust the maximum number of offers that Treck will cache. By default, the cache will hold one DHCP offer.

Compile Time Configuration

The DHCP offer collect and select features mentioned here will be included with DHCP support by default. You can explicitly remove these features and reduce code size by defining the TM_DISABLE_DHCP_COLLECT macro in <trsystem.h>.

You may also define your own default values for the following attributes:

  • time limit on collecting DHCP offers,
  • cache size for collecting DHCP offers.

The corresponding macros will be defined as follows unless you define them in <trsystem.h>:

#define TM_DHCP_DEF_COLLECT_TIMEOUT 15
#define TM_DHCP_DEF_COLLECT_CACHE   1

These attribute values will be inherited by all interfaces, but can be overridden at runtime with the following functions:

  • tfInterfaceSetOptions(), options TM_DEV_OPTIONS_DHCP_COLLECT_TIME and TM_DEV_OPTIONS_DHCP_COLLECT_CACHE. Options set in this manner will be inherited by all addresses configured on the specified interface.
  • tfDhcpConfSetAttributes(), options TM_DHCP_ATTR_COLLECT_TIME and TM_DHCP_ATTR_COLLECT_CACHE. This controls an automatically configured address on an interface (described above).
  • tfDhcpUserSetAttributes(), options TM_DHCP_ATTR_COLLECT_TIME and TM_DHCP_ATTR_COLLECT_CACHE. This controls a user configured address on an interface (described above).

The TM_DHCP_DEF_COLLECT_CACHE option is only meaningful when registering a callback function (see User Controlled Offer Selection below).

User Controlled Offer Selection

For full control over the DHCP offer selection process, register your own callback function using tfRegisterDhcpOfferCB(). You will be notified each time a DHCP offer is received and when the offer collection period has expired. Your callback function can call tfConfGetBootEntry() or tfDhcpUserGetBootEntry() to retrieve detailed information about the offer.

Your callback function must conform to the ttUserDhcpOfferCBFunc function prototype.

The following actions are available when you provide a callback function:

  • Accept the current offer and immediately advance to the requesting state. Return the value TM_DHCP_OFFER_SELECT when your callback function receives a TM_DHCP_EVENT_OFFER event.
  • Hold the current offer in cache while remaining in the selecting state. The application can choose to accept the offer later, if it does not receive a better one. To collect the offer, return the value TM_DHCP_OFFER_COLLECT when your callback function receives a TM_DHCP_EVENT_OFFER event. To select the offer later, call tfDhcpConfSetAttributes() or tfDhcpUserSetAttributes() with option TM_DHCP_ATTR_CACHE_SELECT. Note that you must remember the server id of the offer in order to select it later.
  • Ignore the current offer and remain in the selecting state. The offer will be purged from the cache. Return the value TM_DHCP_OFFER_IGNORE when your callback function receives a TM_DHCP_EVENT_OFFER event.
  • Select any offer that is in the cache. Call tfDhcpConfSetAttributes() or tfDhcpUserSetAttributes() with option TM_DHCP_ATTR_CACHE_SELECT.
  • Remove any offer from the cache to make room for subsequent offers. Call tfDhcpConfSetAttributes() or tfDhcpUserSetAttributes() with option TM_DHCP_ATTR_CACHE_DROP.

If you have not selected an offer by the end of the offer collection period, your callback function will be called with the TM_DHCP_EVENT_TIMEOUT event. Collection timeout occurs 15 seconds (by default) after the first offer is received and presented to your callback function. When you receive the TM_DHCP_EVENT_TIMEOUT event, you must select an offer that you have cached (returned TM_DHCP_OFFER_COLLECT) by calling tfDhcpConfSetAttributes() or tfDhcpUserSetAttributes() with option TM_DHCP_ATTR_CACHE_SELECT and the server id that identifies the offer. If you return from your callback function without selecting an offer, the DHCP session will fail with a timeout error.

You can select or drop an offer from the cache at any time by calling tfDhcpConfSetAttributes() or tfDhcpUserSetAttributes() with option TM_DHCP_ATTR_CACHE_SELECT or TM_DHCP_ATTR_CACHE_DROP. You do not have to wait until your callback function is invoked.

Callback registration is per interface. You may register a different callback function for each interface. The registered function services all multihomes on that interface. Only register a callback function for interfaces on which you wish to receive notification of DHCP offers.


Table of Contents >> Optional Protocols