nmbd/nmbd_namelistdb.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    NBT netbios routines and daemon - version 2
00004    Copyright (C) Andrew Tridgell 1994-1998
00005    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
00006    Copyright (C) Jeremy Allison 1994-2003
00007    
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017    
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021    
00022 */
00023 
00024 #include "includes.h"
00025 
00026 uint16 samba_nb_type = 0; /* samba's NetBIOS name type */
00027 
00028 
00029 /**************************************************************************
00030  Set Samba's NetBIOS name type.
00031 ***************************************************************************/
00032 
00033 void set_samba_nb_type(void)
00034 {
00035         if( lp_wins_support() || wins_srv_count() ) {
00036                 samba_nb_type = NB_HFLAG;               /* samba is a 'hybrid' node type. */
00037         } else {
00038                 samba_nb_type = NB_BFLAG;           /* samba is broadcast-only node type. */
00039         }
00040 }
00041 
00042 /***************************************************************************
00043  Convert a NetBIOS name to upper case.
00044 ***************************************************************************/
00045 
00046 static void upcase_name( struct nmb_name *target, const struct nmb_name *source )
00047 {
00048         int i;
00049         unstring targ;
00050         fstring scope;
00051 
00052         if( NULL != source ) {
00053                 memcpy( target, source, sizeof( struct nmb_name ) );
00054         }
00055 
00056         pull_ascii_nstring(targ, sizeof(targ), target->name);
00057         strupper_m( targ );
00058         push_ascii_nstring( target->name, targ);
00059 
00060         pull_ascii(scope, target->scope, 64, -1, STR_TERMINATE);
00061         strupper_m( scope );
00062         push_ascii(target->scope, scope, 64, STR_TERMINATE);
00063 
00064         /* fudge... We're using a byte-by-byte compare, so we must be sure that
00065          * unused space doesn't have garbage in it.
00066          */
00067 
00068         for( i = strlen( target->name ); i < sizeof( target->name ); i++ ) {
00069                 target->name[i] = '\0';
00070         }
00071         for( i = strlen( target->scope ); i < sizeof( target->scope ); i++ ) {
00072                 target->scope[i] = '\0';
00073         }
00074 }
00075 
00076 /**************************************************************************
00077  Remove a name from the namelist.
00078 ***************************************************************************/
00079 
00080 void remove_name_from_namelist(struct subnet_record *subrec, 
00081                                 struct name_record *namerec )
00082 {
00083         if (subrec == wins_server_subnet) 
00084                 remove_name_from_wins_namelist(namerec);
00085         else {
00086                 subrec->namelist_changed = True;
00087                 DLIST_REMOVE(subrec->namelist, namerec);
00088         }
00089 
00090         SAFE_FREE(namerec->data.ip);
00091         ZERO_STRUCTP(namerec);
00092         SAFE_FREE(namerec);
00093 }
00094 
00095 /**************************************************************************
00096  Find a name in a subnet.
00097 **************************************************************************/
00098 
00099 struct name_record *find_name_on_subnet(struct subnet_record *subrec,
00100                                 const struct nmb_name *nmbname,
00101                                 BOOL self_only)
00102 {
00103         struct nmb_name uc_name;
00104         struct name_record *name_ret;
00105 
00106         upcase_name( &uc_name, nmbname );
00107         
00108         if (subrec == wins_server_subnet) {
00109                 return find_name_on_wins_subnet(&uc_name, self_only);
00110         }
00111 
00112         for( name_ret = subrec->namelist; name_ret; name_ret = name_ret->next) {
00113                 if (memcmp(&uc_name, &name_ret->name, sizeof(struct nmb_name)) == 0) {
00114                         break;
00115                 }
00116         }
00117 
00118         if( name_ret ) {
00119                 /* Self names only - these include permanent names. */
00120                 if( self_only && (name_ret->data.source != SELF_NAME) && (name_ret->data.source != PERMANENT_NAME) ) {
00121                         DEBUG( 9, ( "find_name_on_subnet: on subnet %s - self name %s NOT FOUND\n",
00122                                                 subrec->subnet_name, nmb_namestr(nmbname) ) );
00123                         return NULL;
00124                 }
00125 
00126                 DEBUG( 9, ("find_name_on_subnet: on subnet %s - found name %s source=%d\n",
00127                         subrec->subnet_name, nmb_namestr(nmbname), name_ret->data.source) );
00128 
00129                 return name_ret;
00130         }
00131 
00132         DEBUG( 9, ( "find_name_on_subnet: on subnet %s - name %s NOT FOUND\n",
00133                 subrec->subnet_name, nmb_namestr(nmbname) ) );
00134 
00135         return NULL;
00136 }
00137 
00138 /**************************************************************************
00139  Find a name over all known broadcast subnets.
00140 ************************************************************************/
00141 
00142 struct name_record *find_name_for_remote_broadcast_subnet(struct nmb_name *nmbname,
00143                                                 BOOL self_only)
00144 {
00145         struct subnet_record *subrec;
00146         struct name_record *namerec;
00147 
00148         for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) ) {
00149                 namerec = find_name_on_subnet(subrec, nmbname, self_only);
00150                 if (namerec) {
00151                         return namerec;
00152                 }
00153         }
00154 
00155         return NULL;
00156 }
00157   
00158 /**************************************************************************
00159  Update the ttl of an entry in a subnet name list.
00160 ***************************************************************************/
00161 
00162 void update_name_ttl( struct name_record *namerec, int ttl )
00163 {
00164         time_t time_now = time(NULL);
00165 
00166         if( namerec->data.death_time != PERMANENT_TTL) {
00167                 namerec->data.death_time = time_now + ttl;
00168         }
00169 
00170         namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
00171 
00172         if (namerec->subnet == wins_server_subnet) {
00173                 wins_store_changed_namerec(namerec);
00174         } else {
00175                 namerec->subnet->namelist_changed = True;
00176         }
00177 }
00178 
00179 /**************************************************************************
00180  Add an entry to a subnet name list.
00181 ***********************************************************************/
00182 
00183 BOOL add_name_to_subnet( struct subnet_record *subrec,
00184                         const char *name,
00185                         int type,
00186                         uint16 nb_flags,
00187                         int ttl,
00188                         enum name_source source,
00189                         int num_ips,
00190                         struct in_addr *iplist)
00191 {
00192         BOOL ret = False;
00193         struct name_record *namerec;
00194         time_t time_now = time(NULL);
00195 
00196         namerec = SMB_MALLOC_P(struct name_record);
00197         if( NULL == namerec ) {
00198                 DEBUG( 0, ( "add_name_to_subnet: malloc fail.\n" ) );
00199                 return False;
00200         }
00201 
00202         memset( (char *)namerec, '\0', sizeof(*namerec) );
00203         namerec->data.ip = SMB_MALLOC_ARRAY( struct in_addr, num_ips );
00204         if( NULL == namerec->data.ip ) {
00205                 DEBUG( 0, ( "add_name_to_subnet: malloc fail when creating ip_flgs.\n" ) );
00206                 ZERO_STRUCTP(namerec);
00207                 SAFE_FREE(namerec);
00208                 return False;
00209         }
00210 
00211         namerec->subnet = subrec;
00212 
00213         make_nmb_name(&namerec->name, name, type);
00214         upcase_name(&namerec->name, NULL );
00215 
00216         /* Enter the name as active. */
00217         namerec->data.nb_flags = nb_flags | NB_ACTIVE;
00218         namerec->data.wins_flags = WINS_ACTIVE;
00219 
00220         /* If it's our primary name, flag it as so. */
00221         if (strequal( my_netbios_names(0), name )) {
00222                 namerec->data.nb_flags |= NB_PERM;
00223         }
00224 
00225         /* Copy the IPs. */
00226         namerec->data.num_ips = num_ips;
00227         memcpy( (namerec->data.ip), iplist, num_ips * sizeof(struct in_addr) );
00228 
00229         /* Data source. */
00230         namerec->data.source = source;
00231 
00232         /* Setup the death_time and refresh_time. */
00233         if (ttl == PERMANENT_TTL) {
00234                 namerec->data.death_time = PERMANENT_TTL;
00235         } else {
00236                 namerec->data.death_time = time_now + ttl;
00237         }
00238 
00239         namerec->data.refresh_time = time_now + MIN((ttl/2), MAX_REFRESH_TIME);
00240 
00241         DEBUG( 3, ( "add_name_to_subnet: Added netbios name %s with first IP %s \
00242 ttl=%d nb_flags=%2x to subnet %s\n",
00243                 nmb_namestr( &namerec->name ),
00244                 inet_ntoa( *iplist ),
00245                 ttl,
00246                 (unsigned int)nb_flags,
00247                 subrec->subnet_name ) );
00248 
00249         /* Now add the record to the name list. */    
00250 
00251         if (subrec == wins_server_subnet) {
00252                 ret = add_name_to_wins_subnet(namerec);
00253                 /* Free namerec - it's stored in the tdb. */
00254                 SAFE_FREE(namerec->data.ip);
00255                 SAFE_FREE(namerec);
00256         } else {
00257                 DLIST_ADD(subrec->namelist, namerec);
00258                 subrec->namelist_changed = True;
00259                 ret = True;
00260         }
00261 
00262         return ret;
00263 }
00264 
00265 /*******************************************************************
00266  Utility function automatically called when a name refresh or register 
00267  succeeds. By definition this is a SELF_NAME (or we wouldn't be registering
00268  it).
00269  ******************************************************************/
00270 
00271 void standard_success_register(struct subnet_record *subrec, 
00272                              struct userdata_struct *userdata,
00273                              struct nmb_name *nmbname, uint16 nb_flags, int ttl,
00274                              struct in_addr registered_ip)
00275 {
00276         struct name_record *namerec;
00277 
00278         namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME);
00279         if (namerec == NULL) {
00280                 unstring name;
00281                 pull_ascii_nstring(name, sizeof(name), nmbname->name);
00282                 add_name_to_subnet( subrec, name, nmbname->name_type,
00283                         nb_flags, ttl, SELF_NAME, 1, &registered_ip );
00284         } else {
00285                 update_name_ttl( namerec, ttl );
00286         }
00287 }
00288 
00289 /*******************************************************************
00290  Utility function automatically called when a name refresh or register 
00291  fails. Note that this is only ever called on a broadcast subnet with
00292  one IP address per name. This is why it can just delete the name 
00293  without enumerating the IP adresses. JRA.
00294  ******************************************************************/
00295 
00296 void standard_fail_register( struct subnet_record   *subrec,
00297                              struct nmb_name        *nmbname )
00298 {
00299         struct name_record *namerec;
00300 
00301         namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME);
00302 
00303         DEBUG( 0, ( "standard_fail_register: Failed to register/refresh name %s \
00304 on subnet %s\n", nmb_namestr(nmbname), subrec->subnet_name) );
00305 
00306         /* Remove the name from the subnet. */
00307         if( namerec ) {
00308                 remove_name_from_namelist(subrec, namerec);
00309         }
00310 }
00311 
00312 /*******************************************************************
00313  Utility function to remove an IP address from a name record.
00314  ******************************************************************/
00315 
00316 static void remove_nth_ip_in_record( struct name_record *namerec, int ind)
00317 {
00318         if( ind != namerec->data.num_ips ) {
00319                 memmove( (char *)(&namerec->data.ip[ind]),
00320                                 (char *)(&namerec->data.ip[ind+1]), 
00321                                 ( namerec->data.num_ips - ind - 1) * sizeof(struct in_addr) );
00322         }
00323 
00324         namerec->data.num_ips--;
00325         if (namerec->subnet == wins_server_subnet) {
00326                 wins_store_changed_namerec(namerec);
00327         } else {
00328                 namerec->subnet->namelist_changed = True;
00329         }
00330 }
00331 
00332 /*******************************************************************
00333  Utility function to check if an IP address exists in a name record.
00334  ******************************************************************/
00335 
00336 BOOL find_ip_in_name_record( struct name_record *namerec, struct in_addr ip )
00337 {
00338         int i;
00339 
00340         for(i = 0; i < namerec->data.num_ips; i++) {
00341                 if(ip_equal( namerec->data.ip[i], ip)) {
00342                         return True;
00343                 }
00344         }
00345 
00346         return False;
00347 }
00348 
00349 /*******************************************************************
00350  Utility function to add an IP address to a name record.
00351  ******************************************************************/
00352 
00353 void add_ip_to_name_record( struct name_record *namerec, struct in_addr new_ip )
00354 {
00355         struct in_addr *new_list;
00356 
00357         /* Don't add one we already have. */
00358         if( find_ip_in_name_record( namerec, new_ip )) {
00359                 return;
00360         }
00361   
00362         new_list = SMB_MALLOC_ARRAY( struct in_addr, namerec->data.num_ips + 1);
00363         if( NULL == new_list ) {
00364                 DEBUG(0,("add_ip_to_name_record: Malloc fail !\n"));
00365                 return;
00366         }
00367 
00368         memcpy( (char *)new_list, (char *)namerec->data.ip, namerec->data.num_ips * sizeof(struct in_addr) );
00369         new_list[namerec->data.num_ips] = new_ip;
00370 
00371         SAFE_FREE(namerec->data.ip);
00372         namerec->data.ip = new_list;
00373         namerec->data.num_ips += 1;
00374 
00375         if (namerec->subnet == wins_server_subnet) {
00376                 wins_store_changed_namerec(namerec);
00377         } else {
00378                 namerec->subnet->namelist_changed = True;
00379         }
00380 }
00381 
00382 /*******************************************************************
00383  Utility function to remove an IP address from a name record.
00384  ******************************************************************/
00385 
00386 void remove_ip_from_name_record( struct name_record *namerec,
00387                                  struct in_addr      remove_ip )
00388 {
00389         /* Try and find the requested ip address - remove it. */
00390         int i;
00391         int orig_num = namerec->data.num_ips;
00392 
00393         for(i = 0; i < orig_num; i++) {
00394                 if( ip_equal( remove_ip, namerec->data.ip[i]) ) {
00395                         remove_nth_ip_in_record( namerec, i);
00396                         break;
00397                 }
00398         }
00399 }
00400 
00401 /*******************************************************************
00402  Utility function that release_name callers can plug into as the
00403  success function when a name release is successful. Used to save
00404  duplication of success_function code.
00405  ******************************************************************/
00406 
00407 void standard_success_release( struct subnet_record   *subrec,
00408                                struct userdata_struct *userdata,
00409                                struct nmb_name        *nmbname,
00410                                struct in_addr          released_ip )
00411 {
00412         struct name_record *namerec;
00413 
00414         namerec = find_name_on_subnet( subrec, nmbname, FIND_ANY_NAME );
00415         if( namerec == NULL ) {
00416                 DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
00417 on subnet %s. Name was not found on subnet.\n", nmb_namestr(nmbname), inet_ntoa(released_ip),
00418                                 subrec->subnet_name) );
00419                 return;
00420         } else {
00421                 int orig_num = namerec->data.num_ips;
00422 
00423                 remove_ip_from_name_record( namerec, released_ip );
00424 
00425                 if( namerec->data.num_ips == orig_num ) {
00426                         DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
00427 on subnet %s. This ip is not known for this name.\n", nmb_namestr(nmbname), inet_ntoa(released_ip), subrec->subnet_name ) );
00428                 }
00429         }
00430 
00431         if( namerec->data.num_ips == 0 ) {
00432                 remove_name_from_namelist( subrec, namerec );
00433         }
00434 }
00435 
00436 /*******************************************************************
00437  Expires old names in a subnet namelist.
00438  NB. Does not touch the wins_subnet - no wins specific processing here.
00439 ******************************************************************/
00440 
00441 static void expire_names_on_subnet(struct subnet_record *subrec, time_t t)
00442 {
00443         struct name_record *namerec;
00444         struct name_record *next_namerec;
00445 
00446         for( namerec = subrec->namelist; namerec; namerec = next_namerec ) {
00447                 next_namerec = namerec->next;
00448                 if( (namerec->data.death_time != PERMANENT_TTL) && (namerec->data.death_time < t) ) {
00449                         if( namerec->data.source == SELF_NAME ) {
00450                                 DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF \
00451 name %s\n", subrec->subnet_name, nmb_namestr(&namerec->name) ) );
00452                                 namerec->data.death_time += 300;
00453                                 namerec->subnet->namelist_changed = True;
00454                                 continue;
00455                         }
00456 
00457                         DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n",
00458                                 subrec->subnet_name, nmb_namestr(&namerec->name)));
00459   
00460                         remove_name_from_namelist(subrec, namerec );
00461                 }
00462         }
00463 }
00464 
00465 /*******************************************************************
00466  Expires old names in all subnet namelists.
00467  NB. Does not touch the wins_subnet.
00468 ******************************************************************/
00469 
00470 void expire_names(time_t t)
00471 {
00472         struct subnet_record *subrec;
00473 
00474         for( subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) ) {
00475                 expire_names_on_subnet( subrec, t );
00476         }
00477 }
00478 
00479 /****************************************************************************
00480   Add the magic samba names, useful for finding samba servers.
00481   These go directly into the name list for a particular subnet,
00482   without going through the normal registration process.
00483   When adding them to the unicast subnet, add them as a list of
00484   all broadcast subnet IP addresses.
00485 **************************************************************************/
00486 
00487 void add_samba_names_to_subnet( struct subnet_record *subrec )
00488 {
00489         struct in_addr *iplist = &subrec->myip;
00490         int num_ips = 1;
00491 
00492         /* These names are added permanently (ttl of zero) and will NOT be refreshed.  */
00493 
00494         if( (subrec == unicast_subnet) || (subrec == wins_server_subnet) || (subrec == remote_broadcast_subnet) ) {
00495                 struct subnet_record *bcast_subrecs;
00496                 int i;
00497 
00498                 /* Create an IP list containing all our known subnets. */
00499 
00500                 num_ips = iface_count();
00501                 iplist = SMB_MALLOC_ARRAY( struct in_addr, num_ips);
00502                 if( NULL == iplist ) {
00503                         DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n"));
00504                         return;
00505                 }
00506 
00507                 for( bcast_subrecs = FIRST_SUBNET, i = 0; bcast_subrecs &&
00508                                 i < num_ips;
00509                                 bcast_subrecs = NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs), i++ ) {
00510                         iplist[i] = bcast_subrecs->myip;
00511                 }
00512                 num_ips = i;
00513         }
00514 
00515         add_name_to_subnet(subrec,"*",0x0,samba_nb_type, PERMANENT_TTL,
00516                                 PERMANENT_NAME, num_ips, iplist);
00517         add_name_to_subnet(subrec,"*",0x20,samba_nb_type,PERMANENT_TTL,
00518                                 PERMANENT_NAME, num_ips, iplist);
00519         add_name_to_subnet(subrec,"__SAMBA__",0x20,samba_nb_type,PERMANENT_TTL,
00520                                 PERMANENT_NAME, num_ips, iplist);
00521         add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL,
00522                                 PERMANENT_NAME, num_ips, iplist);
00523 
00524         if(iplist != &subrec->myip) {
00525                 SAFE_FREE(iplist);
00526         }
00527 }
00528 
00529 /****************************************************************************
00530  Dump a name_record struct.
00531 **************************************************************************/
00532 
00533 void dump_name_record( struct name_record *namerec, XFILE *fp)
00534 {
00535         const char *src_type;
00536         struct tm *tm;
00537         int i;
00538 
00539         x_fprintf(fp,"\tName = %s\t", nmb_namestr(&namerec->name));
00540         switch(namerec->data.source) {
00541                 case LMHOSTS_NAME:
00542                         src_type = "LMHOSTS_NAME";
00543                         break;
00544                 case WINS_PROXY_NAME:
00545                         src_type = "WINS_PROXY_NAME";
00546                         break;
00547                 case REGISTER_NAME:
00548                         src_type = "REGISTER_NAME";
00549                         break;
00550                 case SELF_NAME:
00551                         src_type = "SELF_NAME";
00552                         break;
00553                 case DNS_NAME:
00554                         src_type = "DNS_NAME";
00555                         break;
00556                 case DNSFAIL_NAME:
00557                         src_type = "DNSFAIL_NAME";
00558                         break;
00559                 case PERMANENT_NAME:
00560                         src_type = "PERMANENT_NAME";
00561                         break;
00562                 default:
00563                         src_type = "unknown!";
00564                         break;
00565         }
00566 
00567         x_fprintf(fp,"Source = %s\nb_flags = %x\t", src_type, namerec->data.nb_flags);
00568 
00569         if(namerec->data.death_time != PERMANENT_TTL) {
00570                 const char *asct;
00571                 tm = localtime(&namerec->data.death_time);
00572                 if (!tm) {
00573                         return;
00574                 }
00575                 asct = asctime(tm);
00576                 if (!asct) {
00577                         return;
00578                 }
00579                 x_fprintf(fp, "death_time = %s\t", asct);
00580         } else {
00581                 x_fprintf(fp, "death_time = PERMANENT\t");
00582         }
00583 
00584         if(namerec->data.refresh_time != PERMANENT_TTL) {
00585                 const char *asct;
00586                 tm = localtime(&namerec->data.refresh_time);
00587                 if (!tm) {
00588                         return;
00589                 }
00590                 asct = asctime(tm);
00591                 if (!asct) {
00592                         return;
00593                 }
00594                 x_fprintf(fp, "refresh_time = %s\n", asct);
00595         } else {
00596                 x_fprintf(fp, "refresh_time = PERMANENT\n");
00597         }
00598 
00599         x_fprintf(fp, "\t\tnumber of IPS = %d", namerec->data.num_ips);
00600         for(i = 0; i < namerec->data.num_ips; i++) {
00601                 x_fprintf(fp, "\t%s", inet_ntoa(namerec->data.ip[i]));
00602         }
00603 
00604         x_fprintf(fp, "\n\n");
00605         
00606 }
00607 
00608 /****************************************************************************
00609  Dump the contents of the namelists on all the subnets (including unicast)
00610  into a file. Initiated by SIGHUP - used to debug the state of the namelists.
00611 **************************************************************************/
00612 
00613 static void dump_subnet_namelist( struct subnet_record *subrec, XFILE *fp)
00614 {
00615         struct name_record *namerec;
00616         x_fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name);
00617         for( namerec = subrec->namelist; namerec; namerec = namerec->next) {
00618                 dump_name_record(namerec, fp);
00619         }
00620 }
00621 
00622 /****************************************************************************
00623  Dump the contents of the namelists on all the subnets (including unicast)
00624  into a file. Initiated by SIGHUP - used to debug the state of the namelists.
00625 **************************************************************************/
00626 
00627 void dump_all_namelists(void)
00628 {
00629         XFILE *fp; 
00630         struct subnet_record *subrec;
00631 
00632         fp = x_fopen(lock_path("namelist.debug"),O_WRONLY|O_CREAT|O_TRUNC, 0644);
00633      
00634         if (!fp) { 
00635                 DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
00636                         "namelist.debug",strerror(errno)));
00637                 return;
00638         }
00639       
00640         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
00641                 dump_subnet_namelist( subrec, fp );
00642         }
00643 
00644         if (!we_are_a_wins_client()) {
00645                 dump_subnet_namelist( unicast_subnet, fp );
00646         }
00647 
00648         if (remote_broadcast_subnet->namelist != NULL) {
00649                 dump_subnet_namelist( remote_broadcast_subnet, fp );
00650         }
00651 
00652         if (wins_server_subnet != NULL) {
00653                 dump_wins_subnet_namelist(fp );
00654         }
00655 
00656         x_fclose( fp );
00657 }

Sambaに対してSat Aug 29 21:23:08 2009に生成されました。  doxygen 1.4.7