nic.c

Go to the documentation of this file.
00001 /** @file nic.c
00002  *
00003  *  Network Interface Configurator (NIC) for libdhcp.
00004  *
00005  *  Provides facilities for configuring network interfaces, addresses,
00006  *  and routes.
00007  * 
00008  */
00009 /*
00010  * Copyright (C) 2006  Red Hat, Inc. All rights reserved.
00011  *
00012  * This copyrighted material is made available to anyone wishing to use,
00013  * modify, copy, or redistribute it subject to the terms and conditions of
00014  * the GNU General Public License v.2.  This program is distributed in the
00015  * hope that it will be useful, but WITHOUT ANY WARRANTY expressed or
00016  * implied, including the implied warranties of MERCHANTABILITY or FITNESS
00017  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
00018  * details.  You should have received a copy of the GNU General Public
00019  * License along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
00021  * USA. Any Red Hat trademarks that are incorporated in the source code or
00022  * documentation are not subject to the GNU General Public License and may
00023  * only be used or replicated with the express permission of Red Hat, Inc.
00024  *
00025  * Red Hat Author(s): Jason Vas Dias
00026  *                    David Cantrell
00027  */
00028 
00029 #define _GNU_SOURCE 1
00030 
00031 #include <sys/types.h>
00032 #include <unistd.h>
00033 #include <nic.h>
00034 #include <net/if.h>
00035 #include <net/if_arp.h>
00036 #include <arpa/inet.h>
00037 #include <sys/stat.h>
00038 #include <sys/syslog.h>
00039 #include <malloc.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <stdarg.h>
00043 #include <search.h>
00044 #include <time.h>
00045 #include <errno.h>
00046 
00047 #include <libdhcp.h>
00048 
00049 /* libnl Netlink API headers: */
00050 
00051 #include <netlink/netlink.h>
00052 #include <netlink/netlink-kernel.h>
00053 #include <netlink/rtnetlink-kernel.h>
00054 #include <netlink/msg.h>
00055 #include <netlink/attr.h>
00056 #include <netlink/utils.h>
00057 #include <netlink/addr.h>
00058 #include <netlink/route/rtnl.h>
00059 #include <netlink/route/link.h>
00060 #include <netlink/route/addr.h>
00061 #include <netlink/route/route.h>
00062 extern int nl_get_errno(void);
00063 
00064 #define eprintf(level, fmt, arg...) ({if (nh && nh->eh) (nh->eh)(nh, (level), (fmt), ##arg ); })
00065 
00066 /**
00067  * NIC library handle
00068  */
00069 struct nlh_s
00070 {
00071     struct nl_handle *nl;   /* netlink handle */
00072 
00073     void *nic_name_tree;    /* glibc search(3) btrees */
00074     void *nic_index_tree;
00075     void *nic_foreach_arg;  /* nic_foreach() callback arg */
00076 
00077     void *nic_addr_tree;
00078     void *nic_addr_foreach_arg;      
00079 
00080     void *nic_route_tree;
00081     void *nic_route_foreach_arg;
00082 
00083     int               ll;   /* log level      */    
00084     NIC_Error_Handler_t    eh;       /* error handler / logger */
00085     NIC_VA_Error_Handler_t va_eh;    /* underlying va_list logger (libdhcp) */
00086     void                  *va_eh_arg;/* va_list logger 1st argument */
00087 };
00088 
00089 NLH_t nic_open(NIC_Error_Handler_t eh)
00090 {
00091     NLH_t nh;
00092     
00093     if (!(nh = calloc(1, sizeof(struct nlh_s))))
00094         goto nic_open_fail;
00095     
00096     if (eh) {
00097         nh->ll = NIC_ERR;
00098         nh->eh = eh;
00099     }
00100     if (!(nh->nl = nl_handle_alloc())) {
00101         eprintf(NIC_FATAL, "cannot allocate NIC library handle: %m" );
00102         goto nic_open_fail;
00103     }
00104     
00105     if (nl_connect(nh->nl, NETLINK_ROUTE) < 0 ) {
00106         eprintf(NIC_FATAL, "cannot connect netlink socket: %m" );
00107         goto nic_open_fail;
00108     }
00109     
00110     return nh;
00111 
00112 nic_open_fail:
00113     if (nh) {
00114         if (nh->nl) {
00115             nl_handle_destroy(nh->nl);
00116             nh->nl = NULL;
00117         }
00118         free(nh);
00119     }
00120     return NULL;
00121 }
00122 
00123 static void tdestroy_nil(void *n) {}
00124 
00125 void nic_close(struct nlh_s **nhp)
00126 {
00127     struct nlh_s *nh;
00128 
00129     if (!nhp || !*nhp)
00130         return;
00131     nh = *nhp;
00132 
00133     if (nh->nl) {
00134         nl_close(nh->nl);       
00135         nl_handle_destroy(nh->nl);
00136         nh->nl = NULL;
00137     }
00138 
00139     if (nh->nic_name_tree) {
00140         tdestroy(nh->nic_name_tree, free);
00141         if (nh->nic_index_tree)
00142             tdestroy(nh->nic_index_tree, tdestroy_nil);
00143         nh->nic_name_tree = 0;
00144         nh->nic_index_tree = 0;
00145     } else if (nh->nic_index_tree) {
00146         tdestroy(nh->nic_index_tree, free);
00147         if (nh->nic_name_tree)
00148             tdestroy(nh->nic_name_tree, tdestroy_nil);
00149         nh->nic_name_tree = 0;
00150         nh->nic_index_tree = 0;
00151     }
00152     
00153     if (nh->nic_addr_tree) {
00154         tdestroy(nh->nic_addr_tree, nic_addr_free);
00155         nh->nic_addr_tree = 0;
00156     }
00157 
00158     if (nh->nic_route_tree)
00159     {
00160         tdestroy(nh->nic_route_tree, nic_route_free);
00161         nh->nic_route_tree = 0;
00162     }
00163     
00164     free(nh);
00165     *nhp = NULL;
00166 }
00167 
00168 
00169 /* default error handlers: */
00170 
00171 void nic_sys_logger( NLH_t nh, NIC_Error_Level_t el, char *fmt, ... )
00172 {
00173     if ( (nh == 0L) || ( el > nh->ll ) )
00174         return;
00175     va_list va;
00176     
00177     va_start(va, fmt);
00178     
00179     if( nh->va_eh )
00180         nh->va_eh ( nh->va_eh_arg, el, fmt, va );
00181     else 
00182         vsyslog( el, fmt, va );
00183 
00184     va_end(va);
00185 
00186     if ( el == LOG_FATAL )
00187         nic_close(&nh);
00188 }
00189 
00190 void nic_stderr_logger( NLH_t nh, NIC_Error_Level_t el, char *fmt, ... )
00191 {
00192     if ( (nh == 0L) || ( el > nh->ll ) )
00193         return;
00194 
00195     va_list va;
00196     
00197     va_start(va, fmt);
00198     if( nh->va_eh )
00199         nh->va_eh ( nh->va_eh_arg, el, fmt, va );
00200     else 
00201     {
00202         vfprintf(stderr, fmt, va);
00203         fprintf(stderr,"\n");
00204         fflush(stderr);
00205     }
00206     va_end(va);
00207 }
00208 
00209 NIC_Res_t nic_set_loglevel( NLH_t nh, NIC_Error_Level_t ll )
00210 {
00211     if ( nh == 0 )
00212         return NIC_FAIL;
00213 
00214     nh -> ll = ll;
00215     
00216     return NIC_OK;
00217 }
00218 
00219 extern
00220 void nic_set_logger(NLH_t nh, NIC_Error_Handler_t eh)
00221 {
00222     nh -> eh = eh;
00223 }
00224 
00225 extern
00226 void nic_set_va_logger(NLH_t nh, NIC_VA_Error_Handler_t va_eh, void *va_eh_arg)
00227 {
00228     nh -> va_eh = va_eh;
00229     nh -> eh = nic_stderr_logger;
00230 }
00231 
00232 #ifndef IFQDISCSIZ
00233 #define IFQDISCSIZ 32
00234 #endif
00235 
00236 struct nic_s
00237 {
00238     NLH_t             nh;      /**< nic handle */
00239 
00240     struct nic_link
00241     {
00242         struct nlmsghdr   hdr;
00243         struct ifinfomsg  ifi;
00244         /* 
00245          *struct ifinfomsg
00246          *{
00247          *
00248          *      unsigned char   ifi_family;
00249          *      unsigned char   __ifi_pad;
00250          *      unsigned short  ifi_type;
00251          *      int             ifi_index;
00252          *      unsigned        ifi_flags;
00253          *      unsigned        ifi_change;
00254          *};
00255          */
00256         
00257         ip_addr_t       addr;
00258 
00259         ip_addr_t       broadcast;
00260 
00261         char            name[IFNAMSIZ]; 
00262         char            qdisc[IFQDISCSIZ];      
00263         uint32_t        mtu;
00264         uint32_t        link;
00265         uint32_t        txqlen;
00266         uint32_t        weight;
00267         uint32_t        master;  
00268         uint32_t        cost;
00269         uint32_t        priority;
00270         uint32_t        protinfo;
00271         struct rtnl_link_stats stats;
00272         struct rtnl_link_ifmap ifmap;
00273 
00274         enum nic_mask_e
00275         {
00276             NIC_LINK_ADDRESS   =   1,
00277             NIC_LINK_BROADCAST =   2,
00278             NIC_LINK_NAME      =   4,
00279             NIC_LINK_MTU       =   8,
00280             NIC_LINK_LINK      =  16,
00281             NIC_LINK_QDISC     =  32,
00282             NIC_LINK_STATS     =  64,
00283             NIC_LINK_COST      = 128,
00284             NIC_LINK_PRIORITY  = 256,
00285             NIC_LINK_MASTER    = 512,
00286             NIC_LINK_WIRELESS  =1024, /**<unhandled for now */
00287             NIC_LINK_PROTINFO  =2048,
00288             NIC_LINK_TXQLEN    =4096,
00289             NIC_LINK_IFMAP     =8192,       
00290             NIC_LINK_WEIGHT    =16384,
00291             NIC_LINK_OPERSTATE =32768,
00292             NIC_LINK_LINKMODE  =65536
00293         } have, change;
00294     } l;
00295 };
00296 
00297 static struct nla_policy nic_link_policy[IFLA_MAX+1] = {
00298         [IFLA_IFNAME]   = { .type = NLA_STRING,
00299                             .maxlen = IFNAMSIZ },
00300         [IFLA_MTU]      = { .type = NLA_U32 },
00301         [IFLA_TXQLEN]   = { .type = NLA_U32 },
00302         [IFLA_LINK]     = { .type = NLA_U32 },
00303         [IFLA_WEIGHT]   = { .type = NLA_U32 },
00304         [IFLA_COST]     = { .type = NLA_U32 },
00305         [IFLA_PRIORITY] = { .type = NLA_U32 },
00306         [IFLA_PROTINFO] = { .type = NLA_U32 },
00307         [IFLA_MASTER]   = { .type = NLA_U32 },
00308         [IFLA_QDISC]    = { .type = NLA_STRING,
00309                             .maxlen = IFQDISCSIZ },
00310         [IFLA_STATS]    = { .minlen = sizeof(struct rtnl_link_stats) },
00311         [IFLA_MAP]      = { .minlen = sizeof(struct rtnl_link_ifmap) },
00312 };
00313 
00314 static int nic_name_comparator( const void *p1, const void *p2 )
00315 {
00316     const struct nic_s *n1 = p1, *n2 = p2;
00317     return strcmp(n1->l.name, n2->l.name);
00318 }
00319 
00320 static int nic_index_comparator( const void *p1, const void *p2 )
00321 {
00322     const struct nic_s *n1 = p1, *n2 = p2;
00323     return ( (n1->l.ifi.ifi_index == n2->l.ifi.ifi_index)
00324              ? 0
00325              : (n1->l.ifi.ifi_index > n2->l.ifi.ifi_index)
00326                ?  1
00327                : -1
00328            );
00329 }
00330 
00331 static int nic_get_links(NLH_t nh, char *if_name, int if_index)
00332 {
00333     struct nlmsghdr hdr, *rhdrs = NULL, *rhdr = NULL;
00334     struct sockaddr_nl addr = { AF_NETLINK, 0, 0, 0 };
00335     struct nl_msg *msg = NULL;
00336     int nlinks = 0;
00337     int rlen;
00338 
00339     errno = 0;
00340     memset(&hdr, '\0', sizeof (hdr));
00341 
00342     hdr.nlmsg_type = RTM_GETLINK;
00343 
00344     if ((if_name && *if_name) || if_index != -1)
00345         hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ATOMIC;
00346     else
00347         hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
00348 
00349     if (!(msg = nlmsg_build(&hdr))) {
00350         eprintf(NIC_FATAL, "nic_get_links: %m");
00351         return -1;
00352     }
00353 
00354     if (if_name && *if_name) {
00355         eprintf(NIC_DEBUG, "looking for name %s\n", if_name);
00356         NLA_PUT_STRING(msg, IFLA_IFNAME, if_name);
00357     }
00358 
00359     if( if_index != -1 ) {
00360         struct ifinfomsg info;
00361         memset(&info, '\0', sizeof (info));
00362 
00363         eprintf(NIC_DEBUG, "looking for index %d\n", if_index);
00364         info.ifi_index = if_index;
00365 
00366         if (nlmsg_append(msg, &info, sizeof (info), 1) < 0) {
00367             eprintf(NIC_FATAL, "nic_get_links: %m\n");
00368             return -1;
00369         }
00370     }
00371 
00372     if (nl_send_auto_complete(nh->nl, nlmsg_hdr(msg)) < 0) {
00373         eprintf(NIC_FATAL, "nic_get_links: %m\n");
00374         return -1;
00375     }
00376 
00377     rlen = 1;
00378     while (rlen > 0) {
00379         rhdrs = NULL;
00380         if ((rlen = nl_recv(nh->nl, &addr, (void *)&rhdrs)) <= 0)
00381             break;
00382 
00383         if (rlen < sizeof (*rhdr) + sizeof (struct ifinfomsg)) {
00384             nlmsg_free(msg);
00385             return nlinks;
00386         }
00387 
00388         rhdr = rhdrs;
00389         while (nlmsg_ok(rhdr, rlen)) {
00390             struct nl_attr *tb[__IFLA_MAX];
00391             struct nic_s *nic = NULL, **nnic = NULL, **inic = NULL;
00392             int rc;
00393     
00394             memset(tb, '\0', sizeof (tb));
00395             if (rhdr->nlmsg_type == NLMSG_DONE)
00396                 break;
00397             if (rhdr->nlmsg_type != RTM_NEWLINK) {
00398                 rhdr = nlmsg_next(rhdr, &rlen);
00399                 continue;
00400             }
00401     
00402             if (!(nic = calloc(1, sizeof (*nic)))) {
00403                 eprintf(NIC_ERR, "nic_get_links: %m");
00404                 free(rhdrs);
00405                 rhdr = NULL;
00406                 nlmsg_free(msg);
00407                 return nlinks;
00408             }
00409             nic->nh = nh;
00410     
00411             if ((rc = nlmsg_parse(rhdr, sizeof (struct ifinfomsg), (void *)tb, IFLA_MAX, nic_link_policy)) < 0) {
00412                 eprintf(NIC_ERR, "nic_get_links: nl_parse_failed: %s", nl_geterror());
00413                 free(nic);
00414                 free(rhdrs);
00415                 rhdr = NULL;
00416                 nlmsg_free(msg);
00417                 return nlinks;
00418             }
00419     
00420             nic->l.ifi = *(struct ifinfomsg *)nlmsg_data(rhdr);
00421             if (nic->l.ifi.ifi_index != -1)
00422                 eprintf(NIC_DEBUG, "found index %d\n", nic->l.ifi.ifi_index);
00423     
00424             if (tb[IFLA_IFNAME]) {
00425                 int len = nla_len((void *)tb[IFLA_IFNAME]);
00426                 char *nambuf;
00427     
00428                 nambuf = alloca(len + 1);
00429                 memcpy(nambuf, nla_data((void *)tb[IFLA_IFNAME]), len);
00430                 nambuf[len] = '\0';
00431                 eprintf(NIC_DEBUG, "got name: %s", nambuf);
00432     
00433                 strncpy(nic->l.name, nla_data((void *)tb[IFLA_IFNAME]), len);
00434                 nic->l.name[len] = '\0';
00435                 nic->l.have |= NIC_LINK_NAME;
00436                 eprintf(NIC_DEBUG, " %s\n", nic->l.name);
00437             } else {
00438                 eprintf(NIC_DEBUG, "didn't get name\n");
00439             }
00440     
00441             if (tb[IFLA_TXQLEN]) {
00442                 nic->l.txqlen = nla_get_u32((void*)tb[IFLA_TXQLEN]);
00443                 nic->l.have |= NIC_LINK_TXQLEN;
00444             }
00445 
00446             if (tb[IFLA_MTU]) {
00447                 nic->l.mtu = nla_get_u32((void*)tb[IFLA_MTU]);
00448                 nic->l.have |= NIC_LINK_MTU;
00449             }
00450 
00451 
00452             if (tb[IFLA_ADDRESS]) {
00453                 nic->l.addr = ip_addr_binary(
00454                         nla_data((void*)tb[IFLA_ADDRESS]), 
00455                         nla_len((void*)tb[IFLA_ADDRESS]));
00456                 nic->l.have |= NIC_LINK_ADDRESS;
00457             }
00458 
00459             if (tb[IFLA_BROADCAST]) {
00460                 nic->l.broadcast = ip_addr_binary(
00461                         nla_data((void*)tb[IFLA_BROADCAST]), 
00462                         nla_len((void*)tb[IFLA_BROADCAST]));
00463                 nic->l.have |= NIC_LINK_BROADCAST;
00464             }
00465 
00466             if (tb[IFLA_LINK]) {
00467                 nic->l.link = nla_get_u32((void*)tb[IFLA_LINK]);
00468                 nic->l.have |= NIC_LINK_LINK;
00469             }
00470 
00471             if (tb[IFLA_WEIGHT]) {
00472                 nic->l.weight = nla_get_u32((void*)tb[IFLA_WEIGHT]);
00473                 nic->l.have |= NIC_LINK_WEIGHT;
00474             }
00475 
00476             if (tb[IFLA_MASTER]) {
00477                 nic->l.master = nla_get_u32((void*)tb[IFLA_MASTER]);
00478                     nic->l.have |= NIC_LINK_MASTER;
00479             }
00480 
00481             if (tb[IFLA_COST]) {
00482                 nic->l.cost = nla_get_u32((void*)tb[IFLA_COST]);
00483                 nic->l.have |= NIC_LINK_COST;
00484             }
00485 
00486             if (tb[IFLA_PRIORITY]) {
00487                 nic->l.priority = nla_get_u32((void*)tb[IFLA_PRIORITY]);
00488                 nic->l.have |= NIC_LINK_PRIORITY;
00489             }
00490 
00491             if (tb[IFLA_PROTINFO]) {
00492                 nic->l.priority = nla_get_u32((void*)tb[IFLA_PROTINFO]);
00493                 nic->l.have |= NIC_LINK_PROTINFO;
00494             }
00495 
00496             if (tb[IFLA_QDISC]) {
00497                 memcpy(&(nic->l.qdisc[0]), nla_data((void*)tb[IFLA_QDISC]), nla_len((void*)tb[IFLA_QDISC]));
00498                 nic->l.have |= NIC_LINK_QDISC;
00499                 nic->l.have |= NIC_LINK_QDISC;
00500             }
00501 
00502             if (tb[IFLA_STATS]) {
00503                 memcpy( &(nic->l.stats), nla_data((void*)tb[IFLA_STATS]), sizeof(struct rtnl_link_stats));
00504                 nic->l.have |= NIC_LINK_STATS;
00505             }
00506  
00507             if (tb[IFLA_MAP]) {
00508                 memcpy( &(nic->l.ifmap), nla_data((void*)tb[IFLA_MAP]), sizeof(struct rtnl_link_ifmap));
00509                 nic->l.have |= NIC_LINK_IFMAP;
00510             }
00511 
00512             nnic = tfind(nic, &nh->nic_name_tree, nic_name_comparator);
00513             if (!nnic) {
00514                 if (!(nnic = tsearch(nic, &(nh->nic_name_tree), nic_name_comparator))) {
00515                     free(nic);
00516                     free(rhdrs);
00517                     rhdr = NULL;
00518                     goto return_nlinks;
00519                 }
00520                 if (!(inic = tsearch(nic, &(nh->nic_index_tree), nic_index_comparator))) {
00521                     free(nic);
00522                     free(rhdrs);
00523                     rhdr = NULL;
00524                     goto return_nlinks;
00525                 }
00526             }
00527             if (nic != *nnic) {
00528                 free(nic);
00529                 nic = *nnic;
00530             } 
00531             nlinks++;
00532 
00533             if ((if_index != -1 && nic->l.ifi.ifi_index == if_index) ||
00534                     (if_name && !strcmp(nic->l.name, if_name))) {
00535                 free(rhdrs);
00536                 rhdr = NULL;
00537                 goto return_nlinks;
00538             }
00539             rhdr = nlmsg_next(rhdr, &rlen);
00540         }
00541     }
00542     if (rlen < 0)
00543         eprintf(NIC_ERR, "rlen: %d\n", rlen);
00544 
00545 nla_put_failure:
00546     nlmsg_free(msg);
00547     return -1;
00548  
00549 return_nlinks:
00550     nlmsg_free(msg);
00551     return nlinks;
00552 
00553 }
00554 
00555 NIC_t nic_by_name(NLH_t nh, char *if_name)
00556 {    
00557     struct nic_s snic, *nic=0, **pnic=0;
00558 
00559     if (!nh->nic_name_tree)
00560         nic_get_links(nh, "", -1);
00561 
00562     if( (if_name == 0L) || ( *if_name == '\0' ) )
00563     {
00564         eprintf(NIC_FATAL, "nic_by_name: invalid nil argument" );
00565         return( 0L );   
00566     }
00567    
00568     strncpy(&(snic.l.name[0]),if_name, IFNAMSIZ);
00569 
00570     if ( (pnic = tfind(&snic, &(nh->nic_name_tree), nic_name_comparator)) != 0L )
00571         return *pnic;
00572 
00573     if( ( nic_get_links(nh, if_name, -1) <= 0 ) 
00574       ||((pnic = tfind(&snic, &(nh->nic_name_tree), nic_name_comparator)) == 0L)
00575       )
00576     {
00577         eprintf(NIC_ERR, "nic_by_name: no interface named %s found", if_name );
00578         return(0L);
00579     }else
00580         nic = *pnic;
00581     
00582     return nic;
00583 }
00584 
00585 NIC_t nic_by_index(NLH_t nh, int16_t if_index)
00586 {    
00587     struct nic_s snic, *nic=0, **pnic=0;
00588 
00589     /* nic_index_tree will be populated at the same time */
00590     if (!nh->nic_name_tree)
00591         nic_get_links(nh, "", -1);
00592 
00593     if( if_index == -1 )
00594     {
00595         eprintf(NIC_FATAL, "nic_by_index: invalid -1 argument" );
00596         return( 0L );   
00597     }
00598    
00599     snic.l.ifi.ifi_index = if_index;
00600 
00601     if ( (pnic = tfind(&snic, &(nh->nic_index_tree), nic_index_comparator)) != 0L )
00602         return *pnic;
00603 
00604 
00605     if( ( nic_get_links(nh, "", if_index ) <= 0 ) 
00606       ||((pnic = tfind(&snic, &(nh->nic_index_tree), nic_index_comparator)) == 0L)
00607       )
00608     {
00609         eprintf(NIC_ERR, "nic_by_index: no interface with index %d found", if_index );
00610         return(0L);
00611     }else
00612         nic = *pnic;
00613     
00614     return nic;
00615 }
00616 
00617 struct nic_cbarg
00618 {
00619     NIC_handler_t cb;
00620     void        *arg;
00621 };
00622 
00623 static void nic_twalker( const void *p, const VISIT which, const int depth )
00624 {
00625     struct nic_s *nic, *const*npp=p;
00626     struct nic_cbarg *cb;
00627 
00628     if( (npp == 0L)    || ((nic = *npp) == 0L)
00629       ||(nic->nh == 0) || (nic->nh->nic_foreach_arg == 0 )
00630       ||( (which != postorder) && (which != leaf) )
00631       ) return;
00632 
00633     cb = nic->nh->nic_foreach_arg;
00634  
00635     cb->cb( nic->nh, nic, cb->arg );       
00636 }
00637 
00638 void nic_foreach(NLH_t nh, NIC_handler_t handler,  void *arg)
00639 {
00640     struct nic_cbarg cb = { handler, arg };
00641     struct nic_s snic;
00642 
00643     if ( nh->nic_foreach_arg )
00644         return;
00645 
00646     nh->nic_foreach_arg = &cb;
00647     memset(&snic, '\0', sizeof(struct nic_s));
00648     snic.l.ifi.ifi_index = -1;
00649     snic.nh = nh;
00650 
00651     /* Ensure we have ALL current links in the tree */
00652     nic_get_links(nh, "", -1 ) ;
00653 
00654     if( nh->nic_name_tree )
00655         twalk( nh->nic_name_tree, nic_twalker);
00656 
00657     nh->nic_foreach_arg = 0L;
00658 }
00659 
00660 char* nic_get_name( NIC_t nic )
00661 {
00662     if( nic == 0 ) return 0;
00663         
00664     return &(nic->l.name[0]);
00665 }
00666 
00667 int16_t nic_get_index( NIC_t nic )
00668 {
00669     if ( nic == 0 ) return -1;
00670 
00671     return nic->l.ifi.ifi_index ;
00672 }
00673 
00674 ip_addr_t nic_get_link_addr(NIC_t nic)
00675 {
00676     ip_addr_t ip;
00677     memset(&ip, '\0', sizeof(ip));
00678     if( nic == 0L )
00679         return ip;
00680     return nic->l.addr;
00681 }
00682 
00683 ip_addr_t nic_get_link_broadcast(NIC_t nic)
00684 {
00685     ip_addr_t ip;
00686     memset(&ip, '\0', sizeof(ip));
00687     if( nic == 0L )
00688         return ip;
00689     return nic->l.broadcast;
00690 }
00691 
00692 uint32_t nic_get_flags( NIC_t nic )
00693 {
00694     if(nic == 0L)
00695         return 0;
00696     return nic->l.ifi.ifi_flags;
00697 }
00698 
00699 NIC_Res_t nic_update( NIC_t nic )
00700 {
00701     NLH_t nh;
00702     if( nic == 0L )
00703         return NIC_FAIL;
00704 
00705     nh = nic->nh;
00706 
00707     memset(&nic->l.hdr, '\0', sizeof(struct nlmsghdr));
00708 
00709     nic->l.hdr.nlmsg_type = RTM_SETLINK;
00710     nic->l.hdr.nlmsg_flags = NLM_F_REPLACE | NLM_F_REQUEST | NLM_F_ACK | NLM_F_MATCH | NLM_F_ATOMIC;
00711 
00712     struct nl_msg *msg = nlmsg_build(&(nic->l.hdr));
00713 
00714     if ( msg == 0L ) {
00715         eprintf(NIC_ERR, "nic_link_update (%s): nlmsg_build failed - %d %s" ,
00716                 nic->l.name, nl_get_errno(), nl_geterror());
00717         return NIC_FAIL;
00718     }
00719 
00720     nlmsg_append( msg, &(nic->l.ifi), sizeof( struct ifinfomsg ), 1);
00721 
00722     if(  nic->l.have & NIC_LINK_NAME )
00723         NLA_PUT_STRING(msg, IFLA_IFNAME, &(nic->l.name[0]));
00724 
00725     if(  nic->l.change & NIC_LINK_QDISC )
00726         NLA_PUT_STRING(msg, IFLA_QDISC, &(nic->l.qdisc[0]));
00727 
00728     if(  nic->l.have & NIC_LINK_LINK )
00729         NLA_PUT_U32(msg, IFLA_LINK, nic->l.link );
00730     
00731     if(  nic->l.change & NIC_LINK_MTU )
00732         NLA_PUT_U32(msg, IFLA_MTU, nic->l.mtu);
00733 
00734     if(  nic->l.change & NIC_LINK_TXQLEN )
00735         NLA_PUT_U32(msg, IFLA_TXQLEN, nic->l.txqlen);
00736 
00737     if(  nic->l.change & NIC_LINK_WEIGHT )
00738         NLA_PUT_U32(msg, IFLA_WEIGHT, nic->l.weight);
00739 
00740     if(  nic->l.change & NIC_LINK_COST )
00741         NLA_PUT_U32(msg, IFLA_COST, nic->l.cost);
00742 
00743     if(  nic->l.change & NIC_LINK_PRIORITY )
00744         NLA_PUT_U32(msg, IFLA_PRIORITY, nic->l.priority);
00745    
00746     if(  nic->l.change & NIC_LINK_PROTINFO )
00747         NLA_PUT_U32(msg, IFLA_PROTINFO, nic->l.protinfo);
00748 
00749     if( nl_send_auto_complete(nic->nh->nl, nlmsg_hdr(msg)) < 0 )
00750     {
00751         eprintf(NIC_ERR,"nic_update_link: send failed - %d %s",
00752                 nl_get_errno(), nl_geterror());
00753         return NIC_FAIL;
00754     }
00755 
00756     nlmsg_free(msg);
00757 
00758     if( nl_wait_for_ack(nic->nh->nl) < 0 )
00759     {
00760         eprintf(NIC_ERR,"nic_update_link failed - %d: %s",
00761                 nl_get_errno(), nl_geterror());
00762         return NIC_FAIL;        
00763     }
00764     
00765     return NIC_OK;
00766 
00767 nla_put_failure:
00768 
00769     eprintf(NIC_ERR, "nic_update_link append attr failed - out of memory?");
00770 
00771     nlmsg_free(msg);
00772 
00773     return NIC_FAIL;    
00774 }
00775 
00776 void nic_set_flags( NIC_t nic, uint32_t flags )
00777 {
00778     if(nic == 0L) return;
00779         
00780     nic->l.ifi.ifi_flags = flags;
00781 }
00782 
00783 uint32_t nic_get_mtu( NIC_t nic )
00784 {
00785     if((nic == 0L) || ((nic->l.have & NIC_LINK_MTU)==0))
00786         return 0;
00787     return nic->l.mtu;
00788 }
00789 
00790 void nic_set_mtu( NIC_t nic, uint32_t mtu )
00791 {
00792     if( nic == 0 ) return ;
00793     nic->l.mtu = mtu;
00794     nic->l.change |= NIC_LINK_MTU;
00795 }
00796 
00797 char *nic_get_qdisc( NIC_t nic )
00798 {
00799     if((nic == 0) || ((nic->l.have & NIC_LINK_QDISC)==0))
00800         return 0;
00801     return &(nic->l.qdisc[0]);    
00802 }
00803 
00804 extern
00805 void nic_set_qdisc( NIC_t nic, char *qdisc )
00806 {
00807     if(nic == 0) return ;
00808     strncpy(&(nic->l.qdisc[0]), qdisc, IFQDISCSIZ);
00809     nic->l.change |= NIC_LINK_QDISC;
00810 }
00811 
00812 uint32_t nic_get_txqlen( NIC_t nic )
00813 {
00814     if((nic == 0L) || ((nic->l.have & NIC_LINK_TXQLEN)==0))
00815         return 0;
00816     return nic->l.txqlen;
00817 }
00818 
00819 void nic_set_txqlen( NIC_t nic, uint32_t txq )
00820 {
00821     if(nic == 0L) return;
00822     nic->l.txqlen = txq;
00823     nic->l.change |= NIC_LINK_TXQLEN;
00824 }
00825 
00826 uint32_t nic_get_link( NIC_t nic )
00827 {
00828     if((nic == 0L) || ((nic->l.have & NIC_LINK_LINK)==0))
00829         return 0;
00830     return nic->l.link;
00831 }
00832 
00833 void nic_set_link( NIC_t nic, uint32_t link )
00834 {
00835     if( nic == 0L) return;
00836     nic->l.link = link;
00837     nic->l.change |= NIC_LINK_LINK;
00838 }
00839 
00840 uint32_t nic_get_weight( NIC_t nic )
00841 {
00842     if((nic == 0L) || ((nic->l.have & NIC_LINK_WEIGHT)==0))
00843         return 0;
00844     return nic->l.weight;
00845 }
00846 
00847 void nic_set_weight( NIC_t nic, uint32_t weight )
00848 {
00849     if( nic == 0L) return;
00850     nic->l.weight = weight;
00851     nic->l.change |= NIC_LINK_WEIGHT;
00852 }
00853 
00854 uint32_t nic_get_master( NIC_t nic )
00855 {
00856     if((nic == 0L) || ((nic->l.have & NIC_LINK_MASTER)==0))
00857         return 0;
00858     return nic->l.master;
00859 }
00860 
00861 void nic_set_master( NIC_t nic, uint32_t master )
00862 {
00863     if( nic == 0L) return;
00864     nic->l.master = master;
00865     nic->l.change |= NIC_LINK_MASTER;
00866 }
00867 
00868 uint32_t nic_get_cost( NIC_t nic )
00869 {
00870     if((nic == 0L) || ((nic->l.have & NIC_LINK_COST)==0))
00871         return 0;
00872     return nic->l.cost;
00873 }
00874 
00875 void nic_set_cost( NIC_t nic, uint32_t cost )
00876 {
00877     if( nic == 0L) return;
00878     nic->l.cost = cost;
00879     nic->l.change |= NIC_LINK_COST;
00880 }
00881 
00882 uint32_t nic_get_priority( NIC_t nic )
00883 {
00884     if((nic == 0L) || ((nic->l.have & NIC_LINK_PRIORITY)==0))
00885         return 0;
00886     return nic->l.priority;
00887 }
00888 
00889 void nic_set_priority( NIC_t nic, uint32_t priority )
00890 {
00891     if( nic == 0L) return;
00892     nic->l.priority = priority;
00893     nic->l.change |= NIC_LINK_PRIORITY;
00894 }
00895 
00896 uint32_t nic_get_protinfo( NIC_t nic )
00897 {
00898     if((nic == 0L) || ((nic->l.have & NIC_LINK_PROTINFO)==0))
00899         return 0;
00900     return nic->l.protinfo;
00901 }
00902 
00903 void nic_set_protinfo( NIC_t nic, uint32_t protinfo )
00904 {
00905     if( nic == 0L) return;
00906     nic->l.protinfo = protinfo;
00907     nic->l.change |= NIC_LINK_PROTINFO;
00908 }
00909 
00910 struct rtnl_link_stats nic_get_stats(NIC_t nic)
00911 {
00912     struct rtnl_link_stats st;
00913     memset(&st, '\0', sizeof(struct rtnl_link_stats));
00914     if((nic == 0L) || ((nic->l.have & NIC_LINK_STATS)==0))
00915         return st;    
00916     return nic->l.stats;
00917 }
00918 
00919 struct rtnl_link_ifmap nic_get_ifmap(NIC_t nic)
00920 {
00921     struct rtnl_link_ifmap ifm;
00922     memset(&ifm, '\0', sizeof(struct rtnl_link_ifmap));
00923     if((nic == 0L) || ((nic->l.have & NIC_LINK_IFMAP)==0))
00924         return ifm;    
00925     return nic->l.ifmap;
00926 }
00927 
00928 struct nic_ip_address_s 
00929 {
00930     NLH_t nh;
00931     
00932 
00933     struct nic_addr_s
00934     {
00935         struct nlmsghdr   hdr;
00936         struct ifaddrmsg  ifa;
00937         /*
00938          *struct ifaddrmsg
00939          *{
00940          *   unsigned char      ifa_family;
00941          *   unsigned char      ifa_prefixlen;
00942          *   unsigned char      ifa_flags;
00943          *   unsigned char      ifa_scope;
00944          *   int                ifa_index;
00945          *};
00946          */
00947         uint32_t   index;
00948         uint32_t   flags;
00949         ip_addr_t  addr;
00950         ip_addr_t  broadcast;
00951         ip_addr_t  anycast;
00952         ip_addr_t  multicast;
00953         ip_addr_t  local;
00954         struct ifa_cacheinfo cacheinfo;
00955         char       label [ IFNAMSIZ ];
00956 
00957         enum ifa_e
00958         {           
00959             NIC_ADDR_ADDRESS   =   1,
00960             NIC_ADDR_LOCAL     =   2,
00961             NIC_ADDR_LABEL     =   4,
00962             NIC_ADDR_BROADCAST =   8,
00963             NIC_ADDR_ANYCAST   =  16,
00964             NIC_ADDR_CACHEINFO =  32,
00965             NIC_ADDR_MULTICAST =  64
00966         } have, change;
00967         
00968     } nla;    
00969 };
00970 
00971 static struct nla_policy nic_addr_policy[IFA_MAX+1] = {
00972         [IFA_LABEL]     = { .type = NLA_STRING,
00973                             .maxlen = IFNAMSIZ },
00974         [IFA_CACHEINFO] = { .minlen = sizeof(struct ifa_cacheinfo) },
00975 };
00976 
00977 static int nic_addr_comparator( const void *p1, const void *p2 )
00978 {
00979     const struct nic_ip_address_s  *ipa1=p1, *ipa2=p2;
00980 
00981     if( ipa1->nla.ifa.ifa_index > ipa2->nla.ifa.ifa_index )
00982         return 1;
00983     else
00984     if( ipa1->nla.ifa.ifa_index < ipa2->nla.ifa.ifa_index )
00985         return -1;
00986 
00987     uint8_t 
00988         pfx1 = ipa1->nla.ifa.ifa_prefixlen,
00989         pfx2 = ipa2->nla.ifa.ifa_prefixlen;
00990 
00991     const ip_addr_t *ip1=0, *ip2=0;
00992     
00993     if( ipa1->nla.have & NIC_ADDR_ADDRESS )
00994         ip1 = &(ipa1->nla.addr);
00995     else
00996     if( ipa1->nla.have & NIC_ADDR_LOCAL )
00997     {
00998         ip1 = &(ipa1->nla.local);
00999         pfx1 = IP_ADDR_SIZE(ip1) * 8;
01000     }
01001 
01002     if( ipa2->nla.have & NIC_ADDR_ADDRESS )
01003         ip2 = &(ipa2->nla.addr);
01004     else
01005     if( ipa2->nla.have & NIC_ADDR_LOCAL )
01006     {
01007         ip2 = &(ipa2->nla.local);
01008         pfx2= IP_ADDR_SIZE(ip2) * 8;
01009     }
01010 
01011     if( ip1 == 0 )
01012         return -1;
01013     
01014     if( ip2 == 0 )
01015         return 1;
01016 
01017     uint8_t
01018         alen1 = IP_ADDR_SIZE(ip1),
01019         alen2 = IP_ADDR_SIZE(ip2);
01020     
01021     if( alen1 > alen2 )
01022         return 1;
01023     else
01024     if( alen1 < alen2 )
01025         return -1;
01026 
01027     if( pfx1 > pfx2 )
01028         return 1;
01029     else
01030     if( pfx1 < pfx2 )
01031         return -1;
01032 
01033     const uint8_t
01034         *ap1 = IP_ADDR(ip1),
01035         *ap2 = IP_ADDR(ip2);
01036 
01037     for(; alen1 && pfx1; alen1--, pfx1-=8, ap1++, ap2++ )
01038     {
01039         const uint8_t 
01040             v1=*ap1,
01041             v2=*ap2;
01042 
01043         if( pfx1 < 8 )
01044         {
01045             const uint8_t 
01046                 vb1 = v1 & ((1 << pfx1)-1),
01047                 vb2 = v2 & ((1 << pfx1)-1);
01048             return
01049                 ( vb1 > vb2 )
01050                 ? 1
01051                 : ( vb1 < vb2 )
01052                   ? -1
01053                   : 0;
01054         }else
01055         {
01056             if( v1 > v2 )
01057                 return 1;
01058             if( v1 < v2 )
01059                 return -1;
01060         }
01061     }
01062     return 0;
01063 }
01064 
01065 static int nic_get_addresses(NLH_t nh, IPaddr_t ipa)
01066 {
01067     char abuf[32];
01068     struct nic_ip_address_s ipaf, *addr;
01069 
01070     if(nh == 0)
01071         return 0;
01072     
01073     int n_addrs = 0;
01074     struct nic_addr_s *nla;    
01075 
01076     if( ipa )
01077     {
01078         ipaf = *ipa;
01079         addr = ipa;
01080         nla = &(ipa->nla);    
01081         memset(&(nla->hdr),'\0',sizeof(struct nlmsghdr));
01082         nla->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ATOMIC | NLM_F_MATCH;
01083     }else
01084     {
01085         memset(&ipaf, '\0', sizeof(struct nic_ip_address_s));
01086         ipaf.nh = nh;
01087         addr = &ipaf;
01088         nla = &(ipaf.nla);    
01089         addr=&ipaf;     
01090         nla->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
01091     }
01092     
01093     nla->hdr.nlmsg_type = RTM_GETADDR;
01094     
01095     struct nl_msg *msg = nlmsg_build(&(nla->hdr));
01096 
01097     if( msg == 0L )
01098     {
01099         eprintf(NIC_ERR, "nic_get_addresses: out of memory" );
01100         return n_addrs;
01101     }
01102     
01103     if( nlmsg_append(msg, &(nla->ifa), sizeof(struct ifaddrmsg), 1) < 0 )
01104     {   
01105         eprintf(NIC_ERR,"nic_get_addresses: nlmsg_append failed: %d %s\n", 
01106                 nl_get_errno(), nl_geterror());
01107         goto nla_put_failure;
01108     }
01109 
01110     if( addr->nla.addr.sa_family )
01111         NLA_PUT(msg, IFLA_ADDRESS, 
01112                 IP_ADDR_SIZE(&(addr->nla.addr)), 
01113                 IP_ADDR(&(addr->nla.addr))
01114                );
01115 
01116     if ( nl_send_auto_complete( nh->nl, nlmsg_hdr(msg) ) < 0 )
01117     {
01118         eprintf(NIC_ERR,"nic_get_addresses: send failed: %d %s\n", 
01119                 nl_get_errno(), nl_geterror());
01120         goto nla_put_failure;
01121     }
01122 
01123     struct nic_addr_s *buf = 0;
01124 
01125     if( buf == 0L )
01126     {
01127         eprintf(NIC_ERR,"nic_get_addresses: out of memory.");
01128         goto nla_put_failure;
01129     }
01130 
01131     struct nlmsghdr *hdr = (struct nlmsghdr *)buf;
01132     struct sockaddr_nl kernel;
01133     int rlen = 0;
01134     int remaining = 0;
01135     
01136     do
01137     {
01138         if ( (rlen = nl_recv( nh->nl, &kernel, (void*)&buf)) > 0 )
01139         {
01140             if( rlen < (sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg)) )
01141                 goto nla_return;
01142 
01143             hdr = (struct nlmsghdr*)buf;
01144             remaining = rlen;
01145 
01146             if( hdr->nlmsg_type != RTM_NEWADDR )
01147                 goto nla_return;
01148             
01149             do
01150             {
01151                 memset(nla, '\0', sizeof(struct nic_addr_s));
01152                 
01153                 memcpy(nla, hdr, sizeof(struct nlmsghdr));
01154                 
01155                 struct nl_attr *tb[__IFA_MAX];
01156                 
01157                 int i;
01158                 for (i=0; i < __IFA_MAX; i++) tb[i]=0;
01159                 int err = 
01160                     nlmsg_parse((struct nlmsghdr*)hdr, sizeof(struct ifaddrmsg),
01161                                 (void*)tb, IFA_MAX, nic_addr_policy);
01162                 if( err < 0 )
01163                 {
01164                     eprintf(NIC_ERR,"nic_get_addresses: nl_parse failed: %d %s",
01165                             err, nl_geterror());
01166                     goto nla_return;
01167                 }
01168                 
01169                 nla->ifa = *((struct ifaddrmsg*)nlmsg_data((struct nlmsghdr*)hdr));
01170                 
01171                 if( tb[ IFA_ADDRESS ] )
01172                 {
01173                     nla->addr = 
01174                         ip_addr_binary 
01175                         ( nla_data((void*)tb[IFA_ADDRESS]),
01176                           nla_len((void*)tb[IFA_ADDRESS])
01177                         );      
01178 
01179                     eprintf(NIC_DEBUG,"nic %d address: %s/%hd",
01180                             nla->ifa.ifa_index,
01181                             ip_text_addr(&nla->addr, abuf, 32),
01182                             nla->ifa.ifa_prefixlen);
01183                     nla->have |= NIC_ADDR_ADDRESS;
01184                 }
01185 
01186                 if( tb[ IFA_LOCAL ] )
01187                 {
01188                     nla->local = 
01189                         ip_addr_binary 
01190                         ( nla_data((void*)tb[IFA_ADDRESS]),
01191                           nla_len((void*)tb[IFA_ADDRESS])
01192                         );      
01193                     eprintf(NIC_DEBUG,"nic %d local (PtP) address: %s",
01194                             nla->ifa.ifa_index,
01195                             ip_text_addr(&nla->local, abuf, 32));
01196                     nla->have |= NIC_ADDR_LOCAL;
01197                 }
01198 
01199                 if( tb[ IFA_BROADCAST ] )
01200                 {
01201                     nla->broadcast = 
01202                         ip_addr_binary 
01203                         ( nla_data((void*)tb[IFA_BROADCAST]),
01204                           nla_len((void*)tb[IFA_BROADCAST])
01205                         );      
01206                     eprintf(NIC_DEBUG,"nic %d broadcast address: %s",
01207                             nla->ifa.ifa_index,
01208                             ip_text_addr(&nla->broadcast, abuf, 32));
01209                     nla->have |= NIC_ADDR_BROADCAST;
01210                 }
01211 
01212                 if( tb[ IFA_ANYCAST ] )
01213                 {
01214                     nla->anycast = 
01215                         ip_addr_binary 
01216                         ( nla_data((void*)tb[IFA_ANYCAST]),
01217                           nla_len((void*)tb[IFA_ANYCAST])
01218                         );      
01219                     eprintf(NIC_DEBUG,"nic %d anycast address: %s",
01220                             nla->ifa.ifa_index,
01221                             ip_text_addr(&nla->anycast, abuf, 32));
01222                     nla->have |= NIC_ADDR_ANYCAST;
01223                 }
01224                 
01225                 if( tb[ IFA_MULTICAST ] )
01226                 {
01227                     nla->multicast = 
01228                         ip_addr_binary 
01229                         ( nla_data((void*)tb[IFA_MULTICAST]),
01230                           nla_len((void*)tb[IFA_MULTICAST])
01231                         );      
01232                     eprintf(NIC_DEBUG,"nic %d multicast address: %s",
01233                             nla->ifa.ifa_index,
01234                             ip_text_addr(&nla->multicast, abuf, 32));
01235                     nla->have |= NIC_ADDR_MULTICAST;
01236                 }
01237 
01238                 if( tb[IFA_CACHEINFO] )
01239                 {
01240                     memcpy
01241                         ( &(nla->cacheinfo), 
01242                           nla_data((void*)tb[IFA_CACHEINFO]),
01243                           sizeof(struct ifa_cacheinfo)
01244                         );
01245                     eprintf(NIC_DEBUG,"nic %d have cacheinfo", 
01246                             nla->ifa.ifa_index);
01247                     nla->have |= NIC_ADDR_CACHEINFO;
01248                 }
01249 
01250                 if( tb[IFA_LABEL] )
01251                 {
01252                     strncpy
01253                         ( &(nla->label[0]), 
01254                           nla_data((void*)tb[IFA_LABEL]), 
01255                           nla_len((void*)tb[IFA_LABEL])
01256                         );
01257                     eprintf(NIC_DEBUG,"nic %d addr label: %s", 
01258                             nla->ifa.ifa_index, nla->label);
01259                     nla->have |= NIC_ADDR_LABEL;
01260                 }
01261                 
01262                 n_addrs++;
01263                 
01264                 struct nic_ip_address_s **paddr, *taddr=0L, *naddr = 0L;
01265 
01266                 if( ipa == 0 )
01267                 {
01268                     naddr = calloc(1, sizeof(struct nic_ip_address_s));
01269                     if( naddr == 0L )
01270                     {
01271                         eprintf(NIC_ERR, "nic_get_addresses: out of memory.");
01272                         goto nla_return;
01273                     }
01274                     *naddr = *addr;
01275                     taddr = addr;
01276                     addr = naddr;
01277                     naddr = taddr;
01278                     taddr = 0;
01279                 }
01280                 
01281                 if(  (nh->nic_addr_tree == 0L)
01282                   ||((paddr = tfind(addr, &(nh->nic_addr_tree), nic_addr_comparator)) == 0L)
01283                   ) tsearch(addr, &(nh->nic_addr_tree), nic_addr_comparator);
01284                 
01285                 if( paddr != 0L )
01286                 {
01287                     taddr = *paddr;
01288                     *taddr = *addr;
01289                     if( naddr )
01290                         free(naddr);
01291                 }
01292 
01293                 if( ipa == 0L )
01294                     addr = &ipaf;
01295 
01296                 if( ipa && ( nic_addr_comparator( ipa , addr ) == 0 ) )
01297                     goto nla_return;
01298 
01299                 hdr = nlmsg_next( hdr, &remaining );
01300 
01301             } while ( remaining > 0 );  
01302 
01303         }else
01304         {
01305             eprintf(NIC_ERR,"nic_addresses: netlink recv failed: %s %d\n", 
01306                     nl_get_errno(), nl_geterror());
01307             goto nla_return;
01308         }
01309     } while ( (hdr->nlmsg_type == RTM_NEWADDR) && (remaining > 0) );
01310 
01311 nla_return:
01312     if( buf )
01313         free(buf);
01314     nlmsg_free(msg);
01315     return n_addrs;         
01316 
01317 nla_put_failure:
01318     nlmsg_free(msg);
01319     return n_addrs;
01320 }
01321 
01322 struct nic_addr_cbarg
01323 {
01324     IPaddr_Handler_t cb;
01325     void        *arg;
01326 };
01327 
01328 static void nic_addr_twalker( const void *p, const VISIT which, const int depth )
01329 {
01330     struct nic_ip_address_s *addr, *const*app=p;
01331     struct nic_addr_cbarg *cb;
01332 
01333     if( (app == 0L)    || ((addr = *app) == 0L)
01334       ||(addr->nh == 0) || (addr->nh->nic_addr_foreach_arg == 0 )
01335       ||( (which != postorder) && (which != leaf) )
01336       ) return;
01337 
01338     cb = addr->nh->nic_addr_foreach_arg;
01339  
01340     cb->cb( addr->nh, addr, cb->arg );       
01341 }
01342 
01343 void nic_addr_foreach(NLH_t nh, IPaddr_Handler_t handler,  void *arg)
01344 {
01345     struct nic_addr_cbarg cb = { handler, arg };
01346 
01347     if ( nh->nic_addr_foreach_arg )
01348         return;
01349 
01350     nh->nic_addr_foreach_arg = &cb;
01351 
01352     nic_get_addresses(nh, 0L);
01353 
01354     if( nh->nic_addr_tree )
01355         twalk( nh->nic_addr_tree, nic_addr_twalker);
01356 
01357     nh->nic_addr_foreach_arg = 0L;
01358 }
01359 
01360 IPaddr_t nic_addr_ip( NLH_t nh, ip_addr_t *ip)
01361 {
01362     if( ( nh == 0L ) || ( ip == 0L ) 
01363       ||( (ip->sa_family != AF_INET)
01364         &&(ip->sa_family != AF_INET6)
01365         )
01366       ) return 0;
01367         
01368     IPaddr_t ipa = calloc(1, sizeof(struct nic_ip_address_s));
01369     
01370     if( ipa == 0L )
01371     {
01372         eprintf(NIC_ERR, "nic_addr_ip: out of memory");
01373     }
01374     ipa->nh = nh;
01375     ipa->nla.addr = *ip;
01376     ipa->nla.have |= NIC_ADDR_ADDRESS;
01377     return ipa;
01378 }
01379 
01380 IPaddr_t nic_addr( NLH_t nh, ip_addr_t ip)
01381 {
01382     if( ( nh == 0L )
01383       ||( (ip.sa_family != AF_INET)
01384         &&(ip.sa_family != AF_INET6)
01385         )
01386       ) return 0;
01387         
01388     IPaddr_t ipa = calloc(1, sizeof(struct nic_ip_address_s));
01389     
01390     if( ipa == 0L )
01391     {
01392         eprintf(NIC_ERR, "nic_addr: out of memory");
01393     }
01394     ipa->nh = nh;
01395     ipa->nla.addr = ip;
01396     ipa->nla.ifa.ifa_family = ip.sa_family;
01397     ipa->nla.have |= NIC_ADDR_ADDRESS;
01398     return ipa;
01399 }
01400 
01401 IPaddr_t nic_addr_local( NLH_t nh, ip_addr_t ip)
01402 {
01403     if( ( nh == 0L )
01404       ||((ip.sa_family != AF_INET)
01405        &&(ip.sa_family != AF_INET6)
01406         )
01407       ) return 0;
01408         
01409     IPaddr_t ipa = calloc(1, sizeof(struct nic_ip_address_s));
01410     
01411     if( ipa == 0L )
01412     {
01413         eprintf(NIC_ERR, "nic_addr_local: out of memory");
01414     }
01415     ipa->nh = nh;
01416     ipa->nla.local = ip;
01417     ipa->nla.have |= NIC_ADDR_LOCAL;
01418     return ipa;
01419 }
01420 
01421 ip_addr_t nic_ip_addr( IPaddr_t ipa )
01422 {
01423     ip_addr_t ip;
01424     memset(&ip, '\0', sizeof(ip_addr_t));
01425     if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_ADDRESS) == 0))
01426         return ip;
01427     return ipa->nla.addr;
01428 }
01429 
01430 ip_addr_t nic_addr_get_local( IPaddr_t ipa )
01431 {
01432     ip_addr_t ip;
01433     memset(&ip, '\0', sizeof(ip_addr_t));
01434     if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_LOCAL) == 0))
01435         return ip;
01436     return ipa->nla.local;
01437 }
01438 
01439 void nic_addr_set_local( IPaddr_t ipa, ip_addr_t ip )
01440 {
01441     if((ipa == 0L) 
01442       ||((ip.sa_family != AF_INET)
01443        &&(ip.sa_family != AF_INET6)
01444         )
01445       ) return;
01446     
01447     ipa->nla.local = ip;
01448     ipa->nla.have |= NIC_ADDR_LOCAL;
01449 }
01450 
01451 uint8_t nic_addr_get_family( IPaddr_t ipa )
01452 {
01453     if(ipa == 0L) return 0;
01454     return ipa->nla.ifa.ifa_family;
01455 }
01456 
01457 uint8_t nic_addr_get_prefix( IPaddr_t ipa)
01458 {
01459     if(ipa == 0L) return 0;
01460     return ipa->nla.ifa.ifa_prefixlen;
01461 }
01462 
01463 void nic_addr_set_prefix( IPaddr_t ipa, uint8_t prefix)
01464 {
01465     if(  (ipa == 0L)     
01466        ||((ipa->nla.ifa.ifa_family == AF_INET) && (prefix > 32))
01467        ||((ipa->nla.ifa.ifa_family == AF_INET6) && (prefix > 128))
01468       )
01469         return;
01470     
01471     ipa->nla.ifa.ifa_prefixlen = prefix;    
01472 }
01473 
01474 ip_addr_t nic_addr_get_broadcast( IPaddr_t ipa )
01475 {
01476     ip_addr_t ip;
01477     memset(&ip, '\0', sizeof(ip_addr_t));
01478     if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_BROADCAST) == 0))
01479         return ip;
01480     return ipa->nla.broadcast;
01481 }
01482 
01483 void nic_addr_set_broadcast( IPaddr_t ipa, ip_addr_t ip )
01484 {
01485     if( (ipa == 0L) 
01486       ||((ip.sa_family != AF_INET)
01487        &&(ip.sa_family != AF_INET6)
01488         )
01489       ) return;
01490     
01491     ipa->nla.broadcast = ip;
01492     ipa->nla.have |= NIC_ADDR_BROADCAST;
01493 }
01494 
01495 ip_addr_t nic_addr_get_anycast( IPaddr_t ipa )
01496 {
01497     ip_addr_t ip;
01498     memset(&ip, '\0', sizeof(ip_addr_t));
01499     if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_ANYCAST) == 0))
01500         return ip;
01501     return ipa->nla.anycast;
01502 }
01503 
01504 void nic_addr_set_anycast( IPaddr_t ipa, ip_addr_t ip )
01505 {
01506     if( (ipa == 0L) 
01507       ||((ip.sa_family != AF_INET)
01508        &&(ip.sa_family != AF_INET6)
01509         )
01510       ) return;
01511     
01512     ipa->nla.anycast = ip;
01513     ipa->nla.have |= NIC_ADDR_ANYCAST;
01514 }
01515 
01516 ip_addr_t nic_addr_get_multicast( IPaddr_t ipa )
01517 {
01518     ip_addr_t ip;
01519     memset(&ip, '\0', sizeof(ip_addr_t));
01520     if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_MULTICAST) == 0))
01521         return ip;
01522     return ipa->nla.multicast;
01523 }
01524 
01525 void nic_addr_set_multicast( IPaddr_t ipa, ip_addr_t ip )
01526 {
01527     if( (ipa == 0L) 
01528       ||( (ip.sa_family != AF_INET)
01529         &&(ip.sa_family != AF_INET6)
01530         )
01531       ) return;
01532     
01533     ipa->nla.multicast = ip;
01534     ipa->nla.have |= NIC_ADDR_MULTICAST;
01535 }
01536 
01537 int8_t nic_addr_get_scope(IPaddr_t ipa)
01538 {
01539     if(ipa == 0L) return 0;
01540 
01541     return ipa->nla.ifa.ifa_scope;      
01542 }
01543 
01544 void nic_addr_set_scope(IPaddr_t ipa, int8_t scope )
01545 {
01546     if(ipa == 0L) return;
01547     
01548     ipa->nla.ifa.ifa_scope = scope;
01549 }
01550 
01551 uint8_t nic_addr_get_flags(IPaddr_t ipa)
01552 {
01553     if(ipa == 0L) return 0;
01554 
01555     return ipa->nla.ifa.ifa_flags;      
01556 }
01557 
01558 void nic_addr_set_flags(IPaddr_t ipa, uint8_t flags )
01559 {
01560     if(ipa == 0L) return;
01561     
01562     ipa->nla.ifa.ifa_flags = flags;
01563 }
01564 
01565 const char *nic_addr_get_label(IPaddr_t ipa)
01566 {
01567     if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_LABEL) == 0))
01568         return "";
01569     return &(ipa->nla.label[0]);       
01570 }
01571 
01572 void nic_addr_set_label(IPaddr_t ipa, const char *label)
01573 {
01574     if((ipa == 0L) || (label == 0L)) return;
01575     strncpy(&(ipa->nla.label[0]), label, IFNAMSIZ);
01576     ipa->nla.have |= NIC_ADDR_LABEL;
01577 }
01578 
01579 struct ifa_cacheinfo nic_addr_get_cacheinfo( IPaddr_t ipa )
01580 {
01581     struct ifa_cacheinfo ifa_ca;
01582     memset(&ifa_ca, '\0', sizeof(struct ifa_cacheinfo));
01583     if( (ipa == 0L) || ((ipa->nla.have & NIC_ADDR_CACHEINFO) == 0))
01584         return ifa_ca;
01585     return ipa->nla.cacheinfo;
01586 }
01587 
01588 void  nic_addr_set_cacheinfo( IPaddr_t ipa, struct ifa_cacheinfo *ca)
01589 {
01590     if((ipa == 0L) || (ca == 0L)) return;
01591     ipa->nla.cacheinfo = *ca;
01592     ipa->nla.have |= NIC_ADDR_CACHEINFO;
01593 }
01594 
01595 IPaddr_list_t *nic_address_list_new( IPaddr_t ip1, ... )
01596 {      
01597     va_list va;
01598     NLH_t nh = ip1->nh;
01599     va_start(va, ip1);
01600     
01601     IPaddr_list_t *head = calloc(1,sizeof(IPaddr_list_t));
01602     IPaddr_list_node_t *n;
01603     struct nic_ip_address_s *ip;
01604 
01605     if( head == 0 )
01606     {
01607         va_end(va);
01608         eprintf(NIC_ERR, "out of memory" );
01609         return 0;
01610     }
01611     ip=ip1;
01612     STAILQ_INIT(head);
01613     do
01614     {
01615         n = calloc(1,sizeof(IPaddr_list_node_t));
01616         if ( n == 0L )
01617         {
01618             va_end(va);
01619             free(head);
01620             eprintf(NIC_ERR, "out of memory" );
01621             return 0L;
01622         }
01623         n->addr = ip;
01624         STAILQ_INSERT_TAIL( head, n, link );
01625     }while( (ip = va_arg(va, struct nic_ip_address_s*)) != 0) ;
01626     va_end(va);
01627     return(head);
01628 }
01629 
01630 void nic_address_list_free( IPaddr_list_t *head )
01631 {
01632     IPaddr_list_node_t *n, *a;
01633     
01634     if ( !STAILQ_EMPTY(head) )
01635     {
01636         n = STAILQ_FIRST( head );
01637         do
01638         {
01639             a = STAILQ_NEXT(n, link);
01640             free(n->addr);
01641             free(n);
01642             n = a;
01643         } while (n);
01644     }
01645 }
01646 
01647 typedef
01648 enum nic_ar_e
01649 {
01650     NIC_ADD_ADDRESS,
01651     NIC_DELETE_ADDRESS
01652 } NIC_Address_Request;
01653 
01654 static 
01655 int nic_addr_send( IPaddr_t ipa, NIC_Address_Request req )
01656 {
01657     char abuf[64];
01658     int err=0;
01659     NLH_t nh;
01660 
01661     if(ipa == 0L)
01662         return -1;
01663     nh = ipa->nh;
01664     
01665     memset(&(ipa->nla.hdr), '\0', sizeof(struct nlmsghdr));
01666 
01667     ipa->nla.hdr.nlmsg_type = 
01668         (req == NIC_DELETE_ADDRESS) 
01669         ? RTM_DELADDR
01670         : RTM_NEWADDR;
01671 
01672     ipa->nla.hdr.nlmsg_flags =
01673         ( (req == NIC_ADD_ADDRESS) 
01674           ? (NLM_F_REPLACE | NLM_F_MATCH)
01675           : 0
01676         ) | NLM_F_REQUEST | NLM_F_ACK |  NLM_F_ROOT;
01677 
01678     ipa->nla.hdr.nlmsg_len = sizeof(struct nlmsghdr);
01679 
01680     if( ipa->nla.ifa.ifa_flags == 0 )
01681         ipa->nla.ifa.ifa_flags = IFA_F_PERMANENT;
01682 
01683     struct nl_msg *msg = nlmsg_build(&(ipa->nla.hdr));
01684 
01685     if ( msg == 0L ) {
01686         eprintf(NIC_ERR, "nic_addr_send: nlmsg_build failed - %d %s" ,
01687                 nl_get_errno(), nl_geterror());
01688         return NIC_FAIL;
01689     }
01690 
01691     nlmsg_append( msg, &(ipa->nla.ifa), sizeof( struct ifaddrmsg ), 1);
01692 
01693     if( ipa->nla.have & NIC_ADDR_ADDRESS )
01694     {
01695         NLA_PUT(msg, IFA_ADDRESS, IP_ADDR_SIZE(&(ipa->nla.addr)), IP_ADDR( &(ipa->nla.addr) ));
01696         if( (ipa->nla.ifa.ifa_family == AF_INET)  && ((ipa->nla.have & NIC_ADDR_LOCAL)==0) )
01697         {
01698             ipa->nla.have |= NIC_ADDR_LOCAL;
01699             ipa->nla.local = ipa->nla.addr;
01700         }
01701         eprintf(NIC_DEBUG,"nic_addr_send: add IFA_ADDRESS: %d %s/%d\n", 
01702                 ipa->nla.ifa.ifa_index, ip_text_addr(&(ipa->nla.addr),abuf,64),
01703                 ipa->nla.ifa.ifa_prefixlen);
01704     }
01705 
01706     if( ipa->nla.have & NIC_ADDR_LOCAL )
01707     {
01708         NLA_PUT(msg, IFA_LOCAL, IP_ADDR_SIZE(&(ipa->nla.local)), IP_ADDR( &(ipa->nla.local) ));
01709         eprintf(NIC_DEBUG,"nic_addr_send: add IFA_LOCAL: %d %s\n",
01710                 ipa->nla.ifa.ifa_index,
01711                 ip_text_addr(&(ipa->nla.local),abuf,64));
01712     }
01713 
01714     if( ipa->nla.have & NIC_ADDR_LABEL )
01715         NLA_PUT_STRING(msg, IFA_LABEL, &(ipa->nla.label[0]));
01716 
01717     if( ipa->nla.have & NIC_ADDR_BROADCAST )
01718     {
01719         NLA_PUT(msg, IFA_BROADCAST, IP_ADDR_SIZE(&(ipa->nla.broadcast)), IP_ADDR( &(ipa->nla.broadcast) ));
01720         eprintf(NIC_DEBUG,"nic_addr_send: add address: %d broadcast: %s\n", 
01721                 ipa->nla.ifa.ifa_index,
01722                 ip_text_addr(&(ipa->nla.broadcast), abuf, 64));
01723     }
01724 
01725     if( ipa->nla.have & NIC_ADDR_ANYCAST )
01726         NLA_PUT(msg, IFA_ANYCAST, IP_ADDR_SIZE(&(ipa->nla.broadcast)), IP_ADDR( &(ipa->nla.broadcast) ));
01727     
01728     if( ipa->nla.have & NIC_ADDR_MULTICAST )
01729         NLA_PUT(msg, IFA_MULTICAST, IP_ADDR_SIZE(&(ipa->nla.broadcast)), IP_ADDR( &(ipa->nla.multicast) ));
01730 
01731     if( ipa->nla.have & NIC_ADDR_CACHEINFO )
01732         NLA_PUT(msg, IFA_CACHEINFO, sizeof(struct ifa_cacheinfo), &(ipa->nla.cacheinfo));
01733 
01734     if( (err = nl_send_auto_complete(ipa->nh->nl, nlmsg_hdr(msg))) < 0 )
01735     {
01736         eprintf(NIC_ERR,"nic_addr_send: send failed - %d %d %s",
01737                 err, nl_get_errno(), nl_geterror());
01738         return NIC_FAIL;
01739     }
01740 
01741     nlmsg_free(msg);
01742 
01743     int n_tries = 0;
01744     try_again:
01745 
01746     if( (n_tries < 10) && ((err= nl_wait_for_ack(ipa->nh->nl)) < 0) )
01747     {
01748         if( err == - EBUSY )
01749         {
01750             struct timespec ts = { 0, 500000000 };
01751             ++n_tries;
01752             /* Device or resource busy */
01753             nanosleep(&ts,0);
01754             goto try_again;
01755         }
01756         
01757         if( err == -EEXIST )
01758         {
01759             /* something isn't listening to our "NLM_F_REPLACE" flag ...*/
01760             return NIC_OK;
01761         }    
01762         eprintf(NIC_ERR,"nic_addr_send failed - %d: %s", nl_get_errno(),
01763                 nl_geterror());
01764         return NIC_FAIL;        
01765     }
01766     
01767     return NIC_OK;
01768 
01769 nla_put_failure:
01770 
01771     eprintf(NIC_ERR, "nic_addr_send append attr failed - out of memory?");
01772 
01773     nlmsg_free(msg);
01774 
01775     return NIC_FAIL;
01776 }
01777 
01778 NIC_Res_t nic_add_address( NIC_t nic, IPaddr_t ipa)
01779 {
01780     if( ( ipa == 0L ) || (nic == 0L) )
01781         return NIC_FAIL;
01782     ipa->nla.ifa.ifa_index = nic->l.ifi.ifi_index;
01783     return nic_addr_send( ipa, NIC_ADD_ADDRESS );
01784 }
01785 
01786 NIC_Res_t nic_remove_address( NIC_t nic, IPaddr_t ipa)
01787 {
01788     if( ( ipa == 0L ) || (nic == 0L) )
01789         return NIC_FAIL;
01790     ipa->nla.ifa.ifa_index = nic->l.ifi.ifi_index;
01791     return nic_addr_send( ipa, NIC_ADD_ADDRESS );
01792 }
01793 
01794 NIC_Res_t nic_add_addresses( NIC_t nic, IPaddr_list_t *head )
01795 {
01796     IPaddr_list_node_t *n;
01797     NIC_Res_t r;
01798 
01799     STAILQ_FOREACH(n,head,link)
01800     {
01801         if((r = nic_add_address(nic, n->addr)) == NIC_FAIL)
01802             return r;
01803     }
01804     return NIC_OK;
01805 }
01806 
01807 NIC_Res_t nic_remove_addresses( NIC_t nic, IPaddr_list_t *head )
01808 {
01809     IPaddr_list_node_t *n;
01810     NIC_Res_t r;
01811 
01812     STAILQ_FOREACH(n,head,link)
01813     {
01814         if((r = nic_remove_address(nic, n->addr)) == NIC_FAIL)
01815             return r;
01816     }
01817     return NIC_OK;
01818 }
01819 
01820 void nic_addr_free(void *ipa)
01821 {
01822     if (ipa)
01823         free(ipa);
01824 }
01825 
01826 struct nic_route_s
01827 {
01828     NLH_t nh;
01829     
01830     struct nic_rt_s
01831     {
01832         struct nlmsghdr hdr;
01833         struct rtmsg    rtm;
01834         /* struct rtmsg
01835          * {
01836          *      unsigned char           rtm_family;
01837          *      unsigned char           rtm_dst_len;
01838          *      unsigned char           rtm_src_len;
01839          *      unsigned char           rtm_tos;
01840          *
01841          *      unsigned char           rtm_table;
01842          *      unsigned char           rtm_protocol;
01843          *      unsigned char           rtm_scope;
01844          *      unsigned char           rtm_type;
01845          *
01846          *      unsigned                rtm_flags;
01847          *};
01848          */
01849 
01850         ip_addr_t dst;
01851         ip_addr_t gw;
01852         ip_addr_t src;
01853         ip_addr_t prefsrc;
01854         int32_t   oif;       
01855         uint32_t  priority;
01856         uint32_t  protoinfo;
01857         uint32_t  flow;
01858         uint32_t  session;
01859         uint32_t  mp_algo;
01860         struct rta_cacheinfo cacheinfo;
01861         char      iif [ IFNAMSIZ ];
01862         uint32_t  metrics[ __RTAX_MAX ];
01863 
01864         struct nic_rtnh_s
01865         {
01866             struct rtnexthop rtnh;
01867             ip_addr_t gw;
01868         } *hops;
01869         uint32_t n_hops;
01870         
01871         enum rt_a_e
01872         {
01873             NIC_RT_DST      =   1,
01874             NIC_RT_SRC      =   2,  
01875             NIC_RT_IIF      =   8,
01876             NIC_RT_OIF      =  16,
01877             NIC_RT_GATEWAY  =  32,
01878             NIC_RT_PRIORITY =  64,
01879             NIC_RT_PREFSRC  = 128,
01880             NIC_RT_METRICS  = 256,
01881             NIC_RT_MULTIPATH= 512,
01882             NIC_RT_PROTOINFO=1024,
01883             NIC_RT_FLOW     =2048,
01884             NIC_RT_CACHEINFO=4096,
01885             NIC_RT_SESSION  =8192,
01886             NIC_RT_MP_ALGO= 16384
01887         } have, change;
01888         
01889         enum rtax_e
01890         {
01891             NIC_RTAX_LOCK =     (1<<RTAX_LOCK),
01892             NIC_RTAX_MTU  =     (1<<RTAX_MTU),
01893             NIC_RTAX_WINDOW =   (1<<RTAX_WINDOW),
01894             NIC_RTAX_RTT    =   (1<<RTAX_RTT),
01895             NIC_RTAX_RTTVAR =   (1<<RTAX_RTTVAR),
01896             NIC_RTAX_SSTHRESH = (1<<RTAX_SSTHRESH),
01897             NIC_RTAX_CWND     = (1<<RTAX_CWND),
01898             NIC_RTAX_ADVMSS   = (1<<RTAX_ADVMSS),
01899             NIC_RTAX_REORDERING=(1<<RTAX_REORDERING),
01900             NIC_RTAX_HOPLIMIT  =(1<<RTAX_HOPLIMIT),
01901             NIC_RTAX_INITCWND  =(1<<RTAX_INITCWND),
01902             NIC_RTAX_FEATURES  =(1<<RTAX_FEATURES)
01903         } have_metrics, change_metrics;
01904     } rt;
01905 };
01906 
01907 typedef struct nic_route_s RT_t;
01908 
01909 static struct nla_policy nic_route_policy[RTA_MAX+1] = {
01910         [RTA_IIF]       = { .type = NLA_STRING,
01911                             .maxlen = IFNAMSIZ, },
01912         [RTA_OIF]       = { .type = NLA_U32 },
01913         [RTA_PRIORITY]  = { .type = NLA_U32 },
01914         [RTA_FLOW]      = { .type = NLA_U32 },
01915         [RTA_MP_ALGO]   = { .type = NLA_U32 },
01916         [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
01917         [RTA_METRICS]   = { .type = NLA_NESTED },
01918         [RTA_MULTIPATH] = { .type = NLA_NESTED },
01919 };
01920 
01921 static int nic_route_comparator( const void *p1, const void *p2 )
01922 {
01923     const RT_t *rt1 = p1, *rt2 = p2;
01924 
01925     if( rt1->rt.rtm.rtm_table != rt2->rt.rtm.rtm_table )
01926         return
01927         (   (rt1->rt.rtm.rtm_table > rt2->rt.rtm.rtm_table )
01928             ? 1
01929             : -1
01930         );
01931 
01932     if ( rt1->rt.rtm.rtm_family != rt2->rt.rtm.rtm_family )
01933         return
01934         (   ( rt1->rt.rtm.rtm_family > rt2->rt.rtm.rtm_family )
01935             ? 1
01936             : -1
01937         );
01938  
01939     if ( rt1->rt.rtm.rtm_type != rt2->rt.rtm.rtm_type )
01940         return
01941         (   ( rt1->rt.rtm.rtm_type > rt2->rt.rtm.rtm_type )
01942             ? 1
01943             : -1
01944         );
01945 
01946     if ( rt1->rt.rtm.rtm_scope != rt2->rt.rtm.rtm_scope )
01947         return
01948         (   ( rt1->rt.rtm.rtm_scope > rt2->rt.rtm.rtm_scope )
01949             ? 1
01950             : -1
01951         );
01952 
01953     if ( rt1->rt.rtm.rtm_protocol != rt2->rt.rtm.rtm_protocol )
01954         return
01955         (   ( rt1->rt.rtm.rtm_protocol > rt2->rt.rtm.rtm_protocol )
01956             ? 1
01957             : -1
01958         );
01959 
01960     if( rt1->rt.have & NIC_RT_OIF )
01961     {   
01962         if( ( rt2->rt.have & NIC_RT_OIF ) == 0 )
01963             return 1;
01964         else
01965         {
01966             if( rt1->rt.oif != rt2->rt.oif )
01967                 return
01968                     (   (rt1->rt.oif > rt2->rt.oif)
01969                         ? 1
01970                         : -1
01971                     ); 
01972         }
01973     }else
01974     if( rt2->rt.have & NIC_RT_OIF )
01975         return -1;
01976 
01977     if( rt1->rt.have & NIC_RT_IIF )
01978     {   
01979         if( ( rt2->rt.have & NIC_RT_IIF ) == 0 )
01980             return 1;
01981         else
01982         {
01983             int c = strcmp(&(rt1->rt.iif[0]),&(rt2->rt.iif[0]));
01984             if( c != 0 )
01985                 return c;
01986         }
01987     }else
01988     if( rt2->rt.have & NIC_RT_OIF )
01989         return -1;
01990 
01991     if( rt1->rt.have & NIC_RT_DST )
01992     {
01993         if( (rt2->rt.have & NIC_RT_DST) == 0 )
01994             return 1;
01995         else
01996         {
01997                 
01998             if( rt1->rt.dst.sa_family != rt2->rt.dst.sa_family )
01999                 return
02000                 (   ( rt1->rt.dst.sa_family > rt2->rt.dst.sa_family )
02001                     ? 1
02002                     : -1
02003                 );
02004 
02005             if( rt1->rt.rtm.rtm_dst_len != rt2->rt.rtm.rtm_dst_len )
02006                 return
02007                 (   ( rt1->rt.rtm.rtm_dst_len > rt2->rt.rtm.rtm_dst_len )
02008                     ? 1
02009                     : -1
02010                 );
02011 
02012             uint8_t
02013                 *ap1 = IP_ADDR( &(rt1->rt.dst) ),
02014                 *ap2 = IP_ADDR( &(rt2->rt.dst) ),
02015                 pfx1 = rt1->rt.rtm.rtm_dst_len;
02016 
02017             if( pfx1 == 0 )
02018                 pfx1 = IP_ADDR_SIZE( &(rt1->rt.dst) );
02019 
02020             int cr = memcmp( ap1, ap2,
02021                              pfx1 / 8
02022                            );
02023             if ( cr != 0 )
02024                 return cr;
02025             uint8_t 
02026                 v1 = ((uint8_t*)IP_ADDR( &(rt1->rt.dst) ))[ pfx1 / 8 ]
02027                     & ( ( 1 << ( pfx1 % 8 ) ) - 1),
02028                 v2 = ((uint8_t*)IP_ADDR( &(rt2->rt.dst) ))[ pfx1 / 8 ]
02029                     & ( ( 1 << ( pfx1 % 8 ) ) - 1);             
02030 
02031             if( v1 != v2 )
02032                 return 
02033                 (
02034                     (v1 > v2)
02035                     ?  1
02036                     : -1
02037                 );
02038             
02039             if( rt1->rt.have & NIC_RT_PRIORITY )
02040             {
02041                 if( (rt2->rt.have & NIC_RT_PRIORITY) == 0 )
02042                     return -1;
02043                 
02044                 if( rt1->rt.priority !=  rt2->rt.priority )
02045                     return
02046                     (   (rt1->rt.priority >  rt2->rt.priority)
02047                         ? -1
02048                         : 1
02049                     );
02050             }
02051         }
02052     }else
02053     if( rt2->rt.have & NIC_RT_DST )
02054         return -1;
02055 
02056     if( rt1->rt.have & NIC_RT_SRC )
02057     {
02058         if( (rt2->rt.have & NIC_RT_SRC) == 0 )
02059             return 1;
02060         else
02061         {               
02062             if( rt1->rt.src.sa_family != rt2->rt.src.sa_family )
02063                 return
02064                 (   ( rt1->rt.src.sa_family > rt2->rt.src.sa_family )
02065                     ? 1
02066                     : -1
02067                 );
02068 
02069             if( rt1->rt.rtm.rtm_src_len != rt2->rt.rtm.rtm_src_len )
02070                 return
02071                 (   ( rt1->rt.rtm.rtm_src_len > rt2->rt.rtm.rtm_src_len )
02072                     ? 1
02073                     : -1
02074                 );
02075 
02076             uint8_t
02077                 *ap1 = IP_ADDR( &(rt1->rt.src) ),
02078                 *ap2 = IP_ADDR( &(rt2->rt.src) ),
02079                 pfx1 = rt1->rt.rtm.rtm_src_len;
02080 
02081             if( pfx1 == 0 )
02082                 pfx1 = IP_ADDR_SIZE( &(rt1->rt.src) );
02083 
02084             int cr = memcmp( ap1, ap2,
02085                              rt1->rt.rtm.rtm_src_len / 8
02086                            );
02087             if ( cr != 0 )
02088                 return cr;
02089             uint8_t 
02090                 v1 = ((uint8_t*)IP_ADDR( &(rt1->rt.src) ))[ pfx1 / 8 ]
02091                     & ( ( 1 << ( rt1->rt.rtm.rtm_src_len % 8 ) ) - 1),
02092                 v2 = ((uint8_t*)IP_ADDR( &(rt2->rt.src) ))[ pfx1 / 8 ]
02093                     & ( ( 1 << ( pfx1 % 8 ) ) - 1);             
02094 
02095             if( v1 != v2 )
02096                 return 
02097                 (
02098                     (v1 > v2)
02099                     ?  1
02100                     : -1
02101                 );
02102             
02103             if( rt1->rt.have & NIC_RT_PRIORITY )
02104             {
02105                 if( (rt2->rt.have & NIC_RT_PRIORITY) == 0 )
02106                     return -1;
02107                 
02108                 if( rt1->rt.priority !=  rt2->rt.priority )
02109                     return
02110                     (   (rt1->rt.priority >  rt2->rt.priority)
02111                         ? 1
02112                         : -1
02113                     );
02114             }
02115         }
02116     }else
02117     if (rt2->rt.have & NIC_RT_SRC)
02118         return -1;
02119 
02120     if ( rt1->rt.have & NIC_RT_GATEWAY )
02121     {
02122         if((rt2->rt.have & NIC_RT_GATEWAY)==0)
02123             return 1;
02124         {
02125 
02126             if( rt1->rt.gw.sa_family != rt2->rt.gw.sa_family )
02127                 return
02128                 (   ( rt1->rt.gw.sa_family > rt2->rt.gw.sa_family )
02129                     ? 1
02130                     : -1
02131                 );
02132                     
02133             uint8_t
02134                 *ap1 = IP_ADDR( &(rt1->rt.gw) ),
02135                 *ap2 = IP_ADDR( &(rt2->rt.gw) );
02136 
02137             int cr = memcmp( ap1, ap2,
02138                              IP_ADDR_SIZE(&(rt1->rt.gw))
02139                            );
02140             
02141             if( cr != 0 )
02142                 return cr;          
02143         }
02144     }else
02145     if (rt2->rt.have & NIC_RT_GATEWAY)
02146         return -1;
02147 
02148     if ( rt1->rt.have & NIC_RT_PREFSRC )
02149     {
02150         if((rt2->rt.have & NIC_RT_PREFSRC)==0)
02151             return 1;
02152         {
02153 
02154             if( rt1->rt.prefsrc.sa_family != rt2->rt.prefsrc.sa_family )
02155                 return
02156                 (   ( rt1->rt.prefsrc.sa_family > rt2->rt.prefsrc.sa_family )
02157                     ? 1
02158                     : -1
02159                 );
02160                     
02161             uint8_t
02162                 *ap1 = IP_ADDR( &(rt1->rt.prefsrc) ),
02163                 *ap2 = IP_ADDR( &(rt2->rt.prefsrc) );
02164 
02165             int cr = memcmp( ap1, ap2,
02166                              IP_ADDR_SIZE(&(rt1->rt.prefsrc))
02167                            );
02168             
02169             if( cr != 0 )
02170                 return cr;          
02171         }
02172     } else
02173     if (rt2->rt.have & NIC_RT_PREFSRC)
02174         return -1;
02175     return 0;
02176 }
02177 
02178 static int nic_get_routes(NLH_t nh, RT_t *rt)
02179 {
02180     RT_t srt, *rtp=0;
02181     struct nic_rt_s  *rta=0;
02182     int n_routes = 0;
02183 
02184     if(nh == 0)
02185         return 0;   
02186 
02187     if( rt )
02188     {
02189         srt = *rt;
02190         rtp = rt;
02191         rta = &(rt->rt);    
02192         memset(&(rta->hdr),'\0',sizeof(struct nlmsghdr));
02193         rta->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ATOMIC | NLM_F_MATCH;
02194     }else
02195     {
02196         memset(&srt, '\0', sizeof(RT_t));
02197         srt.nh = nh;
02198         rtp = &srt;
02199         rta = &(rtp->rt);    
02200         rta->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
02201     }
02202     
02203     rta->hdr.nlmsg_type = RTM_GETROUTE;
02204     
02205     struct nl_msg *msg = nlmsg_build(&(rta->hdr));
02206 
02207     if( msg == 0L )
02208     {
02209         eprintf(NIC_ERR, "nic_get_routes: out of memory" );
02210         return n_routes;
02211     }
02212     
02213     if( nlmsg_append(msg, &(rta->rtm), sizeof(struct rtmsg), 1) < 0 )
02214     {   
02215         eprintf(NIC_ERR,"nic_get_routes: nlmsg_append failed: %d %s\n", 
02216                 nl_get_errno(), nl_geterror());
02217         goto nla_put_failure;
02218     }
02219 
02220     if(  rta->rtm.rtm_dst_len && rta->dst.sa_family 
02221       &&(rta->have & NIC_RT_DST)
02222       )
02223         NLA_PUT(msg, RTA_DST, 
02224                 IP_ADDR_SIZE(&(rta->dst)), 
02225                 IP_ADDR(&(rta->dst))
02226                );
02227 
02228     if( (rta->have & NIC_RT_OIF) &&  (rta->oif > -1) )
02229         NLA_PUT_U32(msg, RTA_OIF, rta->oif);
02230     
02231     if(  rta->gw.sa_family 
02232       &&(rta->have & NIC_RT_GATEWAY)
02233       )
02234         NLA_PUT(msg, RTA_GATEWAY, 
02235                 IP_ADDR_SIZE(&(rta->gw)), 
02236                 IP_ADDR(&(rta->gw))
02237                );
02238     
02239     if(  rta->rtm.rtm_src_len && rta->src.sa_family 
02240       &&(rta->have & NIC_RT_SRC)
02241       )
02242         NLA_PUT(msg, RTA_SRC, 
02243                 IP_ADDR_SIZE(&(rta->src)), 
02244                 IP_ADDR(&(rta->src))
02245                );
02246     
02247     if( (rta->have & NIC_RT_IIF) &&  (rta->iif[0] != '\0') )
02248         NLA_PUT_STRING(msg, RTA_IIF, &(rta->iif[0]));           
02249 
02250     if ( nl_send_auto_complete( nh->nl, nlmsg_hdr(msg) ) < 0 )
02251     {
02252         eprintf(NIC_ERR,"nic_get_routes: send failed: %d %s\n", 
02253                 nl_get_errno(), nl_geterror());
02254         goto nla_put_failure;
02255     }
02256 
02257     char abuf[64];
02258     struct RT_t *buf =0;
02259     struct nlmsghdr *hdr = (struct nlmsghdr *)buf;
02260     struct sockaddr_nl kernel;
02261     int rlen = 0;
02262     int remaining = 0;
02263     
02264     do
02265     {
02266         if ( (rlen = nl_recv( nh->nl, &kernel, (void*)&buf)) > 0 )
02267         {
02268             if( rlen < (sizeof(struct nlmsghdr) + sizeof(struct rtmsg)) )
02269                 goto rta_return;
02270 
02271             hdr = (struct nlmsghdr*)buf;
02272             remaining = rlen;
02273 
02274             if( hdr->nlmsg_type != RTM_NEWROUTE )
02275                 goto rta_return;
02276             
02277             do
02278             {
02279                 memset(rta, '\0', sizeof(struct nic_rt_s));
02280                 
02281                 memcpy(rta, hdr, sizeof(struct nlmsghdr));
02282                 
02283                 struct nl_attr *tb[__RTA_MAX];          
02284                 int i;
02285                 for (i=0; i < __RTA_MAX; i++) tb[i]=0;
02286 
02287                 int err = 
02288                     nlmsg_parse((struct nlmsghdr*)hdr, sizeof(struct rtmsg),
02289                                 (void*)tb, RTA_MAX, nic_route_policy);
02290                 if ( err < 0 )
02291                 {
02292                     eprintf(NIC_ERR,"nic_get_routes: nl_parse failed: %d %s",
02293                             err, nl_geterror());
02294                     goto rta_return;
02295                 }
02296                 
02297                 rta->rtm = *((struct rtmsg*)nlmsg_data((struct nlmsghdr*)hdr));
02298 
02299                 eprintf(NIC_DEBUG, "\n"
02300                                    "table: %d\ndst_len: %d\nsrc_len: %d\n"
02301                                    "scope: %d\ntype: %d\nprotocol: %d", 
02302                         rta->rtm.rtm_table, rta->rtm.rtm_dst_len,
02303                         rta->rtm.rtm_src_len, rta->rtm.rtm_scope,
02304                         rta->rtm.rtm_type,  rta->rtm.rtm_protocol);
02305 
02306                 if ( tb[RTA_DST] )
02307                 {
02308                     rta->dst =
02309                     ip_addr_binary 
02310                         ( nla_data((void*)tb[RTA_DST]),
02311                           nla_len((void*)tb[RTA_DST])
02312                         );
02313                     rta->have |= NIC_RT_DST;
02314                     eprintf(NIC_DEBUG, "nic route: dst: %s/%d",
02315                             ip_text_addr(&(rta->dst),abuf,64),
02316                             rta->rtm.rtm_dst_len);
02317                 }
02318                 
02319                 if ( tb[RTA_OIF] )
02320                 {
02321                     rta->oif = nla_get_u32( (void*) tb[RTA_OIF] );
02322                     rta->have |= NIC_RT_OIF ;
02323                     eprintf(NIC_DEBUG, "nic route: oif: %d", rta->oif);                 
02324                 }
02325 
02326                 if ( tb[RTA_GATEWAY] )
02327                 {
02328                     rta->gw =
02329                     ip_addr_binary 
02330                         ( nla_data((void*)tb[RTA_GATEWAY]),
02331                           nla_len((void*)tb[RTA_GATEWAY])
02332                         );
02333                     rta->have |= NIC_RT_GATEWAY;
02334                     eprintf(NIC_DEBUG, "nic route: gw: %s",
02335                             ip_text_addr(&(rta->gw),abuf,64));
02336                 }
02337 
02338                 if ( tb[RTA_SRC] )
02339                 {
02340                     rta->src =
02341                     ip_addr_binary 
02342                         ( nla_data((void*)tb[RTA_SRC]),
02343                           nla_len((void*)tb[RTA_SRC])
02344                         );
02345                     rta->have |= NIC_RT_SRC;
02346                     eprintf(NIC_DEBUG, "nic route: src: %s/%d",
02347                             ip_text_addr(&(rta->src),abuf,64),
02348                             rta->rtm.rtm_src_len);
02349                 }
02350                 
02351                 if ( tb[RTA_IIF] )
02352                 {
02353                     memcpy( &(rta->iif),
02354                             nla_data( (void*) tb[RTA_IIF] ),
02355                             nla_len((void*) tb[RTA_IIF] )
02356                           );
02357                     rta->have |= NIC_RT_IIF ;
02358                     eprintf(NIC_DEBUG, "nic route: iif: %s", rta->iif);                 
02359                 }
02360                 
02361                 if ( tb[RTA_PREFSRC] )
02362                 {
02363                     rta->prefsrc =
02364                     ip_addr_binary 
02365                         ( nla_data((void*)tb[RTA_PREFSRC]),
02366                           nla_len((void*)tb[RTA_PREFSRC])
02367                         );
02368                     rta->have |= NIC_RT_PREFSRC;
02369                     eprintf(NIC_DEBUG, "nic route: prefsrc: %s",
02370                             ip_text_addr(&(rta->prefsrc),abuf,64));
02371                 }
02372 
02373                 if ( tb[RTA_PRIORITY] )
02374                 {
02375                     rta->priority = nla_get_u32( (void*)tb[RTA_PRIORITY]);
02376                     rta->have |= NIC_RT_PRIORITY;
02377                     eprintf(NIC_DEBUG,"nic route: priority: %d", rta->priority);
02378                 }
02379                 
02380                 if ( tb[RTA_PROTOINFO] )
02381                 {
02382                     rta->protoinfo = nla_get_u32( (void*)tb[RTA_PROTOINFO]);
02383                     rta->have |= NIC_RT_PROTOINFO;
02384                     eprintf(NIC_DEBUG, "nic route: protoinfo: %x", rta->protoinfo);                 
02385                 }
02386 
02387                 if ( tb[RTA_FLOW] )
02388                 {
02389                     rta->flow = nla_get_u32( (void*)tb[RTA_FLOW]);
02390                     rta->have |= NIC_RT_FLOW;
02391                     eprintf(NIC_DEBUG, "nic route: flow: %x", rta->flow); 
02392                 }
02393 
02394                 if ( tb[RTA_CACHEINFO] )
02395                 {
02396                     memcpy( &(rta->cacheinfo),
02397                             nla_data((void*)tb[RTA_CACHEINFO]),
02398                             sizeof(struct rta_cacheinfo)
02399                           );
02400                     rta->have |= NIC_RT_CACHEINFO;
02401                     eprintf(NIC_DEBUG, "nic route: have cacheinfo");
02402                 }
02403 
02404                 if ( tb[RTA_SESSION] )
02405                 {
02406                     rta->session = nla_get_u32( (void*)tb[RTA_SESSION]);
02407                     rta->have |= NIC_RT_SESSION;
02408                     eprintf(NIC_DEBUG, "nic route: session: %d", rta->session);
02409                 }
02410                 
02411                 if ( tb[RTA_MP_ALGO] )
02412                 {
02413                     rta->mp_algo = nla_get_u32( (void*)tb[RTA_MP_ALGO]);
02414                     rta->have |= NIC_RT_MP_ALGO;
02415                     eprintf(NIC_DEBUG, "nic route: mp algorithm: %x", rta->mp_algo);
02416                 }
02417                 
02418                 if ( tb[RTA_METRICS] )
02419                 {
02420                     struct nlattr *rtax_tb [ __RTAX_MAX ];
02421                     int m;
02422                     for(m=0; m < __RTAX_MAX; m++) rtax_tb[m] = 0L;
02423 
02424                     err = nla_parse_nested( rtax_tb, RTAX_MAX, (void*)tb[RTA_METRICS], 0L);
02425                     if( err < 0 )
02426                     {
02427                         eprintf(NIC_ERR, "nic route: parse of RTAX metrics failed - %d %s",
02428                                 nl_get_errno(), nl_geterror());
02429                         /*XXX: do we care ?*/
02430                     }else
02431                     {
02432                         for( m = 0; m < __RTAX_MAX ; m++ )
02433                         {
02434                             if( rtax_tb [ m ] )
02435                             {
02436                                 rta->metrics[ m ] = nla_get_u32( (void*) rtax_tb [ m ] );
02437                                 rta->have_metrics |= 1<<(m+1);
02438                             }
02439                         }
02440                     }
02441                 }
02442                 
02443                 if ( tb[RTA_MULTIPATH] )
02444                 {
02445                     size_t rtnh_len = nla_len((void*)tb[RTA_MULTIPATH]);
02446 
02447                     struct rtnexthop 
02448                         *rtnhs = nla_data((void*)tb[RTA_MULTIPATH]), 
02449                         *rtnhe = (struct rtnexthop*)(((unsigned long)rtnhs) + rtnh_len),
02450                         *rtnh = rtnhs;
02451                     
02452                     while( rtnh < rtnhe )
02453                     {
02454                         rta->n_hops += 1;
02455                         rtnh = RTNH_NEXT(rtnh);
02456                     }
02457                     
02458                     rta->hops = calloc(rta->n_hops, sizeof(struct nic_rtnh_s));
02459 
02460                     if( rta->hops == 0L )
02461                     {
02462                         eprintf(NIC_ERR, "nic route: parse of route next hops failed - out of memory.");
02463                         /*XXX: do we care ?*/
02464                     }else
02465                     {
02466                         struct nic_rtnh_s *nic_rtnh = rta->hops;
02467                         for(rtnh = rtnhs; rtnh < rtnhe; rtnh = RTNH_NEXT(rtnh), nic_rtnh++ )
02468                         {
02469                             nic_rtnh->rtnh = *rtnh;
02470                             if( rtnh->rtnh_len > sizeof(struct rtnexthop) )
02471                             {
02472                                 struct nlattr *rtnhtb[ __RTA_MAX ];
02473                                 nla_parse((void*)rtnhtb, RTA_MAX, (struct nlattr *) RTNH_DATA(rtnh),
02474                                           rtnh->rtnh_len - sizeof(struct rtnexthop), NULL
02475                                          );                             
02476                                 if ( rtnhtb[RTA_GATEWAY] ) 
02477                                 {
02478                                     nic_rtnh->gw = 
02479                                         ip_addr_binary
02480                                         (   nla_data( (void*) rtnhtb[RTA_GATEWAY] ),
02481                                             nla_len ( (void*) rtnhtb[RTA_GATEWAY] )
02482                                         );
02483                                 }
02484                             }
02485                         }
02486                     }
02487                 }
02488 
02489                 n_routes++;
02490 
02491                 RT_t  **prt=0, *trt=0L, *frt=rt, *nrt = 0L;
02492 
02493                 if( rt == 0 )
02494                 {
02495                     nrt = calloc(1, sizeof(struct nic_route_s));
02496                     if( nrt == 0L )
02497                     {
02498                         eprintf(NIC_ERR, "nic_get_routes: out of memory.");
02499                         goto rta_return;
02500                     }
02501                     *nrt= *rtp;
02502                     eprintf(NIC_DEBUG," new route %p - rta: %p rtp->nh: %p", nrt, rta, nrt->nh);
02503                     trt =  rtp;
02504                     rtp =  nrt;
02505                     nrt =  trt;
02506                     trt =  0;
02507                 }
02508                 
02509                 if( (nh->nic_route_tree == 0L)
02510                   ||((prt = tfind(rtp, &(nh->nic_route_tree), nic_route_comparator)) == 0L)
02511                   )
02512                 {
02513                     tsearch(rtp, &(nh->nic_route_tree), nic_route_comparator);
02514                     eprintf(NIC_DEBUG," route tsearch %p - nh: %p", rtp, rtp->nh);
02515                 }
02516                 
02517                 if( prt != 0L )
02518                 {
02519                     trt = *prt;
02520                     *trt = *rtp;
02521                     frt =  trt;
02522                     eprintf(NIC_DEBUG," route found %p - freeing %p", trt, rtp);
02523                     if( nrt )
02524                         free(rtp);
02525                 }
02526 
02527                 if( rt == 0L )
02528                     rtp = &srt;
02529                 else
02530                 if( nic_route_comparator( frt , rtp ) == 0 )
02531                     goto rta_return;
02532                 
02533                 hdr = nlmsg_next( hdr, &remaining );
02534 
02535             } while ( remaining > 0 );  
02536 
02537         }else
02538         {
02539             eprintf(NIC_ERR,"nic_get_routes: netlink recv failed: %s %d\n", 
02540                     nl_get_errno(), nl_geterror());
02541             goto rta_return;
02542         }
02543     } while ( (hdr->nlmsg_type == RTM_NEWROUTE) && (remaining > 0) );
02544 
02545 rta_return:
02546     if( buf )
02547         free(buf);
02548     nlmsg_free(msg);
02549     return n_routes;        
02550 
02551 nla_put_failure:
02552     nlmsg_free(msg);
02553     return n_routes;
02554 }
02555 
02556 struct nic_route_cbarg
02557 {
02558     IProute_handler_t cb;
02559     void        *arg;
02560 };
02561 
02562 static void nic_route_twalker( const void *p, const VISIT which, const int depth )
02563 {
02564     struct nic_route_s *route, *const*app=p;
02565     struct nic_route_cbarg *cb;
02566 
02567     if( (app == 0L)    || ((route = *app) == 0L)
02568       ||(route->nh == 0) || (route->nh->nic_route_foreach_arg == 0 )
02569       ||( (which != postorder) && (which != leaf) )
02570       ) return;
02571 
02572     cb = route->nh->nic_route_foreach_arg;
02573  
02574     cb->cb( route->nh, route, cb->arg );       
02575 }
02576 
02577 void nic_route_foreach(NLH_t nh, IProute_handler_t handler,  void *arg)
02578 {
02579     struct nic_route_cbarg cb = { handler, arg };
02580 
02581     if ( nh->nic_route_foreach_arg )
02582         return;
02583 
02584     nh->nic_route_foreach_arg = &cb;
02585 
02586     nic_get_routes(nh, 0L);
02587 
02588     if( nh->nic_route_tree )
02589         twalk( nh->nic_route_tree, nic_route_twalker);
02590 
02591     nh->nic_route_foreach_arg = 0L;
02592 }
02593 
02594 int32_t nic_route_get_table(IProute_t rt)
02595 {
02596     if( rt == 0L ) return 0;
02597     return rt->rt.rtm.rtm_table;
02598 }
02599 
02600 void nic_route_set_table(IProute_t rt, uint8_t table)
02601 {
02602     if(rt == 0L) return;
02603     rt->rt.rtm.rtm_table = table;
02604 }
02605 
02606 char *nic_route_get_table_name( int32_t table, char *buf, int len )
02607 {
02608     return rtnl_route_table2str( table, buf, len );
02609 }
02610 
02611 extern
02612 int32_t nic_route_get_table_number( char *table )
02613 {
02614     return rtnl_route_str2table( table );
02615 }
02616 
02617 uint8_t nic_route_get_family( IProute_t rt)
02618 {
02619     if( rt == 0L ) return 0;
02620     
02621     return rt->rt.rtm.rtm_family;
02622 }
02623 
02624 uint8_t nic_route_get_scope(IProute_t rt)
02625 {
02626     if( rt == 0L ) return 0;
02627     return rt->rt.rtm.rtm_scope;
02628 }
02629 
02630 void nic_route_set_scope(IProute_t rt, uint8_t scope)
02631 {
02632     if( rt == 0L ) return;
02633     rt->rt.rtm.rtm_scope = scope;
02634 }
02635 
02636 uint32_t nic_route_get_flags( IProute_t rt )
02637 {
02638     if( rt == 0L ) return 0;
02639     return rt->rt.rtm.rtm_flags;   
02640 }
02641 
02642 void nic_route_set_flags(IProute_t rt, uint32_t flags)
02643 {
02644     if( rt == 0L ) return;
02645     rt->rt.rtm.rtm_flags = flags;
02646 }
02647 
02648 uint8_t nic_route_get_dst_len( IProute_t rt )
02649 {
02650     if( rt == 0L ) return 0;
02651     return rt->rt.rtm.rtm_dst_len;   
02652 }
02653 
02654 void nic_route_set_dst_len( IProute_t rt, uint8_t dst_len )
02655 {
02656     if( rt == 0L ) return;
02657     rt->rt.rtm.rtm_dst_len = dst_len;   
02658 }
02659 
02660 uint8_t nic_route_get_src_len( IProute_t rt )
02661 {
02662     if( rt == 0L ) return 0;
02663     return rt->rt.rtm.rtm_src_len;   
02664 }
02665 
02666 void nic_route_set_src_len( IProute_t rt, uint8_t src_len )
02667 {
02668     if( rt == 0L ) return;
02669     rt->rt.rtm.rtm_src_len = src_len;   
02670 }
02671 
02672 uint8_t nic_route_get_type( IProute_t rt)
02673 {
02674     if( rt == 0L ) return 0;
02675     return rt->rt.rtm.rtm_type;
02676 }
02677 
02678 void nic_route_set_type( IProute_t rt, uint8_t type )
02679 {    
02680     if( rt == 0L ) return;
02681     rt->rt.rtm.rtm_type = type;
02682 }
02683 
02684 uint8_t nic_route_get_protocol( IProute_t rt)
02685 {
02686     if( rt == 0L ) return 0;
02687     return rt->rt.rtm.rtm_protocol;
02688 }
02689 
02690 void nic_route_set_protocol( IProute_t rt, uint8_t protocol )
02691 {    
02692     if( rt == 0L ) return;
02693     rt->rt.rtm.rtm_protocol = protocol;
02694 }
02695 
02696 uint8_t nic_route_get_tos( IProute_t rt)
02697 {
02698     if( rt == 0L ) return 0;
02699     return rt->rt.rtm.rtm_tos;
02700 }
02701 
02702 void nic_route_set_tos( IProute_t rt, uint8_t tos )
02703 {    
02704     if( rt == 0L ) return;
02705     rt->rt.rtm.rtm_protocol = tos;
02706 }
02707 
02708 ip_addr_t nic_route_get_dst( IProute_t rt )
02709 {
02710     ip_addr_t ip;
02711     memset(&ip,'\0',sizeof(ip));
02712     if( ( rt == 0L ) 
02713       ||((rt->rt.have & NIC_RT_DST)==0)
02714       ) return ip;
02715     return rt->rt.dst;
02716 }
02717 
02718 void nic_route_set_dst( IProute_t rt, ip_addr_t ip)
02719 {
02720     if( rt == 0L ) return;
02721     rt->rt.dst = ip;
02722     rt->rt.have |= NIC_RT_DST;
02723 }
02724 
02725 ip_addr_t nic_route_get_gateway( IProute_t rt )
02726 {
02727     ip_addr_t ip;
02728     memset(&ip,'\0',sizeof(ip));
02729     if( ( rt == 0L ) 
02730       ||((rt->rt.have & NIC_RT_GATEWAY)==0)
02731       ) return ip;
02732     return rt->rt.gw;
02733 }
02734 
02735 void nic_route_set_gateway( IProute_t rt, ip_addr_t ip)
02736 {
02737     if( rt == 0L ) return;
02738     rt->rt.gw = ip;
02739     rt->rt.have |= NIC_RT_GATEWAY;
02740 }
02741 
02742 ip_addr_t nic_route_get_src( IProute_t rt )
02743 {
02744     ip_addr_t ip;
02745     memset(&ip,'\0',sizeof(ip));
02746     if( ( rt == 0L ) 
02747       ||((rt->rt.have & NIC_RT_SRC)==0)
02748       ) return ip;
02749     return rt->rt.src;
02750 }
02751 
02752 void nic_route_set_src( IProute_t rt, ip_addr_t ip)
02753 {
02754     if( rt == 0L ) return;
02755     rt->rt.src = ip;
02756     rt->rt.have |= NIC_RT_SRC;
02757 }
02758 
02759 ip_addr_t nic_route_get_prefsrc( IProute_t rt )
02760 {
02761     ip_addr_t ip;
02762     memset(&ip,'\0',sizeof(ip));
02763     if( ( rt == 0L ) 
02764       ||((rt->rt.have & NIC_RT_PREFSRC)==0)
02765       ) return ip;
02766     return rt->rt.prefsrc;
02767 }
02768 
02769 void nic_route_set_prefsrc( IProute_t rt, ip_addr_t ip)
02770 {
02771     if( rt == 0L ) return;
02772     rt->rt.prefsrc = ip;
02773     rt->rt.have |= NIC_RT_PREFSRC;
02774 }
02775 
02776 int16_t nic_route_get_oif( IProute_t rt )
02777 {
02778     if( ( rt == 0L ) 
02779       ||((rt->rt.have & NIC_RT_OIF)==0)
02780       ) return -1;
02781     
02782     return rt->rt.oif;
02783 }
02784 
02785 void nic_route_set_oif( IProute_t rt, uint16_t oif)
02786 {
02787     if( rt == 0L ) return ;
02788     
02789     rt->rt.oif = oif;
02790     rt->rt.have |= NIC_RT_OIF;
02791 }
02792 
02793 NIC_if_name_t nic_route_get_iif( IProute_t rt )
02794 {
02795     NIC_if_name_t nil = { { '\0' } };
02796     if( ( rt == 0L )
02797       ||((rt->rt.have & NIC_RT_IIF) == 0 )
02798       ) return nil;
02799     
02800     return *((NIC_if_name_t*)&(rt->rt.iif[0]));
02801 }
02802 
02803 void nic_route_set_iif( IProute_t rt, char *iif )
02804 {
02805     if( rt == 0 ) return;
02806     
02807     strncpy(&(rt->rt.iif[0]), iif, IFNAMSIZ);   
02808     rt->rt.have |= NIC_RT_IIF;
02809 }
02810 
02811 uint32_t nic_route_get_priority( IProute_t rt )
02812 {
02813     if( ( rt == 0L )
02814       ||((rt->rt.have & NIC_RT_PRIORITY) == 0 )
02815       ) return 0;
02816     
02817     return rt->rt.priority;
02818 }
02819 
02820 void nic_route_set_priority( IProute_t rt, uint32_t priority)
02821 {
02822     if( rt == 0L ) return;
02823     
02824     rt->rt.priority = priority;
02825     rt->rt.have |= NIC_RT_PRIORITY;
02826 }
02827 
02828 extern
02829 uint32_t nic_route_get_protoinfo(IProute_t rt)
02830 {
02831     if( ( rt == 0L )
02832       ||((rt->rt.have & NIC_RT_PROTOINFO) == 0 )
02833       ) return 0;
02834     
02835     return rt->rt.protoinfo;
02836 }
02837 
02838 extern
02839 void nic_route_set_protoinfo(IProute_t rt, uint32_t protoinfo)
02840 {
02841     if( rt == 0L ) return;
02842     rt->rt.protoinfo = protoinfo;
02843     rt->rt.have |= NIC_RT_PROTOINFO;
02844 }
02845 
02846 uint32_t nic_route_get_session(IProute_t rt)
02847 {
02848     if( ( rt == 0L )
02849       ||((rt->rt.have & NIC_RT_SESSION) == 0 )
02850       ) return 0;
02851     
02852     return rt->rt.session;
02853 }
02854 
02855 extern
02856 void nic_route_set_session(IProute_t rt, uint32_t session)
02857 {
02858     if( rt == 0L ) return;
02859     rt->rt.session = session;
02860     rt->rt.have |= NIC_RT_SESSION;
02861 }
02862 
02863 uint32_t nic_route_get_flow(IProute_t rt)
02864 {
02865     if( ( rt == 0L )
02866       ||((rt->rt.have & NIC_RT_FLOW) == 0 )
02867       ) return 0;
02868     
02869     return rt->rt.flow;
02870 }
02871 
02872 void nic_route_set_flow(IProute_t rt, uint32_t flow)
02873 {
02874     if( rt == 0L ) return;
02875     rt->rt.flow = flow;
02876     rt->rt.have |= NIC_RT_FLOW;
02877 }
02878 
02879 uint32_t nic_route_get_mp_algo(IProute_t rt)
02880 {
02881     if( ( rt == 0L )
02882       ||((rt->rt.have & NIC_RT_MP_ALGO) == 0 )
02883       ) return 0;
02884     
02885     return rt->rt.mp_algo;
02886 }
02887 
02888 void nic_route_set_mp_algo(IProute_t rt, uint32_t mp_algo)
02889 {
02890     if( rt == 0L ) return;
02891     rt->rt.mp_algo = mp_algo;
02892     rt->rt.have |= NIC_RT_MP_ALGO;
02893 }
02894 
02895 IProute_t nic_route_new
02896 (   NLH_t nh,
02897     int16_t oif,          /* output interface: -1 means none */
02898     ip_addr_t *dst,       /* 0L here means DEFAULT ROUTE */ 
02899     uint8_t dst_len,      /* dst_len ignored for default route */
02900     ip_addr_t *gw,        /* 0L here means no gateway */
02901     int8_t type,          /* -1: default: RTN_UNICAST */
02902     int8_t protocol,      /* -1: default: RTPROT_BOOT */
02903     int8_t scope,         /* -1=UNIVERSE,LINK=253,SITE=200,HOST=254 */
02904     int32_t priority,     /* metric - -1 means no priority */
02905     int32_t table,        /* table: -1 selects default: "local" */
02906     char*   iif,          /* input interface: 0 means none */
02907     ip_addr_t *src,       /* 0L here means no src route */
02908     uint8_t  src_len      /* 0 here means no src route */
02909 )
02910 {
02911     if( ( dst && (dst->sa_family != AF_INET) && (dst->sa_family != AF_INET6))
02912       ||( gw && (gw->sa_family != AF_INET) && (gw->sa_family != AF_INET6))
02913       ||( src && (src->sa_family != AF_INET) && (src->sa_family != AF_INET6))
02914       )
02915         return 0L;
02916         
02917     IProute_t rt = calloc(1, sizeof(struct nic_route_s));
02918 
02919     if(rt == 0L)
02920         return rt;
02921 
02922     rt->nh = nh;
02923 
02924 
02925     if ( dst == 0L )
02926     { /* default route */
02927         dst_len = 0;
02928         table = RT_TABLE_MAIN;
02929     }else
02930     {
02931         rt->rt.rtm.rtm_dst_len = dst_len;
02932         rt->rt.dst = *dst;
02933         rt->rt.rtm.rtm_family = dst->sa_family;
02934         rt->rt.have |= NIC_RT_DST;
02935     }
02936 
02937     if( gw  )
02938     {   
02939         rt->rt.gw = *gw;
02940         rt->rt.have |= NIC_RT_GATEWAY;
02941         if( rt->rt.rtm.rtm_family == 0 )
02942             rt->rt.rtm.rtm_family = rt->rt.gw.sa_family;
02943     }
02944 
02945     if( scope == -1 )
02946         rt->rt.rtm.rtm_scope = RT_SCOPE_UNIVERSE;
02947     else
02948         rt->rt.rtm.rtm_scope = scope;
02949     
02950     if( table == -1 )
02951         rt->rt.rtm.rtm_table = RT_TABLE_LOCAL;
02952     else
02953         rt->rt.rtm.rtm_table = table;
02954 
02955     if( type == -1 )
02956         rt->rt.rtm.rtm_type = RTN_UNICAST;
02957 
02958     if( protocol == -1 )
02959         rt->rt.rtm.rtm_protocol = RTPROT_BOOT;
02960 
02961     if( oif > -1 )
02962     {
02963         rt->rt.oif = oif;
02964         rt->rt.have |= NIC_RT_OIF;
02965     }
02966    
02967     if( iif )
02968     {
02969         strncpy(&(rt->rt.iif[0]), iif, IFNAMSIZ);
02970         rt->rt.have |= NIC_RT_IIF;
02971     }
02972 
02973     if( src && src_len )
02974     {   
02975         rt->rt.src = *src;
02976         rt->rt.have |= NIC_RT_SRC;
02977         if( rt->rt.rtm.rtm_family == 0 )
02978             rt->rt.rtm.rtm_family = rt->rt.src.sa_family;
02979     }
02980 
02981     if( priority > -1 )
02982     {
02983         rt->rt.priority = priority;
02984         rt->rt.have |= NIC_RT_PRIORITY;
02985     }
02986     return rt;
02987 }
02988 
02989 static NIC_Res_t nic_route_msg( IProute_t rt, char *fn, char *tag, uint32_t msg_type, uint32_t msg_flags)
02990 {
02991     NLH_t nh = rt->nh;
02992     /* libnl as yet provides no support for route creation / deletion / modification.
02993      */
02994     struct nl_msg *msg = nlmsg_build_simple(msg_type, msg_flags) ;
02995     if( msg == 0L )
02996     {
02997         eprintf(NIC_ERR,"%s: failed to %s route - out of memory.", tag, fn);
02998         return NIC_FAIL;
02999     }
03000     
03001     if ( nlmsg_append(msg, &(rt->rt.rtm), sizeof(struct rtmsg), 1) < 0 )
03002         goto nla_put_failure;
03003 
03004     if( rt->rt.have & NIC_RT_OIF )
03005         NLA_PUT_U32(msg, RTA_OIF, rt->rt.oif);
03006     
03007     if ( rt->rt.have & NIC_RT_DST )
03008         NLA_PUT(msg, RTA_DST, IP_ADDR_SIZE(&(rt->rt.dst)), IP_ADDR(&(rt->rt.dst)));
03009 
03010     if ( rt->rt.have & NIC_RT_GATEWAY )
03011         NLA_PUT(msg, RTA_GATEWAY, IP_ADDR_SIZE(&(rt->rt.gw)), IP_ADDR(&(rt->rt.gw)));
03012 
03013     if( rt->rt.have & NIC_RT_IIF )
03014         NLA_PUT_STRING(msg, RTA_IIF, &(rt->rt.iif[0]));
03015 
03016     if ( rt->rt.have & NIC_RT_SRC )
03017         NLA_PUT(msg, RTA_SRC, IP_ADDR_SIZE(&(rt->rt.src)), IP_ADDR(&(rt->rt.src)));
03018 
03019     if ( rt->rt.have & NIC_RT_PREFSRC )
03020         NLA_PUT(msg, RTA_SRC, IP_ADDR_SIZE(&(rt->rt.prefsrc)), IP_ADDR(&(rt->rt.prefsrc)));
03021 
03022     if ( rt->rt.have & NIC_RT_PRIORITY )
03023         NLA_PUT_U32(msg, RTA_PRIORITY, rt->rt.priority);
03024     
03025     if ( rt->rt.have & NIC_RT_FLOW )
03026         NLA_PUT_U32(msg, RTA_FLOW, rt->rt.flow);
03027     
03028     if ( rt->rt.have & NIC_RT_SESSION )
03029         NLA_PUT_U32(msg, RTA_SESSION, rt->rt.session);
03030 
03031     if ( rt->rt.have & NIC_RT_MP_ALGO )
03032         NLA_PUT_U32(msg, RTA_MP_ALGO, rt->rt.mp_algo);
03033     
03034     if( nl_send_auto_complete(rt->nh->nl, nlmsg_hdr(msg)) < 0 )
03035     {
03036         eprintf(NIC_ERR,"%s: send failed - %d %s", tag, nl_get_errno(),
03037                 nl_geterror());
03038         return NIC_FAIL;
03039     }
03040 
03041     nlmsg_free(msg);
03042 
03043     if( nl_wait_for_ack(rt->nh->nl) < 0 )
03044     {
03045         eprintf(NIC_ERR,"%s: failed - %d: %s", tag, nl_get_errno(),
03046                 nl_geterror());
03047         return NIC_FAIL;        
03048     }
03049     
03050     return NIC_OK;
03051 
03052 nla_put_failure:
03053 
03054     eprintf(NIC_ERR,"%s: failed to %s route - out of memory.", tag, fn);
03055     nlmsg_free(msg);
03056     return NIC_FAIL;
03057 }
03058 
03059 NIC_Res_t nic_add_route( IProute_t rt )
03060 { 
03061     if (rt == 0L) return NIC_FAIL;
03062 
03063     return nic_route_msg( rt, "nic_add_route", "add", RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE);
03064 }
03065 
03066 NIC_Res_t nic_update_route( IProute_t rt )
03067 { 
03068     if (rt == 0L) return NIC_FAIL;
03069 
03070     return nic_route_msg( rt, "nic_update_route", "update", RTM_NEWROUTE, NLM_F_REPLACE);
03071 }
03072 
03073 NIC_Res_t nic_remove_route( IProute_t rt )
03074 { 
03075     if (rt == 0L) return NIC_FAIL;
03076 
03077     return nic_route_msg( rt, "nic_remove_route", "remove", RTM_DELROUTE, 0);
03078 }
03079 
03080 IProute_list_t *nic_route_list_new( IProute_t rt1, ... )
03081 {      
03082     va_list va;
03083     NLH_t nh = rt1->nh;
03084     va_start(va, rt1);
03085     
03086     IProute_list_t *head = calloc(1,sizeof(IProute_list_t));
03087     IProute_list_node_t *n;
03088     IProute_t rt;
03089 
03090     if( head == 0 )
03091     {
03092         va_end(va);
03093         eprintf(NIC_ERR, "out of memory" );
03094         return 0;
03095     }
03096     rt=rt1;
03097     STAILQ_INIT(head);
03098     do
03099     {
03100         n = calloc(1,sizeof(IProute_list_node_t));
03101         if ( n == 0L )
03102         {
03103             va_end(va);
03104             free(head);
03105             eprintf(NIC_ERR, "out of memory");
03106             return 0L;
03107         }
03108         n->route = rt;
03109         STAILQ_INSERT_TAIL( head, n, link );
03110     }while( (rt = va_arg(va, IProute_t)) != 0) ;
03111     va_end(va);
03112     return(head);
03113 }
03114 
03115 void nic_route_list_free( IProute_list_t *head )
03116 {
03117     IProute_list_node_t *n, *a;
03118     
03119     if ( !STAILQ_EMPTY(head) )
03120     {
03121         n = STAILQ_FIRST( head );
03122         do
03123         {
03124             a = STAILQ_NEXT(n, link);
03125             nic_route_free(n->route);
03126             free(n);
03127             n = a;
03128         }while (n);
03129     }
03130 }
03131 
03132 NIC_Res_t nic_add_routes( IProute_list_t *head )
03133 {
03134     IProute_list_node_t *n;
03135     NIC_Res_t r;
03136     STAILQ_FOREACH(n,head,link)
03137     {
03138         if((r=nic_add_route(n->route)) == NIC_FAIL)
03139             return r;
03140     }
03141     return NIC_OK;
03142 }
03143 
03144 NIC_Res_t nic_remove_routes( IProute_list_t *head )
03145 {
03146     IProute_list_node_t *n;
03147     NIC_Res_t r;
03148     STAILQ_FOREACH(n,head,link)
03149     {
03150         if((r=nic_remove_route(n->route))==NIC_FAIL)
03151             return r;
03152     }
03153     return NIC_OK;
03154 }
03155 
03156 NIC_Res_t nic_update_routes( IProute_list_t *head )
03157 {
03158     IProute_list_node_t *n;
03159     NIC_Res_t r;
03160     STAILQ_FOREACH(n,head,link)
03161     {
03162         if((r=nic_update_route(n->route))==NIC_FAIL)
03163             return r;
03164     }
03165     return NIC_OK;
03166 }
03167 
03168 void nic_route_free(void *rtp)
03169 {
03170     IProute_t rt = rtp;
03171 
03172     if (!rt)
03173         return;
03174     
03175     if( rt->nh->nic_route_tree )
03176         tdelete(rt, &(rt->nh->nic_route_tree), nic_route_comparator);
03177     
03178     if( rt->rt.hops )
03179         free(rt->rt.hops);
03180 
03181     free(rt);
03182 }
03183 
03184 extern
03185 NIC_Res_t 
03186 nic_set_hostname
03187 ( NLH_t nh,
03188   char *hostname
03189 )
03190 {
03191     return sethostname(hostname, strlen(hostname)) == 0 ? NIC_OK : NIC_FAIL;
03192 }
03193 
03194 NIC_Res_t 
03195 nic_configure
03196 (
03197     NLH_t          nh,
03198     NIC_t          nic,
03199     IPaddr_list_t  *addresses,
03200     IProute_list_t *routes,
03201     IPaddr_list_t  *dns_servers,
03202     char           *search_list,
03203     char           *host_name
03204 )
03205 {
03206     if ( addresses && ( nic_add_addresses( nic, addresses ) == NIC_FAIL ))
03207     {
03208         eprintf(NIC_ERR, "nic_configure: failed to add addresses.");
03209         return NIC_FAIL;
03210     }
03211      
03212     if ( routes && ( nic_add_routes( routes ) == NIC_FAIL ))
03213     {
03214         eprintf(NIC_ERR, "nic_configure: failed to add routes.");
03215         return NIC_FAIL;
03216     }
03217 
03218     return NIC_OK;
03219 }
03220 
03221 /*
03222  * vim:ts=8:sw=4:sts=4:et
03223  */

Generated on Mon Aug 14 17:25:56 2006 for libdhcp by  doxygen 1.4.7