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