Ticket #1649: Prepare for prerelease mc-4.7.0-pre3 (code cleanup)
[midnight-commander.git] / vfs / samba / libsmb / nmblib.c
blob6dd820824200740d438864bce1dafb945a74b0d5
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 NBT netbios library routines
5 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include "includes.h"
25 extern int DEBUGLEVEL;
27 int num_good_sends = 0;
28 int num_good_receives = 0;
30 static struct opcode_names {
31 const char *nmb_opcode_name;
32 int opcode;
33 } const nmb_header_opcode_names[] = {
34 {"Query", 0 },
35 {"Registration", 5 },
36 {"Release", 6 },
37 {"WACK", 7 },
38 {"Refresh", 8 },
39 {"Refresh(altcode)", 9 },
40 {"Multi-homed Registration", 15 },
41 {0, -1 }
44 /****************************************************************************
45 * Lookup a nmb opcode name.
46 ****************************************************************************/
47 static const char *lookup_opcode_name( int opcode )
49 const struct opcode_names *op_namep = nmb_header_opcode_names;
51 while(op_namep->nmb_opcode_name) {
52 if(opcode == op_namep->opcode)
53 return op_namep->nmb_opcode_name;
54 op_namep++;
56 return "<unknown opcode>";
59 /****************************************************************************
60 print out a res_rec structure
61 ****************************************************************************/
62 static void debug_nmb_res_rec(struct res_rec *res, const char *hdr)
64 int i, j;
66 DEBUGADD( 4, ( " %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n",
67 hdr,
68 nmb_namestr(&res->rr_name),
69 res->rr_type,
70 res->rr_class,
71 res->ttl ) );
73 if( res->rdlength == 0 || res->rdata == NULL )
74 return;
76 for (i = 0; i < res->rdlength; i+= 16)
78 DEBUGADD(4, (" %s %3x char ", hdr, i));
80 for (j = 0; j < 16; j++)
82 unsigned char x = res->rdata[i+j];
83 if (x < 32 || x > 127) x = '.';
85 if (i+j >= res->rdlength) break;
86 DEBUGADD(4, ("%c", x));
89 DEBUGADD(4, (" hex "));
91 for (j = 0; j < 16; j++)
93 if (i+j >= res->rdlength) break;
94 DEBUGADD(4, ("%02X", (unsigned char)res->rdata[i+j]));
97 DEBUGADD(4, ("\n"));
101 /****************************************************************************
102 process a nmb packet
103 ****************************************************************************/
104 void debug_nmb_packet(struct packet_struct *p)
106 struct nmb_packet *nmb = &p->packet.nmb;
108 if( DEBUGLVL( 4 ) )
110 dbgtext( "nmb packet from %s(%d) header: id=%d opcode=%s(%d) response=%s\n",
111 inet_ntoa(p->ip), p->port,
112 nmb->header.name_trn_id,
113 lookup_opcode_name(nmb->header.opcode),
114 nmb->header.opcode,
115 BOOLSTR(nmb->header.response) );
116 dbgtext( " header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n",
117 BOOLSTR(nmb->header.nm_flags.bcast),
118 BOOLSTR(nmb->header.nm_flags.recursion_available),
119 BOOLSTR(nmb->header.nm_flags.recursion_desired),
120 BOOLSTR(nmb->header.nm_flags.trunc),
121 BOOLSTR(nmb->header.nm_flags.authoritative) );
122 dbgtext( " header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n",
123 nmb->header.rcode,
124 nmb->header.qdcount,
125 nmb->header.ancount,
126 nmb->header.nscount,
127 nmb->header.arcount );
130 if (nmb->header.qdcount)
132 DEBUGADD( 4, ( " question: q_name=%s q_type=%d q_class=%d\n",
133 nmb_namestr(&nmb->question.question_name),
134 nmb->question.question_type,
135 nmb->question.question_class) );
138 if (nmb->answers && nmb->header.ancount)
140 debug_nmb_res_rec(nmb->answers,"answers");
142 if (nmb->nsrecs && nmb->header.nscount)
144 debug_nmb_res_rec(nmb->nsrecs,"nsrecs");
146 if (nmb->additional && nmb->header.arcount)
148 debug_nmb_res_rec(nmb->additional,"additional");
152 /*******************************************************************
153 handle "compressed" name pointers
154 ******************************************************************/
155 static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
156 BOOL *got_pointer,int *ret)
158 int loop_count=0;
160 while ((ubuf[*offset] & 0xC0) == 0xC0) {
161 if (!*got_pointer) (*ret) += 2;
162 (*got_pointer)=True;
163 (*offset) = ((ubuf[*offset] & ~0xC0)<<8) | ubuf[(*offset)+1];
164 if (loop_count++ == 10 || (*offset) < 0 || (*offset)>(length-2)) {
165 return(False);
168 return(True);
171 /*******************************************************************
172 parse a nmb name from "compressed" format to something readable
173 return the space taken by the name, or 0 if the name is invalid
174 ******************************************************************/
175 static int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *name)
177 int m,n=0;
178 unsigned char *ubuf = (unsigned char *)inbuf;
179 int ret = 0;
180 BOOL got_pointer=False;
182 if (length - offset < 2)
183 return(0);
185 /* handle initial name pointers */
186 if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
187 return(0);
189 m = ubuf[offset];
191 if (!m)
192 return(0);
193 if ((m & 0xC0) || offset+m+2 > length)
194 return(0);
196 memset((char *)name,'\0',sizeof(*name));
198 /* the "compressed" part */
199 if (!got_pointer)
200 ret += m + 2;
201 offset++;
202 while (m > 0) {
203 unsigned char c1,c2;
204 c1 = ubuf[offset++]-'A';
205 c2 = ubuf[offset++]-'A';
206 if ((c1 & 0xF0) || (c2 & 0xF0) || ((size_t) n > sizeof(name->name)-1))
207 return(0);
208 name->name[n++] = (c1<<4) | c2;
209 m -= 2;
211 name->name[n] = 0;
213 if (n==16) {
214 /* parse out the name type,
215 its always in the 16th byte of the name */
216 name->name_type = ((unsigned char)name->name[15]) & 0xff;
218 /* remove trailing spaces */
219 name->name[15] = 0;
220 n = 14;
221 while (n && name->name[n]==' ')
222 name->name[n--] = 0;
225 /* now the domain parts (if any) */
226 n = 0;
227 while (ubuf[offset]) {
228 /* we can have pointers within the domain part as well */
229 if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
230 return(0);
232 m = ubuf[offset];
233 if (!got_pointer)
234 ret += m+1;
235 if (n)
236 name->scope[n++] = '.';
237 if (m+2+offset>length || (size_t) n+m+1 >sizeof(name->scope))
238 return(0);
239 offset++;
240 while (m--)
241 name->scope[n++] = (char)ubuf[offset++];
243 name->scope[n++] = 0;
245 return(ret);
249 /*******************************************************************
250 put a compressed nmb name into a buffer. return the length of the
251 compressed name
253 compressed names are really weird. The "compression" doubles the
254 size. The idea is that it also means that compressed names conform
255 to the doman name system. See RFC1002.
256 ******************************************************************/
257 static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
259 int ret,m;
260 fstring buf1;
261 char *p;
263 if (strcmp(name->name,"*") == 0) {
264 /* special case for wildcard name */
265 memset(buf1,'\0',20);
266 buf1[0] = '*';
267 buf1[15] = name->name_type;
268 } else {
269 slprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type);
272 buf[offset] = 0x20;
274 ret = 34;
276 for (m=0;m<16;m++) {
277 buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF);
278 buf[offset+2+2*m] = 'A' + (buf1[m]&0xF);
280 offset += 33;
282 buf[offset] = 0;
284 if (name->scope[0]) {
285 /* XXXX this scope handling needs testing */
286 ret += strlen(name->scope) + 1;
287 pstrcpy(&buf[offset+1],name->scope);
289 p = &buf[offset+1];
290 while ((p = strchr(p,'.'))) {
291 buf[offset] = PTR_DIFF(p,&buf[offset+1]);
292 offset += (buf[offset] + 1);
293 p = &buf[offset+1];
295 buf[offset] = strlen(&buf[offset+1]);
298 return(ret);
301 /*******************************************************************
302 useful for debugging messages
303 ******************************************************************/
304 char *nmb_namestr(struct nmb_name *n)
306 static int i=0;
307 static fstring ret[4];
308 char *p = ret[i];
310 if (!n->scope[0])
311 slprintf(p,sizeof(fstring)-1, "%s<%02x>",n->name,n->name_type);
312 else
313 slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",n->name,n->name_type,n->scope);
315 i = (i+1)%4;
316 return(p);
319 /*******************************************************************
320 allocate and parse some resource records
321 ******************************************************************/
322 static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
323 struct res_rec **recs, int count)
325 int i;
326 *recs = (struct res_rec *)malloc(sizeof(**recs)*count);
327 if (!*recs) return(False);
329 memset((char *)*recs,'\0',sizeof(**recs)*count);
331 for (i=0;i<count;i++) {
332 int l = parse_nmb_name(inbuf,*offset,length,&(*recs)[i].rr_name);
333 (*offset) += l;
334 if (!l || (*offset)+10 > length) {
335 free(*recs);
336 return(False);
338 (*recs)[i].rr_type = RSVAL(inbuf,(*offset));
339 (*recs)[i].rr_class = RSVAL(inbuf,(*offset)+2);
340 (*recs)[i].ttl = RIVAL(inbuf,(*offset)+4);
341 (*recs)[i].rdlength = RSVAL(inbuf,(*offset)+8);
342 (*offset) += 10;
343 if ((size_t)(*recs)[i].rdlength>sizeof((*recs)[i].rdata) ||
344 (*offset)+(*recs)[i].rdlength > length) {
345 free(*recs);
346 return(False);
348 memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
349 (*offset) += (*recs)[i].rdlength;
351 return(True);
354 /*******************************************************************
355 put a resource record into a packet
356 ******************************************************************/
357 static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
359 int ret=0;
360 int i;
362 for (i=0;i<count;i++) {
363 int l = put_nmb_name(buf,offset,&recs[i].rr_name);
364 offset += l;
365 ret += l;
366 RSSVAL(buf,offset,recs[i].rr_type);
367 RSSVAL(buf,offset+2,recs[i].rr_class);
368 RSIVAL(buf,offset+4,recs[i].ttl);
369 RSSVAL(buf,offset+8,recs[i].rdlength);
370 memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength);
371 offset += 10+recs[i].rdlength;
372 ret += 10+recs[i].rdlength;
375 return(ret);
378 /*******************************************************************
379 put a compressed name pointer record into a packet
380 ******************************************************************/
381 static int put_compressed_name_ptr(unsigned char *buf,int offset,struct res_rec *rec,int ptr_offset)
383 int ret=0;
384 buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
385 buf[offset+1] = (ptr_offset & 0xFF);
386 offset += 2;
387 ret += 2;
388 RSSVAL(buf,offset,rec->rr_type);
389 RSSVAL(buf,offset+2,rec->rr_class);
390 RSIVAL(buf,offset+4,rec->ttl);
391 RSSVAL(buf,offset+8,rec->rdlength);
392 memcpy(buf+offset+10,rec->rdata,rec->rdlength);
393 offset += 10+rec->rdlength;
394 ret += 10+rec->rdlength;
396 return(ret);
399 /*******************************************************************
400 parse a dgram packet. Return False if the packet can't be parsed
401 or is invalid for some reason, True otherwise
403 this is documented in section 4.4.1 of RFC1002
404 ******************************************************************/
405 static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
407 int offset;
408 int flags;
410 memset((char *)dgram,'\0',sizeof(*dgram));
412 if (length < 14) return(False);
414 dgram->header.msg_type = CVAL(inbuf,0);
415 flags = CVAL(inbuf,1);
416 dgram->header.flags.node_type = (enum node_type)((flags>>2)&3);
417 if (flags & 1) dgram->header.flags.more = True;
418 if (flags & 2) dgram->header.flags.first = True;
419 dgram->header.dgm_id = RSVAL(inbuf,2);
420 putip((char *)&dgram->header.source_ip,inbuf+4);
421 dgram->header.source_port = RSVAL(inbuf,8);
422 dgram->header.dgm_length = RSVAL(inbuf,10);
423 dgram->header.packet_offset = RSVAL(inbuf,12);
425 offset = 14;
427 if (dgram->header.msg_type == 0x10 ||
428 dgram->header.msg_type == 0x11 ||
429 dgram->header.msg_type == 0x12) {
430 offset += parse_nmb_name(inbuf,offset,length,&dgram->source_name);
431 offset += parse_nmb_name(inbuf,offset,length,&dgram->dest_name);
434 if (offset >= length || ((size_t)length-offset > sizeof(dgram->data)))
435 return(False);
437 dgram->datasize = length-offset;
438 memcpy(dgram->data,inbuf+offset,dgram->datasize);
440 return(True);
444 /*******************************************************************
445 parse a nmb packet. Return False if the packet can't be parsed
446 or is invalid for some reason, True otherwise
447 ******************************************************************/
448 static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
450 int nm_flags,offset;
452 memset((char *)nmb,'\0',sizeof(*nmb));
454 if (length < 12) return(False);
456 /* parse the header */
457 nmb->header.name_trn_id = RSVAL(inbuf,0);
459 DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id));
461 nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF;
462 nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False;
463 nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4);
464 nmb->header.nm_flags.bcast = (nm_flags&1)?True:False;
465 nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False;
466 nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False;
467 nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False;
468 nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;
469 nmb->header.rcode = CVAL(inbuf,3) & 0xF;
470 nmb->header.qdcount = RSVAL(inbuf,4);
471 nmb->header.ancount = RSVAL(inbuf,6);
472 nmb->header.nscount = RSVAL(inbuf,8);
473 nmb->header.arcount = RSVAL(inbuf,10);
475 if (nmb->header.qdcount) {
476 offset = parse_nmb_name(inbuf,12,length,&nmb->question.question_name);
477 if (!offset) return(False);
479 if (length - (12+offset) < 4) return(False);
480 nmb->question.question_type = RSVAL(inbuf,12+offset);
481 nmb->question.question_class = RSVAL(inbuf,12+offset+2);
483 offset += 12+4;
484 } else {
485 offset = 12;
488 /* and any resource records */
489 if (nmb->header.ancount &&
490 !parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers,
491 nmb->header.ancount))
492 return(False);
494 if (nmb->header.nscount &&
495 !parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs,
496 nmb->header.nscount))
497 return(False);
499 if (nmb->header.arcount &&
500 !parse_alloc_res_rec(inbuf,&offset,length,&nmb->additional,
501 nmb->header.arcount))
502 return(False);
504 return(True);
506 #if 0
507 /*******************************************************************
508 'Copy constructor' for an nmb packet
509 ******************************************************************/
510 static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
512 struct nmb_packet *nmb;
513 struct nmb_packet *copy_nmb;
514 struct packet_struct *pkt_copy;
516 if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
518 DEBUG(0,("copy_nmb_packet: malloc fail.\n"));
519 return NULL;
522 /* Structure copy of entire thing. */
524 *pkt_copy = *packet;
526 /* Ensure this copy is not locked. */
527 pkt_copy->locked = False;
529 /* Ensure this copy has no resource records. */
530 nmb = &packet->packet.nmb;
531 copy_nmb = &pkt_copy->packet.nmb;
533 copy_nmb->answers = NULL;
534 copy_nmb->nsrecs = NULL;
535 copy_nmb->additional = NULL;
537 /* Now copy any resource records. */
539 if (nmb->answers)
541 if((copy_nmb->answers = (struct res_rec *)
542 malloc(nmb->header.ancount * sizeof(struct res_rec))) == NULL)
543 goto free_and_exit;
544 memcpy((char *)copy_nmb->answers, (char *)nmb->answers,
545 nmb->header.ancount * sizeof(struct res_rec));
547 if (nmb->nsrecs)
549 if((copy_nmb->nsrecs = (struct res_rec *)
550 malloc(nmb->header.nscount * sizeof(struct res_rec))) == NULL)
551 goto free_and_exit;
552 memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs,
553 nmb->header.nscount * sizeof(struct res_rec));
555 if (nmb->additional)
557 if((copy_nmb->additional = (struct res_rec *)
558 malloc(nmb->header.arcount * sizeof(struct res_rec))) == NULL)
559 goto free_and_exit;
560 memcpy((char *)copy_nmb->additional, (char *)nmb->additional,
561 nmb->header.arcount * sizeof(struct res_rec));
564 return pkt_copy;
566 free_and_exit:
568 if(copy_nmb->answers)
569 free((char *)copy_nmb->answers);
570 if(copy_nmb->nsrecs)
571 free((char *)copy_nmb->nsrecs);
572 if(copy_nmb->additional)
573 free((char *)copy_nmb->additional);
574 free((char *)pkt_copy);
576 DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n"));
577 return NULL;
580 /*******************************************************************
581 'Copy constructor' for a dgram packet
582 ******************************************************************/
583 static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
585 struct packet_struct *pkt_copy;
587 if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
589 DEBUG(0,("copy_dgram_packet: malloc fail.\n"));
590 return NULL;
593 /* Structure copy of entire thing. */
595 *pkt_copy = *packet;
597 /* Ensure this copy is not locked. */
598 pkt_copy->locked = False;
600 /* There are no additional pointers in a dgram packet,
601 we are finished. */
602 return pkt_copy;
605 /*******************************************************************
606 'Copy constructor' for a generic packet
607 ******************************************************************/
608 struct packet_struct *copy_packet(struct packet_struct *packet)
610 if(packet->packet_type == NMB_PACKET)
611 return copy_nmb_packet(packet);
612 else if (packet->packet_type == DGRAM_PACKET)
613 return copy_dgram_packet(packet);
614 return NULL;
616 #endif /* 0 */
617 /*******************************************************************
618 free up any resources associated with an nmb packet
619 ******************************************************************/
620 static void free_nmb_packet(struct nmb_packet *nmb)
622 if (nmb->answers) free(nmb->answers);
623 if (nmb->nsrecs) free(nmb->nsrecs);
624 if (nmb->additional) free(nmb->additional);
627 /*******************************************************************
628 free up any resources associated with a dgram packet
629 ******************************************************************/
630 static void free_dgram_packet(struct dgram_packet *nmb)
632 /* We have nothing to do for a dgram packet. */
633 (void) nmb;
636 /*******************************************************************
637 free up any resources associated with a packet
638 ******************************************************************/
639 void free_packet(struct packet_struct *packet)
641 if (packet->locked)
642 return;
643 if (packet->packet_type == NMB_PACKET)
644 free_nmb_packet(&packet->packet.nmb);
645 else if (packet->packet_type == DGRAM_PACKET)
646 free_dgram_packet(&packet->packet.dgram);
647 free(packet);
650 /*******************************************************************
651 read a packet from a socket and parse it, returning a packet ready
652 to be used or put on the queue. This assumes a UDP socket
653 ******************************************************************/
654 struct packet_struct *read_packet(int fd,enum packet_type packet_type)
656 extern struct in_addr lastip;
657 extern int lastport;
658 struct packet_struct *packet;
659 char buf[MAX_DGRAM_SIZE];
660 int length;
661 BOOL ok=False;
663 length = read_udp_socket(fd,buf,sizeof(buf));
664 if (length < MIN_DGRAM_SIZE) return(NULL);
666 packet = (struct packet_struct *)malloc(sizeof(*packet));
667 if (!packet) return(NULL);
669 packet->next = NULL;
670 packet->prev = NULL;
671 packet->ip = lastip;
672 packet->port = lastport;
673 packet->fd = fd;
674 packet->locked = False;
675 packet->timestamp = time(NULL);
676 packet->packet_type = packet_type;
677 switch (packet_type)
679 case NMB_PACKET:
680 ok = parse_nmb(buf,length,&packet->packet.nmb);
681 break;
683 case DGRAM_PACKET:
684 ok = parse_dgram(buf,length,&packet->packet.dgram);
685 break;
687 if (!ok) {
688 DEBUG(10,("read_packet: discarding packet id = %d\n",
689 packet->packet.nmb.header.name_trn_id));
690 free_packet(packet);
691 return(NULL);
694 num_good_receives++;
696 DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
697 length, inet_ntoa(packet->ip), packet->port ) );
699 return(packet);
703 /*******************************************************************
704 send a udp packet on a already open socket
705 ******************************************************************/
706 static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
708 BOOL ret;
709 struct sockaddr_in sock_out;
711 /* set the address and port */
712 memset((char *)&sock_out,'\0',sizeof(sock_out));
713 putip((char *)&sock_out.sin_addr,(char *)&ip);
714 sock_out.sin_port = htons( port );
715 sock_out.sin_family = AF_INET;
717 DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n",
718 len, inet_ntoa(ip), port ) );
720 ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out,
721 sizeof(sock_out)) >= 0);
723 if (!ret)
724 DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
725 inet_ntoa(ip),port,strerror(errno)));
727 if (ret)
728 num_good_sends++;
730 return(ret);
733 /*******************************************************************
734 build a dgram packet ready for sending
736 XXXX This currently doesn't handle packets too big for one
737 datagram. It should split them and use the packet_offset, more and
738 first flags to handle the fragmentation. Yuck.
739 ******************************************************************/
740 static int build_dgram(char *buf,struct packet_struct *p)
742 struct dgram_packet *dgram = &p->packet.dgram;
743 unsigned char *ubuf = (unsigned char *)buf;
744 int offset=0;
746 /* put in the header */
747 ubuf[0] = dgram->header.msg_type;
748 ubuf[1] = (((int)dgram->header.flags.node_type)<<2);
749 if (dgram->header.flags.more) ubuf[1] |= 1;
750 if (dgram->header.flags.first) ubuf[1] |= 2;
751 RSSVAL(ubuf,2,dgram->header.dgm_id);
752 putip(ubuf+4,(char *)&dgram->header.source_ip);
753 RSSVAL(ubuf,8,dgram->header.source_port);
754 RSSVAL(ubuf,12,dgram->header.packet_offset);
756 offset = 14;
758 if (dgram->header.msg_type == 0x10 ||
759 dgram->header.msg_type == 0x11 ||
760 dgram->header.msg_type == 0x12) {
761 offset += put_nmb_name((char *)ubuf,offset,&dgram->source_name);
762 offset += put_nmb_name((char *)ubuf,offset,&dgram->dest_name);
765 memcpy(ubuf+offset,dgram->data,dgram->datasize);
766 offset += dgram->datasize;
768 /* automatically set the dgm_length */
769 dgram->header.dgm_length = offset;
770 RSSVAL(ubuf,10,dgram->header.dgm_length);
772 return(offset);
775 /*******************************************************************
776 build a nmb name
777 *******************************************************************/
778 void make_nmb_name( struct nmb_name *n, const char *name, int type )
780 extern pstring global_scope;
781 memset( (char *)n, '\0', sizeof(struct nmb_name) );
782 StrnCpy( n->name, name, 15 );
783 strupper( n->name );
784 n->name_type = (unsigned int)type & 0xFF;
785 StrnCpy( n->scope, global_scope, 63 );
786 strupper( n->scope );
789 /*******************************************************************
790 Compare two nmb names
791 ******************************************************************/
792 #if 0
793 BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
795 return ((n1->name_type == n2->name_type) &&
796 strequal(n1->name ,n2->name ) &&
797 strequal(n1->scope,n2->scope));
799 #endif /* 0 */
800 /*******************************************************************
801 build a nmb packet ready for sending
803 XXXX this currently relies on not being passed something that expands
804 to a packet too big for the buffer. Eventually this should be
805 changed to set the trunc bit so the receiver can request the rest
806 via tcp (when that becomes supported)
807 ******************************************************************/
808 static int build_nmb(char *buf,struct packet_struct *p)
810 struct nmb_packet *nmb = &p->packet.nmb;
811 unsigned char *ubuf = (unsigned char *)buf;
812 int offset=0;
814 /* put in the header */
815 RSSVAL(ubuf,offset,nmb->header.name_trn_id);
816 ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
817 if (nmb->header.response) ubuf[offset+2] |= (1<<7);
818 if (nmb->header.nm_flags.authoritative &&
819 nmb->header.response) ubuf[offset+2] |= 0x4;
820 if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2;
821 if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1;
822 if (nmb->header.nm_flags.recursion_available &&
823 nmb->header.response) ubuf[offset+3] |= 0x80;
824 if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10;
825 ubuf[offset+3] |= (nmb->header.rcode & 0xF);
827 RSSVAL(ubuf,offset+4,nmb->header.qdcount);
828 RSSVAL(ubuf,offset+6,nmb->header.ancount);
829 RSSVAL(ubuf,offset+8,nmb->header.nscount);
830 RSSVAL(ubuf,offset+10,nmb->header.arcount);
832 offset += 12;
833 if (nmb->header.qdcount) {
834 /* XXXX this doesn't handle a qdcount of > 1 */
835 offset += put_nmb_name((char *)ubuf,offset,&nmb->question.question_name);
836 RSSVAL(ubuf,offset,nmb->question.question_type);
837 RSSVAL(ubuf,offset+2,nmb->question.question_class);
838 offset += 4;
841 if (nmb->header.ancount)
842 offset += put_res_rec((char *)ubuf,offset,nmb->answers,
843 nmb->header.ancount);
845 if (nmb->header.nscount)
846 offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
847 nmb->header.nscount);
850 * The spec says we must put compressed name pointers
851 * in the following outgoing packets :
852 * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST,
853 * NAME_RELEASE_REQUEST.
856 if((nmb->header.response == False) &&
857 ((nmb->header.opcode == NMB_NAME_REG_OPCODE) ||
858 (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) ||
859 (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
860 (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) ||
861 (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) &&
862 (nmb->header.arcount == 1)) {
864 offset += put_compressed_name_ptr(ubuf,offset,nmb->additional,12);
866 } else if (nmb->header.arcount) {
867 offset += put_res_rec((char *)ubuf,offset,nmb->additional,
868 nmb->header.arcount);
870 return(offset);
874 /*******************************************************************
875 send a packet_struct
876 ******************************************************************/
877 BOOL send_packet(struct packet_struct *p)
879 char buf[1024];
880 int len=0;
882 memset(buf,'\0',sizeof(buf));
884 switch (p->packet_type)
886 case NMB_PACKET:
887 len = build_nmb(buf,p);
888 debug_nmb_packet(p);
889 break;
891 case DGRAM_PACKET:
892 len = build_dgram(buf,p);
893 break;
896 if (!len) return(False);
898 return(send_udp(p->fd,buf,len,p->ip,p->port));
901 /****************************************************************************
902 receive a packet with timeout on a open UDP filedescriptor
903 The timeout is in milliseconds
904 ***************************************************************************/
905 struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
907 fd_set fds;
908 struct timeval timeout;
910 FD_ZERO(&fds);
911 FD_SET(fd,&fds);
912 timeout.tv_sec = t/1000;
913 timeout.tv_usec = 1000*(t%1000);
915 sys_select(fd+1,&fds,&timeout);
917 if (FD_ISSET(fd,&fds))
918 return(read_packet(fd,type));
920 return(NULL);
923 #if 0
924 /****************************************************************************
925 return the number of bits that match between two 4 character buffers
926 ***************************************************************************/
927 static int matching_bits(uchar *p1, uchar *p2)
929 int i, j, ret = 0;
930 for (i=0; i<4; i++) {
931 if (p1[i] != p2[i]) break;
932 ret += 8;
935 if (i==4) return ret;
937 for (j=0; j<8; j++) {
938 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j)))) break;
939 ret++;
942 return ret;
945 static uchar sort_ip[4];
947 /****************************************************************************
948 compare two query reply records
949 ***************************************************************************/
950 static int name_query_comp(uchar *p1, uchar *p2)
952 return matching_bits(p2+2, sort_ip) - matching_bits(p1+2, sort_ip);
955 /****************************************************************************
956 sort a set of 6 byte name query response records so that the IPs that
957 have the most leading bits in common with the specified address come first
958 ***************************************************************************/
959 void sort_query_replies(char *data, int n, struct in_addr ip)
961 if (n <= 1) return;
963 putip(sort_ip, (char *)&ip);
965 qsort(data, n, 6, QSORT_CAST name_query_comp);
967 #endif /*0 */