lots of changes to nmbd
[kai/samba.git] / source3 / namework.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    NBT netbios routines and daemon - version 2
5    Copyright (C) Andrew Tridgell 1994-1996
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21    Revision History:
22
23    14 jan 96: lkcl@pires.co.uk
24    added multiple workgroup domain master support
25
26 */
27
28 #include "includes.h"
29
30 extern int ClientNMB;
31 extern int ClientDGRAM;
32
33 #define TEST_CODE /* want to debug unknown browse packets */
34
35 extern int DEBUGLEVEL;
36 extern pstring scope;
37 extern BOOL CanRecurse;
38
39 extern pstring myname;
40
41 extern int ClientNMB;
42 extern int ClientDGRAM;
43
44 extern struct in_addr ipzero;
45
46 extern int workgroup_count; /* total number of workgroups we know about */
47
48 /* this is our domain/workgroup/server database */
49 extern struct subnet_record *subnetlist;
50
51 /* machine comment for host announcements */
52 extern  pstring ServerComment;
53
54 extern int  updatecount;
55
56 /* what server type are we currently */
57 #define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
58                 SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX |\
59                 SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
60
61 /* backup request types: which servers are to be included */
62 #define MASTER_TYPE (SV_TYPE_MASTER_BROWSER)
63 #define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL   )
64
65 extern time_t StartupTime;
66
67 extern BOOL updatedlists;
68
69 /****************************************************************************
70 tell a server to become a backup browser
71 state - 0x01 become backup instead of master
72       - 0x02 remove all entries in browse list and become non-master
73       - 0x04 stop master browser service altogether. NT ignores this 
74 **************************************************************************/
75 void reset_server(char *name, int state, struct in_addr ip)
76 {
77   char outbuf[20];
78   char *p;
79
80   bzero(outbuf,sizeof(outbuf));
81   p = outbuf;
82
83   CVAL(p,0) = ANN_ResetBrowserState;
84   CVAL(p,2) = state; 
85   p += 2;
86
87   DEBUG(2,("sending reset to %s %s of state %d\n",
88            name,inet_ntoa(ip),state));
89
90   send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
91                       myname,name,0x20,0x1d,ip,*iface_ip(ip));
92 }
93
94
95 /****************************************************************************
96 tell a server to become a backup browser
97 **************************************************************************/
98 void tell_become_backup(void)
99 {
100   /* XXXX note: this function is currently unsuitable for use, as it
101      does not properly check that a server is in a fit state to become
102      a backup browser before asking it to be one.
103    */
104
105   struct subnet_record *d;
106   for (d = subnetlist; d; d = d->next)
107     {
108       struct work_record *work;
109       for (work = d->workgrouplist; work; work = work->next)
110         {
111           struct server_record *s;
112           int num_servers = 0;
113           int num_backups = 0;
114           
115           for (s = work->serverlist; s; s = s->next)
116             {
117               if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
118               
119               num_servers++;
120               
121               if (strequal(myname, s->serv.name)) continue;
122               
123               if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
124                 num_backups++;
125                 continue;
126               }
127               
128               if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
129               
130               if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
131               
132               DEBUG(3,("num servers: %d num backups: %d\n", 
133                        num_servers, num_backups));
134               
135               /* make first server a backup server. thereafter make every
136                  tenth server a backup server */
137               if (num_backups != 0 && (num_servers+9) / num_backups > 10)
138                 {
139                   continue;
140                 }
141               
142               DEBUG(2,("sending become backup to %s %s for %s\n",
143                        s->serv.name, inet_ntoa(d->bcast_ip),
144                        work->work_group));
145               
146               /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
147               do_announce_request(s->serv.name, work->work_group,
148                                   ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
149             }
150         }
151     }
152 }
153
154
155 /*******************************************************************
156   same context: scope. should check name_type as well, and makes sure
157   we don't process messages from ourselves
158   ******************************************************************/
159 BOOL same_context(struct dgram_packet *dgram)
160 {
161   if (!strequal(dgram->dest_name  .scope,scope )) return(True);
162   if ( strequal(dgram->source_name.name ,myname)) return(True);
163   
164   return(False);
165 }
166
167
168 /*******************************************************************
169   am I listening on a name. XXXX check the type of name as well.
170   ******************************************************************/
171 BOOL listening_name(struct work_record *work, struct nmb_name *n)
172 {
173   if (strequal(n->name,myname) ||
174       strequal(n->name,work->work_group) ||
175       strequal(n->name,MSBROWSE))
176     {
177       return(True);
178     }
179   
180   return(False);
181 }
182
183
184 /*******************************************************************
185   process a domain announcement frame
186
187   Announce frames come in 3 types. Servers send host announcements
188   (command=1) to let the master browswer know they are
189   available. Master browsers send local master announcements
190   (command=15) to let other masters and backups that they are the
191   master. They also send domain announcements (command=12) to register
192   the domain
193
194   The comment field of domain announcements contains the master
195   browser name. The servertype is used by NetServerEnum to select
196   resources. We just have to pass it to smbd (via browser.dat) and let
197   the client choose using bit masks.
198   ******************************************************************/
199 static void process_announce(struct packet_struct *p,uint16 command,char *buf)
200 {
201   struct dgram_packet *dgram = &p->packet.dgram;
202   struct in_addr ip = dgram->header.source_ip;
203   struct subnet_record *d = find_subnet(ip); 
204   int update_count = CVAL(buf,0);
205
206   int ttl = IVAL(buf,1)/1000;
207   char *name = buf+5;
208   int osmajor=CVAL(buf,21);
209   int osminor=CVAL(buf,22);
210   uint32 servertype = IVAL(buf,23);
211   uint32 browse_type= CVAL(buf,27);
212   uint32 browse_sig = CVAL(buf,29);
213   char *comment = buf+31;
214
215   struct work_record *work;
216   char *work_name;
217   char *serv_name = dgram->source_name.name;
218   BOOL add = False;
219
220   comment[43] = 0;
221   
222   DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
223   DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
224            namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
225            servertype,browse_type,browse_sig,comment));
226   
227   name[15] = 0;  
228   
229   if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
230     {
231       DEBUG(2,("Announce to nametype(0) not supported yet\n"));
232       return;
233     }
234
235   if (command == ANN_DomainAnnouncement && 
236       ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
237        dgram->dest_name.name_type != 0x1))
238     {
239       DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
240                 command, inet_ntoa(ip), namestr(&dgram->dest_name)));
241       return;
242     }
243   
244   if (!strequal(dgram->dest_name.scope,scope )) return;
245   
246   if (command == ANN_DomainAnnouncement) { 
247     /* XXXX if we are a master browser for the workgroup work_name,
248        then there is a local subnet configuration problem. only
249        we should be sending out such domain announcements, because
250        as the master browser, that is our job.
251
252        stop being a master browser, and force an election. this will
253        sort out the network problem. hopefully.
254      */
255
256     work_name = name;
257     add = True;
258   } else {
259     work_name = dgram->dest_name.name;
260   }
261
262   /* we need some way of finding out about new workgroups
263      that appear to be sending packets to us. The name_type checks make
264      sure we don't add host names as workgroups */
265   if (command == ANN_HostAnnouncement &&
266       (dgram->dest_name.name_type == 0x1d ||
267        dgram->dest_name.name_type == 0x1e))
268     add = True;
269   
270   if (!(work = find_workgroupstruct(d, work_name,add)))
271     return;
272   
273   DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
274   
275   ttl = GET_TTL(ttl);
276   
277   /* add them to our browse list, and update the browse.dat file */
278   add_server_entry(d,work,name,servertype,ttl,comment,True);
279   updatedlists = True;
280
281 #if 0
282   /* the tell become backup code is broken, no great harm is done by
283      disabling it */
284   tell_become_backup();
285 #endif
286
287   /* XXXX over-kill: i don't think we should really be doing this,
288      but it doesn't do much harm other than to add extra network
289      traffic. to be more precise, we should (possibly) only
290      sync browse lists with a host that sends an
291      ANN_LocalMasterAnnouncement or an ANN_DomainAnnouncement.
292      possibly.
293    */
294
295   /* get their browse list from them and add it to ours. */
296   add_browser_entry(serv_name,dgram->dest_name.name_type,
297                     work->work_group,30,ip);
298 }
299
300 /*******************************************************************
301   process a master announcement frame
302   ******************************************************************/
303 static void process_master_announce(struct packet_struct *p,char *buf)
304 {
305   struct dgram_packet *dgram = &p->packet.dgram;
306   struct in_addr ip = dgram->header.source_ip;
307   struct subnet_record *d = find_subnet(ip);
308   struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
309   char *name = buf;
310   struct work_record *work;
311   name[15] = 0;
312   
313   DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(ip)));
314   
315   if (same_context(dgram)) return;
316   
317   if (!d || !mydomain) return;
318   
319   if (!lp_domain_master()) return;
320   
321   for (work = mydomain->workgrouplist; work; work = work->next)
322     {
323       if (AM_MASTER(work))
324         {
325           /* merge browse lists with them */
326           add_browser_entry(name,0x1b, work->work_group,30,ip);
327         }
328     }
329 }
330
331 /*******************************************************************
332   process a receive backup list request
333   
334   we receive a list of servers, and we attempt to locate them all on
335   our local subnet, and sync browse lists with them on the workgroup
336   they are said to be in.
337
338   XXXX NOTE: this function is in overdrive. it should not really do
339   half of what it actually does (it should pick _one_ name from the
340   list received and sync with it at regular intervals, rather than
341   sync with them all only once!)
342
343   ******************************************************************/
344 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
345 {
346   struct dgram_packet *dgram = &p->packet.dgram;
347   struct in_addr ip = dgram->header.source_ip;
348   int count = CVAL(buf,0);
349   uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
350   char *buf1;
351   
352   DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
353            namestr(&dgram->dest_name), inet_ntoa(ip),
354            count, info));
355   
356   if (same_context(dgram)) return;
357   
358   if (count <= 0) return;
359   
360   /* go through the list of servers attempting to sync browse lists */
361   for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
362   {
363     struct in_addr back_ip;
364     struct subnet_record *d;
365       
366     DEBUG(4,("Searching for backup browser %s at %s...\n",
367                buf1, inet_ntoa(ip)));
368       
369     /* XXXX assume name is a DNS name NOT a netbios name. a more complete
370            approach is to use reply_name_query functionality to find the name */
371
372     back_ip = *interpret_addr2(buf1);
373       
374     if (zero_ip(back_ip))
375         {
376           DEBUG(4,("Failed to find backup browser server using DNS\n"));
377           continue;
378         }
379       
380       DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
381       DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
382       
383       /* XXXX function needs work */
384           continue;
385
386     if ((d = find_subnet(back_ip)))
387         {
388           struct subnet_record *d1;
389           for (d1 = subnetlist; d1; d1 = d1->next)
390           {
391               struct work_record *work;
392               for (work = d1->workgrouplist; work; work = work->next)
393                 {
394                   if (work->token == 0 /* token */)
395                   {
396                       queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
397                                            work->work_group,0x1d,0,0,
398                                            False,False,back_ip,back_ip);
399                       return;
400                   }
401                 }
402           }
403         }
404   }
405 }
406
407
408 /****************************************************************************
409   send a backup list response.
410   **************************************************************************/
411 static void send_backup_list(char *work_name, struct nmb_name *src_name,
412                              int token, uint32 info,
413                              int name_type, struct in_addr ip)
414 {                     
415   struct subnet_record *d;
416   char outbuf[1024];
417   char *p, *countptr, *nameptr;
418   int count = 0;
419   char *theirname = src_name->name;
420   
421   DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n", 
422            work_name, inet_ntoa(ip),
423            myname,0x0,theirname,0x0));     
424   
425   if (name_type == 0x1d)
426     {
427       DEBUG(4,("master browsers: "));
428     }
429   else if (name_type == 0x1b)
430     {
431       DEBUG(4,("domain controllers: "));
432     }
433   else
434     {
435       DEBUG(0,("backup request for unknown type %0x\n", name_type));
436       return;
437     }
438   
439   bzero(outbuf,sizeof(outbuf));
440   p = outbuf;
441   
442   CVAL(p,0) = ANN_GetBackupListResp;    /* backup list response */
443   
444   p++;
445   countptr = p;
446
447   SIVAL(p,1,info); /* the sender's unique info */
448
449   p += 5;
450   
451   nameptr = p;
452
453 #if 0
454
455   for (d = subnetlist; d; d = d->next)
456   {
457       struct work_record *work;
458       
459       for (work = d->workgrouplist; work; work = work->next)
460         {
461           struct server_record *s;
462           
463           if (!strequal(work->work_group, work_name)) continue;
464           
465           for (s = work->serverlist; s; s = s->next)
466             { 
467               BOOL found = False;
468               char *n;
469               
470               if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
471               
472               for (n = nameptr; n < p; n = skip_string(n, 1))
473                 {
474                   if (strequal(n, s->serv.name)) found = True;
475                 }
476               
477               if (found) continue; /* exclude names already added */
478               
479               /* workgroup request: include all backup browsers in the list */
480               /* domain request: include all domain members in the list */
481
482               if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
483                       (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
484                 {                          
485                   DEBUG(4, ("%s ", s->serv.name));
486                   
487                   count++;
488                   strcpy(p,s->serv.name);
489                   strupper(p);
490                   p = skip_string(p,1);
491                 }
492          }
493         }
494   }
495
496 #endif
497
498         count++;
499         strcpy(p,myname);
500         strupper(p);
501         p = skip_string(p,1);
502
503   if (count == 0)
504     {
505       DEBUG(4, ("none\n"));
506     }
507   else
508     {
509       DEBUG(4, (" - count %d\n", count));
510     }
511   
512   CVAL(countptr, 0) = count;
513
514   {
515     int len = PTR_DIFF(p, outbuf);
516     debug_browse_data(outbuf, len);
517   }
518   send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
519                       myname,theirname,0x0,0x0,ip,*iface_ip(ip));
520 }
521
522
523 /*******************************************************************
524   process a send backup list request
525
526   A client sends a backup list request to ask for a list of servers on
527   the net that maintain server lists for a domain. A server is then
528   chosen from this list to send NetServerEnum commands to to list
529   available servers.
530
531   Currently samba only sends back one name in the backup list, its
532   own. For larger nets we'll have to add backups and send "become
533   backup" requests occasionally.
534   ******************************************************************/
535 static void process_send_backup_list(struct packet_struct *p,char *buf)
536 {
537   struct dgram_packet *dgram = &p->packet.dgram;
538   struct in_addr ip = dgram->header.source_ip;
539   struct subnet_record *d;
540   struct work_record *work;
541
542   int    token = CVAL(buf,0); /* sender's key index for the workgroup */
543   uint32 info  = IVAL(buf,1); /* XXXX don't know: some sort of info */
544   int name_type = dgram->dest_name.name_type;
545
546   if (same_context(dgram)) return;
547   
548   if (name_type != 0x1b && name_type != 0x1d) {
549     DEBUG(0,("backup request to wrong type %d from %s\n",
550               name_type,inet_ntoa(ip)));
551     return;
552   }
553   
554   for (d = subnetlist; d; d = d->next)
555     {
556       for (work = d->workgrouplist; work; work = work->next)
557         {
558           if (strequal(work->work_group, dgram->dest_name.name))
559             {
560               DEBUG(2,("sending backup list to %s %s id=%x\n",
561                        namestr(&dgram->dest_name),inet_ntoa(ip),info));
562   
563               send_backup_list(work->work_group,&dgram->source_name,
564                                token,info,name_type,ip);
565               return;
566             }
567         } 
568     }
569 }
570
571
572 /*******************************************************************
573   process a reset browser state
574
575   diagnostic packet:
576   0x1 - stop being a master browser and become a backup browser.
577   0x2 - discard browse lists, stop being a master browser, try again.
578   0x4 - stop being a master browser forever. no way. ain't gonna.
579          
580   ******************************************************************/
581 static void process_reset_browser(struct packet_struct *p,char *buf)
582 {
583   struct dgram_packet *dgram = &p->packet.dgram;
584   int state = CVAL(buf,0);
585
586   DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
587            namestr(&dgram->dest_name), state));
588
589   /* stop being a master but still deal with being a backup browser */
590   if (state & 0x1)
591     {
592       struct subnet_record *d;
593       for (d = subnetlist; d; d = d->next)
594         {
595           struct work_record *work;
596           for (work = d->workgrouplist; work; work = work->next)
597             {
598               if (AM_MASTER(work))
599                 {
600                   become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
601                 }
602             }
603         }
604     }
605   
606   /* XXXX documentation inconsistency: the above description does not
607      exactly tally with what is implemented for state & 0x2
608    */
609
610   /* totally delete all servers and start afresh */
611   if (state & 0x2)
612     {
613       struct subnet_record *d;
614       for (d = subnetlist; d; d = d->next)
615         {
616           struct work_record *work;
617           for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
618         }
619       add_my_subnets(lp_workgroup());
620     }
621   
622   /* stop browsing altogether. i don't think this is a good idea! */
623   if (state & 0x4)
624     {
625       DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
626     }
627 }
628
629 /*******************************************************************
630   process a announcement request
631
632   clients send these when they want everyone to send an announcement
633   immediately. This can cause quite a storm of packets!
634   ******************************************************************/
635 static void process_announce_request(struct packet_struct *p,char *buf)
636 {
637   struct dgram_packet *dgram = &p->packet.dgram;
638   struct work_record *work;
639   struct in_addr ip = dgram->header.source_ip;
640   struct subnet_record *d = find_subnet(ip);
641   int token = CVAL(buf,0);
642   char *name = buf+1;
643   
644   name[15] = 0;
645   
646   DEBUG(3,("Announce request from %s to %s token=0x%X\n",
647            name,namestr(&dgram->dest_name), token));
648   
649   if (strequal(dgram->source_name.name,myname)) return;
650   
651   /* XXXX BUG or FEATURE?: need to ensure that we are a member of
652      this workgroup before announcing, particularly as we only
653      respond on local interfaces anyway.
654
655      if (strequal(dgram->dest_name, lp_workgroup()) return; ???
656    */
657
658   if (!d) return;
659   
660   if (!d->my_interface) return;
661   
662   for (work = d->workgrouplist; work; work = work->next)
663     {
664      /* XXXX BUG: the destination name type should also be checked,
665         not just the name. e.g if the name is WORKGROUP(0x1d) then
666         we should only respond if we own that name */
667     
668       if (strequal(dgram->dest_name.name,work->work_group)) 
669         {
670           work->needannounce = True;
671         }
672     }
673 }
674
675
676 /****************************************************************************
677 depending on what announce has been made, we are only going to
678 accept certain types of name announce. XXXX untested code
679
680 check listening name type
681 ****************************************************************************/
682 BOOL listening_type(struct packet_struct *p, int command)
683 {
684   struct dgram_packet *dgram = &p->packet.dgram;
685   int type = dgram->dest_name.name_type;
686
687   switch (command)
688     {
689     case ANN_HostAnnouncement:
690       {
691         if (type != 0x0 || type != 0x20) return (False);
692         break;
693       }
694       
695     case ANN_AnnouncementRequest:
696       {
697         return (True);
698         break;
699       }
700       
701     case ANN_Election:
702       {
703         return (True);
704         break;
705       }
706       
707     case ANN_GetBackupListReq:
708       {
709         return (True);
710         break;
711       }
712       
713     case ANN_GetBackupListResp:
714       {
715         return (True);
716         break;
717       }
718       
719     case ANN_DomainAnnouncement:
720       {
721         if (type != 0x1b || type != 0x1c) return (False);
722         break;
723       }
724       
725     case ANN_MasterAnnouncement:
726       {
727         if (type != 0x1d) return (False);
728         break;
729       }
730       
731     case ANN_LocalMasterAnnouncement:
732       {
733         if (type != 0x1c || type != 0x1d) return (False);
734         break;
735       }
736     }
737   return (True); /* we're not dealing with unknown packet types */
738 }
739
740
741 /****************************************************************************
742 process a browse frame
743 ****************************************************************************/
744 void process_browse_packet(struct packet_struct *p,char *buf,int len)
745 {
746   int command = CVAL(buf,0);
747   switch (command) 
748     {
749     case ANN_HostAnnouncement:
750     case ANN_DomainAnnouncement:
751     case ANN_LocalMasterAnnouncement:
752       {
753         debug_browse_data(buf, len);
754         process_announce(p,command,buf+1);
755         break;
756       }
757       
758     case ANN_AnnouncementRequest:
759       {
760         process_announce_request(p,buf+1);
761         break;
762       }
763       
764     case ANN_Election:
765       {
766         process_election(p,buf+1);
767         break;
768       }
769       
770     case ANN_GetBackupListReq:
771       {
772         debug_browse_data(buf, len);
773         process_send_backup_list(p,buf+1);
774         break;
775       }
776       
777     case ANN_GetBackupListResp:
778     {
779         debug_browse_data(buf, len);
780         process_rcv_backup_list(p, buf+1);
781         break;
782     }
783       
784     case ANN_ResetBrowserState:
785       {
786         process_reset_browser(p, buf+1);
787         break;
788       }
789       
790     case ANN_MasterAnnouncement:
791       {
792         process_master_announce(p,buf+1);
793         break;
794       }
795       
796     default:
797       {
798         struct dgram_packet *dgram = &p->packet.dgram;
799         DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
800                  command, namestr(&dgram->source_name), 
801                  inet_ntoa(p->ip), namestr(&dgram->dest_name)));
802       }
803     }
804 }
805
806