1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22*7f667e74Sjose borrego * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw /* 27da6c28aaSamw * Description: 28da6c28aaSamw * 29da6c28aaSamw * Contains base code for netbios datagram service. 30da6c28aaSamw * 31da6c28aaSamw * Relavent sections from RFC1002: 32da6c28aaSamw * 33da6c28aaSamw * 5.3. NetBIOS DATAGRAM SERVICE PROTOCOLS 34da6c28aaSamw * 35da6c28aaSamw * The following are GLOBAL variables and should be NetBIOS user 36da6c28aaSamw * configurable: 37da6c28aaSamw * 38da6c28aaSamw * - SCOPE_ID: the non-leaf section of the domain name preceded by a 39da6c28aaSamw * '.' which represents the domain of the NetBIOS scope for the 40da6c28aaSamw * NetBIOS name. The following protocol description only supports 41da6c28aaSamw * single scope operation. 42da6c28aaSamw * 43da6c28aaSamw * - MAX_DATAGRAM_LENGTH: the maximum length of an IP datagram. The 44da6c28aaSamw * minimal maximum length defined in for IP is 576 bytes. This 45da6c28aaSamw * value is used when determining whether to fragment a NetBIOS 46da6c28aaSamw * datagram. Implementations are expected to be capable of 47da6c28aaSamw * receiving unfragmented NetBIOS datagrams up to their maximum 48da6c28aaSamw * size. 49da6c28aaSamw * 50da6c28aaSamw * - BROADCAST_ADDRESS: the IP address B-nodes use to send datagrams 51da6c28aaSamw * with group name destinations and broadcast datagrams. The 52da6c28aaSamw * default is the IP broadcast address for a single IP network. 53da6c28aaSamw * 54da6c28aaSamw * 55da6c28aaSamw * The following are Defined Constants for the NetBIOS Datagram 56da6c28aaSamw * Service: 57da6c28aaSamw * 58da6c28aaSamw * - DGM_SRVC_UDP_PORT: the globally well-known UDP port allocated 59da6c28aaSamw * where the NetBIOS Datagram Service receives UDP packets. See 60da6c28aaSamw * section 6, "Defined Constants", for its value. 61da6c28aaSamw */ 62da6c28aaSamw 63da6c28aaSamw /* 64da6c28aaSamw * 65da6c28aaSamw * 6. DEFINED CONSTANTS AND VARIABLES 66da6c28aaSamw * 67da6c28aaSamw * GENERAL: 68da6c28aaSamw * 69da6c28aaSamw * SCOPE_ID The name of the NetBIOS scope. 70da6c28aaSamw * 71da6c28aaSamw * This is expressed as a character 72da6c28aaSamw * string meeting the requirements of 73da6c28aaSamw * the domain name system and without 74da6c28aaSamw * a leading or trailing "dot". 75da6c28aaSamw * 76da6c28aaSamw * An implementation may elect to make 77da6c28aaSamw * this a single global value for the 78da6c28aaSamw * node or allow it to be specified 79da6c28aaSamw * with each separate NetBIOS name 80da6c28aaSamw * (thus permitting cross-scope 81da6c28aaSamw * references.) 82da6c28aaSamw * 83da6c28aaSamw * BROADCAST_ADDRESS An IP address composed of the 84da6c28aaSamw * node network and subnetwork 85da6c28aaSamw * numbers with all remaining bits set 86da6c28aaSamw * to one. 87da6c28aaSamw * 88da6c28aaSamw * I.e. "Specific subnet" broadcast 89da6c28aaSamw * addressing according to section 2.3 90da6c28aaSamw * of RFC 950. 91da6c28aaSamw * 92da6c28aaSamw * BCAST_REQ_RETRY_TIMEOUT 250 milliseconds. 93da6c28aaSamw * An adaptive timer may be used. 94da6c28aaSamw * 95da6c28aaSamw * BCAST_REQ_RETRY_COUNT 3 96da6c28aaSamw * 97da6c28aaSamw * UCAST_REQ_RETRY_TIMEOUT 5 seconds 98da6c28aaSamw * An adaptive timer may be used. 99da6c28aaSamw * 100da6c28aaSamw * UCAST_REQ_RETRY_COUNT 3 101da6c28aaSamw * 102da6c28aaSamw * MAX_DATAGRAM_LENGTH 576 bytes (default) 103da6c28aaSamw * 104da6c28aaSamw * DATAGRAM SERVICE: 105da6c28aaSamw * 106da6c28aaSamw * DGM_SRVC_UDP_PORT 138 (decimal) 107da6c28aaSamw * 108da6c28aaSamw * FRAGMENT_TO 2 seconds (default) 109da6c28aaSamw */ 110da6c28aaSamw 111da6c28aaSamw #include <stdlib.h> 112da6c28aaSamw #include <unistd.h> 113da6c28aaSamw #include <string.h> 114da6c28aaSamw #include <strings.h> 115da6c28aaSamw #include <syslog.h> 116da6c28aaSamw #include <synch.h> 117da6c28aaSamw #include <sys/socket.h> 118da6c28aaSamw #include <arpa/inet.h> 119da6c28aaSamw 120da6c28aaSamw #include <smbns_netbios.h> 121da6c28aaSamw 122da6c28aaSamw #include <smbsrv/libsmbns.h> 123da6c28aaSamw 124da6c28aaSamw static int datagram_sock = -1; 125da6c28aaSamw static short datagram_id = 1; 126da6c28aaSamw static struct datagram_queue smb_datagram_queue; 127da6c28aaSamw static mutex_t smb_dgq_mtx; 128da6c28aaSamw 129da6c28aaSamw /* 130da6c28aaSamw * Function: smb_netbios_datagram_tick(void) 131da6c28aaSamw * 132da6c28aaSamw * Description: 133da6c28aaSamw * 134da6c28aaSamw * Called once a second to handle time to live timeouts in 135da6c28aaSamw * datagram assembly queue. 136da6c28aaSamw * 137da6c28aaSamw * Inputs: 138da6c28aaSamw * 139da6c28aaSamw * Returns: 140da6c28aaSamw * void -> Nothing at all... 141da6c28aaSamw */ 142da6c28aaSamw 143da6c28aaSamw void 144da6c28aaSamw smb_netbios_datagram_tick(void) 145da6c28aaSamw { 146da6c28aaSamw struct datagram *entry; 147da6c28aaSamw struct datagram *next; 148da6c28aaSamw 149da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx); 150da6c28aaSamw 151da6c28aaSamw for (entry = smb_datagram_queue.forw; 152da6c28aaSamw entry != (struct datagram *)((uintptr_t)&smb_datagram_queue); 153da6c28aaSamw entry = next) { 154da6c28aaSamw next = entry->forw; 155da6c28aaSamw if (--entry->discard_timer == 0) { 156da6c28aaSamw /* Toss it */ 157da6c28aaSamw QUEUE_CLIP(entry); 158da6c28aaSamw free(entry); 159da6c28aaSamw } 160da6c28aaSamw } 161da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx); 162da6c28aaSamw } 163da6c28aaSamw 164da6c28aaSamw void 165da6c28aaSamw smb_netbios_datagram_fini() 166da6c28aaSamw { 167da6c28aaSamw struct datagram *entry; 168da6c28aaSamw 169da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx); 170da6c28aaSamw while ((entry = smb_datagram_queue.forw) != 171da6c28aaSamw (struct datagram *)((uintptr_t)&smb_datagram_queue)) { 172da6c28aaSamw QUEUE_CLIP(entry); 173da6c28aaSamw free(entry); 174da6c28aaSamw } 175da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx); 176da6c28aaSamw } 177da6c28aaSamw 178da6c28aaSamw /* 179da6c28aaSamw * Function: int smb_netbios_send_Bnode_datagram(unsigned char *data, 180da6c28aaSamw * struct name_entry *source, struct name_entry *destination, 181da6c28aaSamw * uint32_t broadcast) 182da6c28aaSamw * 183da6c28aaSamw * Description from rfc1002: 184da6c28aaSamw * 185da6c28aaSamw * 5.3.1. B NODE TRANSMISSION OF NetBIOS DATAGRAMS 186da6c28aaSamw * 187da6c28aaSamw * PROCEDURE send_datagram(data, source, destination, broadcast) 188da6c28aaSamw * 189da6c28aaSamw * (* 190da6c28aaSamw * * user initiated processing on B node 191da6c28aaSamw * *) 192da6c28aaSamw * 193da6c28aaSamw * BEGIN 194da6c28aaSamw * group = FALSE; 195da6c28aaSamw * 196da6c28aaSamw * do name discovery on destination name, returns name type and 197da6c28aaSamw * IP address; 198da6c28aaSamw * 199da6c28aaSamw * IF name type is group name THEN 200da6c28aaSamw * BEGIN 201da6c28aaSamw * group = TRUE; 202da6c28aaSamw * END 203da6c28aaSamw * 204da6c28aaSamw * (* 205da6c28aaSamw * * build datagram service UDP packet; 206da6c28aaSamw * *) 207da6c28aaSamw * convert source and destination NetBIOS names into 208da6c28aaSamw * half-ASCII, biased encoded name; 209da6c28aaSamw * SOURCE_NAME = cat(source, SCOPE_ID); 210da6c28aaSamw * SOURCE_IP = this nodes IP address; 211da6c28aaSamw * SOURCE_PORT = DGM_SRVC_UDP_PORT; 212da6c28aaSamw * 213da6c28aaSamw * IF NetBIOS broadcast THEN 214da6c28aaSamw * BEGIN 215da6c28aaSamw * DESTINATION_NAME = cat("*", SCOPE_ID) 216da6c28aaSamw * END 217da6c28aaSamw * ELSE 218da6c28aaSamw * BEGIN 219da6c28aaSamw * DESTINATION_NAME = cat(destination, SCOPE_ID) 220da6c28aaSamw * END 221da6c28aaSamw * 222da6c28aaSamw * MSG_TYPE = select_one_from_set 223da6c28aaSamw * {BROADCAST, DIRECT_UNIQUE, DIRECT_GROUP} 224da6c28aaSamw * DGM_ID = next transaction id for Datagrams; 225da6c28aaSamw * DGM_LENGTH = length of data + length of second level encoded 226da6c28aaSamw * source and destination names; 227da6c28aaSamw * 228da6c28aaSamw * IF (length of the NetBIOS Datagram, including UDP and 229da6c28aaSamw * IP headers, > MAX_DATAGRAM_LENGTH) THEN 230da6c28aaSamw * BEGIN 231da6c28aaSamw * (* 232da6c28aaSamw * * fragment NetBIOS datagram into 2 UDP packets 233da6c28aaSamw * *) 234da6c28aaSamw * Put names into 1st UDP packet and any data that fits 235da6c28aaSamw * after names; 236da6c28aaSamw * Set MORE and FIRST bits in 1st UDP packets FLAGS; 237da6c28aaSamw * OFFSET in 1st UDP = 0; 238da6c28aaSamw * 239da6c28aaSamw * Replicate NetBIOS Datagram header from 1st UDP packet 240da6c28aaSamw * into 2nd UDP packet; 241da6c28aaSamw * Put rest of data in 2nd UDP packet; 242da6c28aaSamw * Clear MORE and FIRST bits in 2nd UDP packets FLAGS; 243da6c28aaSamw * OFFSET in 2nd UDP = DGM_LENGTH - number of name and 244da6c28aaSamw * data bytes in 1st UDP; 245da6c28aaSamw * END 246da6c28aaSamw * BEGIN 247da6c28aaSamw * (* 248da6c28aaSamw * * Only need one UDP packet 249da6c28aaSamw * *) 250da6c28aaSamw * USER_DATA = data; 251da6c28aaSamw * Clear MORE bit and set FIRST bit in FLAGS; 252da6c28aaSamw * OFFSET = 0; 253da6c28aaSamw * END 254da6c28aaSamw * 255da6c28aaSamw * IF (group == TRUE) OR (NetBIOS broadcast) THEN 256da6c28aaSamw * BEGIN 257da6c28aaSamw * send UDP packet(s) to BROADCAST_ADDRESS; 258da6c28aaSamw * END 259da6c28aaSamw * ELSE 260da6c28aaSamw * BEGIN 261da6c28aaSamw * send UDP packet(s) to IP address returned by name 262da6c28aaSamw * discovery; 263da6c28aaSamw * END 264da6c28aaSamw * END (* procedure *) 265da6c28aaSamw * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 266da6c28aaSamw * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 267da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 268da6c28aaSamw * | MSG_TYPE | FLAGS | DGM_ID | 269da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 270da6c28aaSamw * | SOURCE_IP | 271da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 272da6c28aaSamw * | SOURCE_PORT | DGM_LENGTH | 273da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 274da6c28aaSamw * | PACKET_OFFSET | 275da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 276da6c28aaSamw * 277da6c28aaSamw * MSG_TYPE values (in hexidecimal): 278da6c28aaSamw * 279da6c28aaSamw * 10 - DIRECT_UNIQUE DATAGRAM 280da6c28aaSamw * 11 - DIRECT_GROUP DATAGRAM 281da6c28aaSamw * 12 - BROADCAST DATAGRAM 282da6c28aaSamw * 13 - DATAGRAM ERROR 283da6c28aaSamw * 14 - DATAGRAM QUERY REQUEST 284da6c28aaSamw * 15 - DATAGRAM POSITIVE QUERY RESPONSE 285da6c28aaSamw * 16 - DATAGRAM NEGATIVE QUERY RESPONSE 286da6c28aaSamw * 287da6c28aaSamw * Bit definitions of the FLAGS field: 288da6c28aaSamw * 289da6c28aaSamw * 0 1 2 3 4 5 6 7 290da6c28aaSamw * +---+---+---+---+---+---+---+---+ 291da6c28aaSamw * | 0 | 0 | 0 | 0 | SNT | F | M | 292da6c28aaSamw * +---+---+---+---+---+---+---+---+ 293da6c28aaSamw * 294da6c28aaSamw * Symbol Bit(s) Description 295da6c28aaSamw * 296da6c28aaSamw * M 7 MORE flag, If set then more NetBIOS datagram 297da6c28aaSamw * fragments follow. 298da6c28aaSamw * 299da6c28aaSamw * F 6 FIRST packet flag, If set then this is first 300da6c28aaSamw * (and possibly only) fragment of NetBIOS 301da6c28aaSamw * datagram 302da6c28aaSamw * 303da6c28aaSamw * SNT 4,5 Source End-Node type: 304da6c28aaSamw * 00 = B node 305da6c28aaSamw * 01 = P node 306da6c28aaSamw * 10 = M node 307da6c28aaSamw * 11 = NBDD 308da6c28aaSamw * RESERVED 0-3 Reserved, must be zero (0) 309da6c28aaSamw * (But MS sets bit 3 in this field) 310da6c28aaSamw * 311da6c28aaSamw */ 312da6c28aaSamw 313da6c28aaSamw int 314da6c28aaSamw smb_netbios_datagram_send(struct name_entry *src, struct name_entry *dest, 315da6c28aaSamw unsigned char *data, int length) 316da6c28aaSamw { 317*7f667e74Sjose borrego smb_inaddr_t ipaddr; 318da6c28aaSamw size_t count, srclen, destlen, sinlen; 319da6c28aaSamw struct addr_entry *addr; 320da6c28aaSamw struct sockaddr_in sin; 321da6c28aaSamw char *buffer; 322da6c28aaSamw char ha_source[NETBIOS_DOMAIN_NAME_MAX]; 323da6c28aaSamw char ha_dest[NETBIOS_DOMAIN_NAME_MAX]; 324da6c28aaSamw 325da6c28aaSamw (void) smb_first_level_name_encode(src, (unsigned char *)ha_source, 326da6c28aaSamw sizeof (ha_source)); 327da6c28aaSamw srclen = strlen(ha_source) + 1; 328da6c28aaSamw 329da6c28aaSamw (void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest, 330da6c28aaSamw sizeof (ha_dest)); 331da6c28aaSamw destlen = strlen(ha_dest) + 1; 332da6c28aaSamw 333da6c28aaSamw /* give some extra room */ 334da6c28aaSamw buffer = (char *)malloc(MAX_DATAGRAM_LENGTH * 4); 335da6c28aaSamw if (buffer == 0) { 336da6c28aaSamw syslog(LOG_ERR, "netbios: datagram send (resource shortage)"); 337da6c28aaSamw return (-1); 338da6c28aaSamw } 339da6c28aaSamw 340da6c28aaSamw buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE; 341da6c28aaSamw switch (smb_node_type) { 342da6c28aaSamw case 'B': 343da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST; 344da6c28aaSamw break; 345da6c28aaSamw case 'P': 346da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST; 347da6c28aaSamw break; 348da6c28aaSamw case 'M': 349da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST; 350da6c28aaSamw break; 351da6c28aaSamw case 'H': 352da6c28aaSamw default: 353da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST; 354da6c28aaSamw break; 355da6c28aaSamw } 356da6c28aaSamw 357da6c28aaSamw datagram_id++; 358da6c28aaSamw BE_OUT16(&buffer[2], datagram_id); 359da6c28aaSamw (void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr, 360da6c28aaSamw sizeof (uint32_t)); 361da6c28aaSamw (void) memcpy(&buffer[8], &src->addr_list.sin.sin_port, 362da6c28aaSamw sizeof (uint16_t)); 363da6c28aaSamw BE_OUT16(&buffer[10], length + srclen + destlen); 364da6c28aaSamw BE_OUT16(&buffer[12], 0); 365da6c28aaSamw 366da6c28aaSamw bcopy(ha_source, &buffer[14], srclen); 367da6c28aaSamw bcopy(ha_dest, &buffer[14 + srclen], destlen); 368da6c28aaSamw bcopy(data, &buffer[14 + srclen + destlen], length); 369da6c28aaSamw count = &buffer[14 + srclen + destlen + length] - buffer; 370da6c28aaSamw 371da6c28aaSamw bzero(&sin, sizeof (sin)); 372da6c28aaSamw sin.sin_family = AF_INET; 373da6c28aaSamw sinlen = sizeof (sin); 374da6c28aaSamw addr = &dest->addr_list; 375da6c28aaSamw do { 376*7f667e74Sjose borrego ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; 377*7f667e74Sjose borrego ipaddr.a_family = AF_INET; 378da6c28aaSamw /* Don't send anything to myself... */ 379*7f667e74Sjose borrego if (smb_nic_exists(&ipaddr, B_FALSE)) 380da6c28aaSamw goto next; 381da6c28aaSamw 382*7f667e74Sjose borrego sin.sin_addr.s_addr = ipaddr.a_ipv4; 383da6c28aaSamw sin.sin_port = addr->sin.sin_port; 384da6c28aaSamw (void) sendto(datagram_sock, buffer, count, 0, 385da6c28aaSamw (struct sockaddr *)&sin, sinlen); 386da6c28aaSamw 387da6c28aaSamw next: addr = addr->forw; 388da6c28aaSamw } while (addr != &dest->addr_list); 389da6c28aaSamw free(buffer); 390da6c28aaSamw return (0); 391da6c28aaSamw } 392da6c28aaSamw 393da6c28aaSamw 394da6c28aaSamw int 395da6c28aaSamw smb_netbios_datagram_send_to_net(struct name_entry *src, 396da6c28aaSamw struct name_entry *dest, char *data, int length) 397da6c28aaSamw { 398*7f667e74Sjose borrego smb_inaddr_t ipaddr; 399da6c28aaSamw size_t count, srclen, destlen, sinlen; 400da6c28aaSamw struct addr_entry *addr; 401da6c28aaSamw struct sockaddr_in sin; 402da6c28aaSamw char *buffer; 403da6c28aaSamw char ha_source[NETBIOS_DOMAIN_NAME_MAX]; 404da6c28aaSamw char ha_dest[NETBIOS_DOMAIN_NAME_MAX]; 405da6c28aaSamw 406da6c28aaSamw (void) smb_first_level_name_encode(src, (unsigned char *)ha_source, 407da6c28aaSamw sizeof (ha_source)); 408da6c28aaSamw srclen = strlen(ha_source) + 1; 409da6c28aaSamw 410da6c28aaSamw (void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest, 411da6c28aaSamw sizeof (ha_dest)); 412da6c28aaSamw destlen = strlen(ha_dest) + 1; 413da6c28aaSamw 414da6c28aaSamw /* give some extra room */ 415da6c28aaSamw buffer = (char *)malloc(MAX_DATAGRAM_LENGTH * 4); 416da6c28aaSamw if (buffer == 0) { 417da6c28aaSamw syslog(LOG_ERR, "netbios: datagram send (resource shortage)"); 418da6c28aaSamw return (-1); 419da6c28aaSamw } 420da6c28aaSamw 421da6c28aaSamw buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE; 422da6c28aaSamw switch (smb_node_type) { 423da6c28aaSamw case 'B': 424da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST; 425da6c28aaSamw break; 426da6c28aaSamw case 'P': 427da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST; 428da6c28aaSamw break; 429da6c28aaSamw case 'M': 430da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST; 431da6c28aaSamw break; 432da6c28aaSamw case 'H': 433da6c28aaSamw default: 434da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST; 435da6c28aaSamw break; 436da6c28aaSamw } 437da6c28aaSamw 438da6c28aaSamw datagram_id++; 439da6c28aaSamw BE_OUT16(&buffer[2], datagram_id); 440da6c28aaSamw (void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr, 441da6c28aaSamw sizeof (uint32_t)); 442da6c28aaSamw (void) memcpy(&buffer[8], &src->addr_list.sin.sin_port, 443da6c28aaSamw sizeof (uint16_t)); 444da6c28aaSamw BE_OUT16(&buffer[10], length + srclen + destlen); 445da6c28aaSamw BE_OUT16(&buffer[12], 0); 446da6c28aaSamw 447da6c28aaSamw bcopy(ha_source, &buffer[14], srclen); 448da6c28aaSamw bcopy(ha_dest, &buffer[14 + srclen], destlen); 449da6c28aaSamw bcopy(data, &buffer[14 + srclen + destlen], length); 450da6c28aaSamw count = &buffer[14 + srclen + destlen + length] - buffer; 451da6c28aaSamw 452da6c28aaSamw bzero(&sin, sizeof (sin)); 453da6c28aaSamw sin.sin_family = AF_INET; 454da6c28aaSamw sinlen = sizeof (sin); 455da6c28aaSamw addr = &dest->addr_list; 456da6c28aaSamw do { 457*7f667e74Sjose borrego ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; 458*7f667e74Sjose borrego ipaddr.a_family = AF_INET; 459*7f667e74Sjose borrego if (smb_nic_exists(&ipaddr, B_FALSE)) 460da6c28aaSamw goto next; 4617b59d02dSjb 462*7f667e74Sjose borrego sin.sin_addr.s_addr = ipaddr.a_ipv4; 463da6c28aaSamw sin.sin_port = addr->sin.sin_port; 464da6c28aaSamw (void) sendto(datagram_sock, buffer, count, 0, 465da6c28aaSamw (struct sockaddr *)&sin, sinlen); 466da6c28aaSamw 467da6c28aaSamw next: addr = addr->forw; 468da6c28aaSamw } while (addr != &dest->addr_list); 469da6c28aaSamw free(buffer); 470da6c28aaSamw return (0); 471da6c28aaSamw } 472da6c28aaSamw 473da6c28aaSamw 474da6c28aaSamw int 475da6c28aaSamw smb_datagram_decode(struct datagram *datagram, int bytes) 476da6c28aaSamw { 477da6c28aaSamw unsigned char *ha_src; 478da6c28aaSamw unsigned char *ha_dest; 479da6c28aaSamw unsigned char *data; 480da6c28aaSamw 481da6c28aaSamw if (bytes < DATAGRAM_HEADER_LENGTH) { 482da6c28aaSamw syslog(LOG_ERR, "NbtDatagramDecode[%d]: too small packet", 483da6c28aaSamw bytes); 484da6c28aaSamw return (-1); 485da6c28aaSamw } 486da6c28aaSamw 487da6c28aaSamw ha_src = &datagram->rawbuf[DATAGRAM_HEADER_LENGTH]; 488da6c28aaSamw ha_dest = ha_src + strlen((char *)ha_src) + 1; 489da6c28aaSamw data = ha_dest + strlen((char *)ha_dest) + 1; 490da6c28aaSamw 491da6c28aaSamw bzero(&datagram->src, sizeof (struct name_entry)); 492da6c28aaSamw bzero(&datagram->dest, sizeof (struct name_entry)); 493da6c28aaSamw 494da6c28aaSamw datagram->rawbytes = bytes; 495da6c28aaSamw datagram->packet_type = datagram->rawbuf[0]; 496da6c28aaSamw datagram->flags = datagram->rawbuf[1]; 497da6c28aaSamw datagram->datagram_id = BE_IN16(&datagram->rawbuf[2]); 498da6c28aaSamw 499da6c28aaSamw datagram->src.addr_list.sinlen = sizeof (struct sockaddr_in); 500da6c28aaSamw (void) memcpy(&datagram->src.addr_list.sin.sin_addr.s_addr, 501da6c28aaSamw &datagram->rawbuf[4], sizeof (uint32_t)); 502da6c28aaSamw (void) memcpy(&datagram->src.addr_list.sin.sin_port, 503da6c28aaSamw &datagram->rawbuf[8], sizeof (uint16_t)); 504da6c28aaSamw datagram->src.addr_list.forw = datagram->src.addr_list.back = 505da6c28aaSamw &datagram->src.addr_list; 506da6c28aaSamw 507da6c28aaSamw datagram->data = data; 508da6c28aaSamw datagram->data_length = BE_IN16(&datagram->rawbuf[10]); 509da6c28aaSamw datagram->offset = BE_IN16(&datagram->rawbuf[12]); 510da6c28aaSamw 511da6c28aaSamw if (smb_first_level_name_decode(ha_src, &datagram->src) < 0) { 512da6c28aaSamw syslog(LOG_DEBUG, "NbtDatagram[%s]: invalid calling name", 513da6c28aaSamw inet_ntoa(datagram->src.addr_list.sin.sin_addr)); 514da6c28aaSamw syslog(LOG_DEBUG, "Calling name: <%02X>%32.32s", 515da6c28aaSamw ha_src[0], &ha_src[1]); 516da6c28aaSamw } 517da6c28aaSamw 518da6c28aaSamw datagram->dest.addr_list.forw = datagram->dest.addr_list.back = 519da6c28aaSamw &datagram->dest.addr_list; 520da6c28aaSamw 521da6c28aaSamw if (smb_first_level_name_decode(ha_dest, &datagram->dest) < 0) { 522da6c28aaSamw syslog(LOG_DEBUG, "NbtDatagram[%s]: invalid called name", 523da6c28aaSamw inet_ntoa(datagram->src.addr_list.sin.sin_addr)); 524da6c28aaSamw syslog(LOG_DEBUG, "Called name: <%02X>%32.32s", ha_dest[0], 525da6c28aaSamw &ha_dest[1]); 526da6c28aaSamw } 527da6c28aaSamw 528da6c28aaSamw return (0); 529da6c28aaSamw } 530da6c28aaSamw 531da6c28aaSamw 532da6c28aaSamw /* 533da6c28aaSamw * Function: int smb_netbios_process_BPM_datagram(unsigned char *packet, 534da6c28aaSamw * struct addr_entry *addr) 535da6c28aaSamw * 536da6c28aaSamw * Description from rfc1002: 537da6c28aaSamw * 538da6c28aaSamw * 5.3.3. RECEPTION OF NetBIOS DATAGRAMS BY ALL NODES 539da6c28aaSamw * 540da6c28aaSamw * The following algorithm discards out of order NetBIOS Datagram 541da6c28aaSamw * fragments. An implementation which reassembles out of order 542da6c28aaSamw * NetBIOS Datagram fragments conforms to this specification. The 543da6c28aaSamw * fragment discard timer is initialized to the value FRAGMENT_TIMEOUT. 544da6c28aaSamw * This value should be user configurable. The default value is 545da6c28aaSamw * given in Section 6, "Defined Constants and Variables". 546da6c28aaSamw * 547da6c28aaSamw * PROCEDURE datagram_packet(packet) 548da6c28aaSamw * 549da6c28aaSamw * (* 550da6c28aaSamw * * processing initiated by datagram packet reception 551da6c28aaSamw * * on B, P and M nodes 552da6c28aaSamw * *) 553da6c28aaSamw * BEGIN 554da6c28aaSamw * (* 555da6c28aaSamw * * if this node is a P node, ignore 556da6c28aaSamw * * broadcast packets. 557da6c28aaSamw * *) 558da6c28aaSamw * 559da6c28aaSamw * IF this is a P node AND incoming packet is 560da6c28aaSamw * a broadcast packet THEN 561da6c28aaSamw * BEGIN 562da6c28aaSamw * discard packet; 563da6c28aaSamw * END 564da6c28aaSamw * 565da6c28aaSamw * CASE packet type OF 566da6c28aaSamw * 567da6c28aaSamw * DATAGRAM SERVICE: 568da6c28aaSamw * BEGIN 569da6c28aaSamw * IF FIRST bit in FLAGS is set THEN 570da6c28aaSamw * BEGIN 571da6c28aaSamw * IF MORE bit in FLAGS is set THEN 572da6c28aaSamw * BEGIN 573da6c28aaSamw * Save 1st UDP packet of the Datagram; 574da6c28aaSamw * Set this Datagrams fragment discard 575da6c28aaSamw * timer to FRAGMENT_TIMEOUT; 576da6c28aaSamw * return; 577da6c28aaSamw * END 578da6c28aaSamw * ELSE 579da6c28aaSamw * Datagram is composed of a single 580da6c28aaSamw * UDP packet; 581da6c28aaSamw * END 582da6c28aaSamw * ELSE 583da6c28aaSamw * BEGIN 584da6c28aaSamw * (* Have the second fragment of a Datagram *) 585da6c28aaSamw * 586da6c28aaSamw * Search for 1st fragment by source IP address 587da6c28aaSamw * and DGM_ID; 588da6c28aaSamw * IF found 1st fragment THEN 589da6c28aaSamw * Process both UDP packets; 590da6c28aaSamw * ELSE 591da6c28aaSamw * BEGIN 592da6c28aaSamw * discard 2nd fragment UDP packet; 593da6c28aaSamw * return; 594da6c28aaSamw * END 595da6c28aaSamw * END 596da6c28aaSamw * 597da6c28aaSamw * IF DESTINATION_NAME is '*' THEN 598da6c28aaSamw * BEGIN 599da6c28aaSamw * (* NetBIOS broadcast *) 600da6c28aaSamw * 601da6c28aaSamw * deliver USER_DATA from UDP packet(s) to all 602da6c28aaSamw * outstanding receive broadcast 603da6c28aaSamw * datagram requests; 604da6c28aaSamw * return; 605da6c28aaSamw * END 606da6c28aaSamw * ELSE 607da6c28aaSamw * BEGIN (* non-broadcast *) 608da6c28aaSamw * (* Datagram for Unique or Group Name *) 609da6c28aaSamw * 610da6c28aaSamw * IF DESTINATION_NAME is not present in the 611da6c28aaSamw * local name table THEN 612da6c28aaSamw * BEGIN 613da6c28aaSamw * (* destination not present *) 614da6c28aaSamw * build DATAGRAM ERROR packet, clear 615da6c28aaSamw * FIRST and MORE bit, put in 616da6c28aaSamw * this nodes IP and PORT, set 617da6c28aaSamw * ERROR_CODE; 618da6c28aaSamw * send DATAGRAM ERROR packet to 619da6c28aaSamw * source IP address and port 620da6c28aaSamw * of UDP; 621da6c28aaSamw * discard UDP packet(s); 622da6c28aaSamw * return; 623da6c28aaSamw * END 624da6c28aaSamw * ELSE 625da6c28aaSamw * BEGIN (* good *) 626da6c28aaSamw * (* 627da6c28aaSamw * * Replicate received NetBIOS datagram for 628da6c28aaSamw * * each recipient 629da6c28aaSamw * *) 630da6c28aaSamw * FOR EACH pending NetBIOS users receive 631da6c28aaSamw * datagram operation 632da6c28aaSamw * BEGIN 633da6c28aaSamw * IF source name of operation 634da6c28aaSamw * matches destination name 635da6c28aaSamw * of packet THEN 636da6c28aaSamw * BEGIN 637da6c28aaSamw * deliver USER_DATA from UDP 638da6c28aaSamw * packet(s); 639da6c28aaSamw * END 640da6c28aaSamw * END (* for each *) 641da6c28aaSamw * return; 642da6c28aaSamw * END (* good *) 643da6c28aaSamw * END (* non-broadcast *) 644da6c28aaSamw * END (* datagram service *) 645da6c28aaSamw * 646da6c28aaSamw * DATAGRAM ERROR: 647da6c28aaSamw * BEGIN 648da6c28aaSamw * (* 649da6c28aaSamw * * name service returned incorrect information 650da6c28aaSamw * *) 651da6c28aaSamw * 652da6c28aaSamw * inform local name service that incorrect 653da6c28aaSamw * information was provided; 654da6c28aaSamw * 655da6c28aaSamw * IF this is a P or M node THEN 656da6c28aaSamw * BEGIN 657da6c28aaSamw * (* 658da6c28aaSamw * * tell NetBIOS Name Server that it may 659da6c28aaSamw * * have given incorrect information 660da6c28aaSamw * *) 661da6c28aaSamw * 662da6c28aaSamw * send NAME RELEASE REQUEST with name 663da6c28aaSamw * and incorrect IP address to NetBIOS 664da6c28aaSamw * Name Server; 665da6c28aaSamw * END 666da6c28aaSamw * END (* datagram error *) 667da6c28aaSamw * 668da6c28aaSamw * END (* case *) 669da6c28aaSamw * END 670da6c28aaSamw */ 671da6c28aaSamw 672da6c28aaSamw static struct datagram * 673da6c28aaSamw smb_netbios_datagram_getq(struct datagram *datagram) 674da6c28aaSamw { 675da6c28aaSamw struct datagram *prev = 0; 676da6c28aaSamw 677da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx); 678da6c28aaSamw for (prev = smb_datagram_queue.forw; 679da6c28aaSamw prev != (struct datagram *)((uintptr_t)&smb_datagram_queue); 680da6c28aaSamw prev = prev->forw) { 681da6c28aaSamw if (prev->src.addr_list.sin.sin_addr.s_addr == 682da6c28aaSamw datagram->src.addr_list.sin.sin_addr.s_addr) { 683da6c28aaSamw /* Something waiting */ 684da6c28aaSamw QUEUE_CLIP(prev); 685da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx); 686da6c28aaSamw bcopy(datagram->data, &prev->data[prev->data_length], 687da6c28aaSamw datagram->data_length); 688da6c28aaSamw prev->data_length += datagram->data_length; 689da6c28aaSamw free(datagram); 690da6c28aaSamw return (prev); 691da6c28aaSamw } 692da6c28aaSamw } 693da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx); 694da6c28aaSamw 695da6c28aaSamw return (0); 696da6c28aaSamw } 697da6c28aaSamw 698da6c28aaSamw static void 699da6c28aaSamw smb_netbios_BPM_datagram(struct datagram *datagram) 700da6c28aaSamw { 701da6c28aaSamw struct name_entry *entry = 0; 702da6c28aaSamw struct datagram *qpacket = 0; 703da6c28aaSamw pthread_t browser_dispatch; 704da6c28aaSamw 705da6c28aaSamw switch (datagram->packet_type) { 706da6c28aaSamw case DATAGRAM_TYPE_BROADCAST : 707da6c28aaSamw if (smb_node_type == 'P') { 708da6c28aaSamw /* 709da6c28aaSamw * if this node is a P node, ignore 710da6c28aaSamw * broadcast packets. 711da6c28aaSamw */ 712da6c28aaSamw break; 713da6c28aaSamw } 714da6c28aaSamw /* FALLTHROUGH */ 715da6c28aaSamw 716da6c28aaSamw case DATAGRAM_TYPE_DIRECT_UNIQUE : 717da6c28aaSamw case DATAGRAM_TYPE_DIRECT_GROUP : 718da6c28aaSamw if ((datagram->flags & DATAGRAM_FLAGS_FIRST) != 0) { 719da6c28aaSamw if (datagram->flags & DATAGRAM_FLAGS_MORE) { 720da6c28aaSamw /* Save 1st UDP packet of the Datagram */ 721da6c28aaSamw datagram->discard_timer = FRAGMENT_TIMEOUT; 722da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx); 723da6c28aaSamw QUEUE_INSERT_TAIL(&smb_datagram_queue, datagram) 724da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx); 725da6c28aaSamw return; 726da6c28aaSamw } 727da6c28aaSamw /* process datagram */ 728da6c28aaSamw } else { 729da6c28aaSamw qpacket = smb_netbios_datagram_getq(datagram); 730da6c28aaSamw if (qpacket) { 731da6c28aaSamw datagram = qpacket; 732da6c28aaSamw goto process_datagram; 733da6c28aaSamw } 734da6c28aaSamw break; 735da6c28aaSamw } 736da6c28aaSamw 737da6c28aaSamw process_datagram: 738da6c28aaSamw entry = 0; 739da6c28aaSamw if ((strcmp((char *)datagram->dest.name, "*") == 0) || 740da6c28aaSamw ((entry = 741da6c28aaSamw smb_netbios_cache_lookup(&datagram->dest)) != 0)) { 742da6c28aaSamw if (entry) { 743da6c28aaSamw int is_local = IS_LOCAL(entry->attributes); 744da6c28aaSamw smb_netbios_cache_unlock_entry(entry); 745da6c28aaSamw 746da6c28aaSamw if (is_local) { 747da6c28aaSamw (void) pthread_create(&browser_dispatch, 748da6c28aaSamw 0, smb_browser_dispatch, 749da6c28aaSamw (void *)datagram); 750da6c28aaSamw (void) pthread_detach(browser_dispatch); 751da6c28aaSamw return; 752da6c28aaSamw } 753da6c28aaSamw } 754da6c28aaSamw 755da6c28aaSamw datagram->rawbuf[0] = DATAGRAM_TYPE_ERROR_DATAGRAM; 756da6c28aaSamw datagram->rawbuf[1] &= DATAGRAM_FLAGS_SRC_TYPE; 757da6c28aaSamw 758da6c28aaSamw (void) memcpy(&datagram->rawbuf[4], 759da6c28aaSamw &datagram->src.addr_list.sin.sin_addr.s_addr, 760da6c28aaSamw sizeof (uint32_t)); 761da6c28aaSamw BE_OUT16(&datagram->rawbuf[8], DGM_SRVC_UDP_PORT); 762da6c28aaSamw 763da6c28aaSamw (void) sendto(datagram_sock, datagram->rawbuf, 764da6c28aaSamw datagram->rawbytes, 0, 765da6c28aaSamw (struct sockaddr *)&datagram->src.addr_list.sin, 766da6c28aaSamw datagram->src.addr_list.sinlen); 767da6c28aaSamw } 768da6c28aaSamw break; 769da6c28aaSamw 770da6c28aaSamw case DATAGRAM_TYPE_ERROR_DATAGRAM : 771da6c28aaSamw break; 772da6c28aaSamw } 773da6c28aaSamw free(datagram); 774da6c28aaSamw } 775da6c28aaSamw 776da6c28aaSamw 777da6c28aaSamw /* 778da6c28aaSamw * smb_netbios_process_NBDD_datagram 779da6c28aaSamw * 780da6c28aaSamw * Description from rfc1002: 781da6c28aaSamw * 782da6c28aaSamw * 783da6c28aaSamw * 5.3.4. PROTOCOLS FOR THE NBDD 784da6c28aaSamw * 785da6c28aaSamw * The key to NetBIOS Datagram forwarding service is the packet 786da6c28aaSamw * delivered to the destination end node must have the same NetBIOS 787da6c28aaSamw * header as if the source end node sent the packet directly to the 788da6c28aaSamw * destination end node. Consequently, the NBDD does not reassemble 789da6c28aaSamw * NetBIOS Datagrams. It forwards the UDP packet as is. 790da6c28aaSamw * 791da6c28aaSamw * PROCEDURE datagram_packet(packet) 792da6c28aaSamw * 793da6c28aaSamw * (* 794da6c28aaSamw * * processing initiated by a incoming datagram service 795da6c28aaSamw * * packet on a NBDD node. 796da6c28aaSamw * *) 797da6c28aaSamw * 798da6c28aaSamw * BEGIN 799da6c28aaSamw * CASE packet type OF 800da6c28aaSamw * 801da6c28aaSamw * DATAGRAM SERVICE: 802da6c28aaSamw * BEGIN 803da6c28aaSamw * IF packet was sent as a directed 804da6c28aaSamw * NetBIOS datagram THEN 805da6c28aaSamw * BEGIN 806da6c28aaSamw * (* 807da6c28aaSamw * * provide group forwarding service 808da6c28aaSamw * * 809da6c28aaSamw * * Forward datagram to each member of the 810da6c28aaSamw * * group. Can forward via: 811da6c28aaSamw * * 1) get list of group members and send 812da6c28aaSamw * * the DATAGRAM SERVICE packet unicast 813da6c28aaSamw * * to each 814da6c28aaSamw * * 2) use Group Multicast, if available 815da6c28aaSamw * * 3) combination of 1) and 2) 816da6c28aaSamw * *) 817da6c28aaSamw * 818da6c28aaSamw * ... 819da6c28aaSamw * 820da6c28aaSamw * END 821da6c28aaSamw * 822da6c28aaSamw * ELSE 823da6c28aaSamw * BEGIN 824da6c28aaSamw * (* 825da6c28aaSamw * * provide broadcast forwarding service 826da6c28aaSamw * * 827da6c28aaSamw * * Forward datagram to every node in the 828da6c28aaSamw * * NetBIOS scope. Can forward via: 829da6c28aaSamw * * 1) get list of group members and send 830da6c28aaSamw * * the DATAGRAM SERVICE packet unicast 831da6c28aaSamw * * to each 832da6c28aaSamw * * 2) use Group Multicast, if available 833da6c28aaSamw * * 3) combination of 1) and 2) 834da6c28aaSamw * *) 835da6c28aaSamw * 836da6c28aaSamw * ... 837da6c28aaSamw * 838da6c28aaSamw * END 839da6c28aaSamw * END (* datagram service *) 840da6c28aaSamw * 841da6c28aaSamw * DATAGRAM ERROR: 842da6c28aaSamw * BEGIN 843da6c28aaSamw * (* 844da6c28aaSamw * * Should never receive these because Datagrams 845da6c28aaSamw * * forwarded have source end node IP address and 846da6c28aaSamw * * port in NetBIOS header. 847da6c28aaSamw * *) 848da6c28aaSamw * 849da6c28aaSamw * send DELETE NAME REQUEST with incorrect name and 850da6c28aaSamw * IP address to NetBIOS Name Server; 851da6c28aaSamw * 852da6c28aaSamw * END (* datagram error *) 853da6c28aaSamw * 854da6c28aaSamw * DATAGRAM QUERY REQUEST: 855da6c28aaSamw * BEGIN 856da6c28aaSamw * IF can send packet to DESTINATION_NAME THEN 857da6c28aaSamw * BEGIN 858da6c28aaSamw * (* 859da6c28aaSamw * * NBDD is able to relay Datagrams for 860da6c28aaSamw * * this name 861da6c28aaSamw * *) 862da6c28aaSamw * 863da6c28aaSamw * send POSITIVE DATAGRAM QUERY RESPONSE to 864da6c28aaSamw * REQUEST source IP address and UDP port 865da6c28aaSamw * with requests DGM_ID; 866da6c28aaSamw * END 867da6c28aaSamw * ELSE 868da6c28aaSamw * BEGIN 869da6c28aaSamw * (* 870da6c28aaSamw * * NBDD is NOT able to relay Datagrams for 871da6c28aaSamw * * this name 872da6c28aaSamw * *) 873da6c28aaSamw * 874da6c28aaSamw * send NEGATIVE DATAGRAM QUERY RESPONSE to 875da6c28aaSamw * REQUEST source IP address and UDP port 876da6c28aaSamw * 877da6c28aaSamw * with requests DGM_ID; 878da6c28aaSamw * END 879da6c28aaSamw * END (* datagram query request *) 880da6c28aaSamw * 881da6c28aaSamw * END (* case *) 882da6c28aaSamw * END (* procedure *) 883da6c28aaSamw */ 884da6c28aaSamw 885da6c28aaSamw 886da6c28aaSamw /* 887da6c28aaSamw * Function: int smb_netbios_datagram_service_daemon(void) 888da6c28aaSamw * 889da6c28aaSamw * Description: 890da6c28aaSamw * 891da6c28aaSamw * 4.4. DATAGRAM SERVICE PACKETS 892da6c28aaSamw * 893da6c28aaSamw * 4.4.1. NetBIOS DATAGRAM HEADER 894da6c28aaSamw * 895da6c28aaSamw * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 896da6c28aaSamw * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 897da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 898da6c28aaSamw * | MSG_TYPE | FLAGS | DGM_ID | 899da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 900da6c28aaSamw * | SOURCE_IP | 901da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 902da6c28aaSamw * | SOURCE_PORT | DGM_LENGTH | 903da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 904da6c28aaSamw * | PACKET_OFFSET | 905da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 906da6c28aaSamw * 907da6c28aaSamw * MSG_TYPE values (in hexidecimal): 908da6c28aaSamw * 909da6c28aaSamw * 10 - DIRECT_UNIQUE DATAGRAM 910da6c28aaSamw * 11 - DIRECT_GROUP DATAGRAM 911da6c28aaSamw * 12 - BROADCAST DATAGRAM 912da6c28aaSamw * 13 - DATAGRAM ERROR 913da6c28aaSamw * 14 - DATAGRAM QUERY REQUEST 914da6c28aaSamw * 15 - DATAGRAM POSITIVE QUERY RESPONSE 915da6c28aaSamw * 16 - DATAGRAM NEGATIVE QUERY RESPONSE 916da6c28aaSamw * 917da6c28aaSamw * Bit definitions of the FLAGS field: 918da6c28aaSamw * 919da6c28aaSamw * 0 1 2 3 4 5 6 7 920da6c28aaSamw * +---+---+---+---+---+---+---+---+ 921da6c28aaSamw * | 0 | 0 | 0 | 0 | SNT | F | M | 922da6c28aaSamw * +---+---+---+---+---+---+---+---+ 923da6c28aaSamw * 924da6c28aaSamw * Symbol Bit(s) Description 925da6c28aaSamw * 926da6c28aaSamw * M 7 MORE flag, If set then more NetBIOS datagram 927da6c28aaSamw * fragments follow. 928da6c28aaSamw * 929da6c28aaSamw * F 6 FIRST packet flag, If set then this is first 930da6c28aaSamw * (and possibly only) fragment of NetBIOS 931da6c28aaSamw * datagram 932da6c28aaSamw * 933da6c28aaSamw * SNT 4,5 Source End-Node type: 934da6c28aaSamw * 00 = B node 935da6c28aaSamw * 01 = P node 936da6c28aaSamw * 10 = M node 937da6c28aaSamw * 11 = NBDD 938da6c28aaSamw * RESERVED 0-3 Reserved, must be zero (0) 939da6c28aaSamw * 940da6c28aaSamw * Inputs: 941da6c28aaSamw * Nothing 942da6c28aaSamw * 943da6c28aaSamw * Returns: 944da6c28aaSamw * int -> Description 945da6c28aaSamw */ 946da6c28aaSamw 947da6c28aaSamw /*ARGSUSED*/ 948da6c28aaSamw void * 949da6c28aaSamw smb_netbios_datagram_service_daemon(void *arg) 950da6c28aaSamw { 951da6c28aaSamw struct sockaddr_in sin; 952da6c28aaSamw struct datagram *datagram; 953da6c28aaSamw int bytes, flag = 1; 954*7f667e74Sjose borrego smb_inaddr_t ipaddr; 955da6c28aaSamw 956da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx); 957da6c28aaSamw bzero(&smb_datagram_queue, sizeof (smb_datagram_queue)); 958da6c28aaSamw smb_datagram_queue.forw = smb_datagram_queue.back = 959da6c28aaSamw (struct datagram *)((uintptr_t)&smb_datagram_queue); 960da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx); 961da6c28aaSamw 962da6c28aaSamw if ((datagram_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 963da6c28aaSamw syslog(LOG_ERR, 964da6c28aaSamw "smbd: Could not create AF_INET, SOCK_DGRAM, socket"); 965da6c28aaSamw smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_FAILED, 1); 966da6c28aaSamw return (0); 967da6c28aaSamw } 968da6c28aaSamw 969da6c28aaSamw bzero(&sin, sizeof (sin)); 970da6c28aaSamw sin.sin_family = AF_INET; 971da6c28aaSamw sin.sin_port = htons(DGM_SRVC_UDP_PORT); 972da6c28aaSamw if (bind(datagram_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) { 973da6c28aaSamw syslog(LOG_ERR, "smbd: Bind to name service port %d failed", 974da6c28aaSamw DGM_SRVC_UDP_PORT); 975da6c28aaSamw (void) close(datagram_sock); 976da6c28aaSamw smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_FAILED, 1); 977da6c28aaSamw return (0); 978da6c28aaSamw } 979da6c28aaSamw (void) setsockopt(datagram_sock, SOL_SOCKET, SO_BROADCAST, &flag, 980da6c28aaSamw sizeof (flag)); 981da6c28aaSamw 982da6c28aaSamw smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_RUNNING, 1); 983da6c28aaSamw 984da6c28aaSamw while (((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) || 985da6c28aaSamw (nb_status.state & NETBIOS_BROWSER_RUNNING)) { 986da6c28aaSamw if ((datagram = (struct datagram *) 987da6c28aaSamw malloc(sizeof (struct datagram))) == 0) { 988da6c28aaSamw /* Sleep for 10 sec and try again */ 989da6c28aaSamw (void) sleep(10); 990da6c28aaSamw continue; 991da6c28aaSamw } 992da6c28aaSamw 993da6c28aaSamw ignore: bzero(&datagram->inaddr, sizeof (struct addr_entry)); 994da6c28aaSamw datagram->inaddr.sinlen = sizeof (datagram->inaddr.sin); 995da6c28aaSamw datagram->inaddr.forw = datagram->inaddr.back = 996da6c28aaSamw &datagram->inaddr; 997da6c28aaSamw 998da6c28aaSamw if ((bytes = recvfrom(datagram_sock, datagram->rawbuf, 999da6c28aaSamw MAX_DATAGRAM_LENGTH, 0, 1000da6c28aaSamw (struct sockaddr *)&datagram->inaddr.sin, 1001da6c28aaSamw &datagram->inaddr.sinlen)) < 0) { 1002da6c28aaSamw syslog(LOG_ERR, 1003da6c28aaSamw "smbd: NETBIOS datagram - recvfrom failed"); 1004da6c28aaSamw smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_FAILED, 1); 1005da6c28aaSamw break; 1006da6c28aaSamw } 1007da6c28aaSamw 1008da6c28aaSamw /* Ignore any incoming packets from myself... */ 1009*7f667e74Sjose borrego ipaddr.a_ipv4 = datagram->inaddr.sin.sin_addr.s_addr; 1010*7f667e74Sjose borrego ipaddr.a_family = AF_INET; 1011*7f667e74Sjose borrego if (smb_nic_exists(&ipaddr, B_FALSE)) { 1012da6c28aaSamw goto ignore; 1013da6c28aaSamw } 10147b59d02dSjb 1015da6c28aaSamw if (smb_datagram_decode(datagram, bytes) < 0) 1016da6c28aaSamw goto ignore; 1017da6c28aaSamw 1018da6c28aaSamw /* 1019da6c28aaSamw * This code was doing the wrong thing with responses from a 1020da6c28aaSamw * Windows2000 PDC because both DATAGRAM_FLAGS_H_NODE and 1021da6c28aaSamw * DATAGRAM_FLAGS_NBDD are defined to be the same value (see 1022da6c28aaSamw * netbios.h). Since the Windows2000 PDC wants to be an H-Node, 1023da6c28aaSamw * we need to handle all messages via smb_netbios_BPM_datagram. 1024da6c28aaSamw * 1025da6c28aaSamw * if ((datagram->flags & DATAGRAM_FLAGS_SRC_TYPE) == 1026da6c28aaSamw * DATAGRAM_FLAGS_NBDD) 1027da6c28aaSamw * smb_netbios_NBDD_datagram(datagram); 1028da6c28aaSamw * else 1029da6c28aaSamw * smb_netbios_BPM_datagram(datagram); 1030da6c28aaSamw */ 1031da6c28aaSamw 1032da6c28aaSamw smb_netbios_BPM_datagram(datagram); 1033da6c28aaSamw } 1034da6c28aaSamw 1035da6c28aaSamw smb_netbios_chg_status(NETBIOS_DATAGRAM_SVC_RUNNING, 0); 1036da6c28aaSamw 1037da6c28aaSamw (void) mutex_lock(&nb_status.mtx); 1038da6c28aaSamw while (nb_status.state & NETBIOS_BROWSER_RUNNING) 1039da6c28aaSamw (void) cond_wait(&nb_status.cv, &nb_status.mtx); 1040da6c28aaSamw (void) mutex_unlock(&nb_status.mtx); 1041da6c28aaSamw 1042da6c28aaSamw (void) close(datagram_sock); 1043da6c28aaSamw smb_netbios_datagram_fini(); 1044da6c28aaSamw syslog(LOG_DEBUG, "smbd: Netbios Datagram Service is down\n"); 1045da6c28aaSamw return (0); 1046da6c28aaSamw } 1047da6c28aaSamw 1048da6c28aaSamw static char 1049da6c28aaSamw /* LINTED - E_STATIC_UNUSED */ 1050da6c28aaSamw nb_fmt_flags(unsigned char flags) 1051da6c28aaSamw { 1052da6c28aaSamw switch (flags & DATAGRAM_FLAGS_SRC_TYPE) { 1053da6c28aaSamw case DATAGRAM_FLAGS_B_NODE: return ('B'); 1054da6c28aaSamw case DATAGRAM_FLAGS_P_NODE: return ('P'); 1055da6c28aaSamw case DATAGRAM_FLAGS_M_NODE: return ('M'); 1056da6c28aaSamw case DATAGRAM_FLAGS_H_NODE: return ('H'); 1057da6c28aaSamw default: return ('?'); 1058da6c28aaSamw } 1059da6c28aaSamw } 1060