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

Generated on Thu Aug 10 22:16:40 2006 for libdhcp by  doxygen 1.4.7