/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Description: * * Contains base code for netbios datagram service. * * Relavent sections from RFC1002: * * 5.3. NetBIOS DATAGRAM SERVICE PROTOCOLS * * The following are GLOBAL variables and should be NetBIOS user * configurable: * * - SCOPE_ID: the non-leaf section of the domain name preceded by a * '.' which represents the domain of the NetBIOS scope for the * NetBIOS name. The following protocol description only supports * single scope operation. * * - MAX_DATAGRAM_LENGTH: the maximum length of an IP datagram. The * minimal maximum length defined in for IP is 576 bytes. This * value is used when determining whether to fragment a NetBIOS * datagram. Implementations are expected to be capable of * receiving unfragmented NetBIOS datagrams up to their maximum * size. * * - BROADCAST_ADDRESS: the IP address B-nodes use to send datagrams * with group name destinations and broadcast datagrams. The * default is the IP broadcast address for a single IP network. * * * The following are Defined Constants for the NetBIOS Datagram * Service: * * - IPPORT_NETBIOS_DGM: the globally well-known UDP port allocated * where the NetBIOS Datagram Service receives UDP packets. See * section 6, "Defined Constants", for its value. */ /* * * 6. DEFINED CONSTANTS AND VARIABLES * * GENERAL: * * SCOPE_ID The name of the NetBIOS scope. * * This is expressed as a character * string meeting the requirements of * the domain name system and without * a leading or trailing "dot". * * An implementation may elect to make * this a single global value for the * node or allow it to be specified * with each separate NetBIOS name * (thus permitting cross-scope * references.) * * BROADCAST_ADDRESS An IP address composed of the * node network and subnetwork * numbers with all remaining bits set * to one. * * I.e. "Specific subnet" broadcast * addressing according to section 2.3 * of RFC 950. * * BCAST_REQ_RETRY_TIMEOUT 250 milliseconds. * An adaptive timer may be used. * * BCAST_REQ_RETRY_COUNT 3 * * UCAST_REQ_RETRY_TIMEOUT 5 seconds * An adaptive timer may be used. * * UCAST_REQ_RETRY_COUNT 3 * * MAX_DATAGRAM_LENGTH 576 bytes (default) * * DATAGRAM SERVICE: * * IPPORT_NETBIOS_DGM 138 (decimal) * * FRAGMENT_TO 2 seconds (default) */ #include #include #include #include #include #include #include #include #include #include #include static int datagram_sock = -1; static short datagram_id = 1; static struct datagram_queue smb_datagram_queue; static mutex_t smb_dgq_mtx; static void smb_netbios_datagram_error(unsigned char *buf); /* * Function: smb_netbios_datagram_tick(void) * * Description: * * Called once a second to handle time to live timeouts in * datagram assembly queue. * * Inputs: * * Returns: * void -> Nothing at all... */ void smb_netbios_datagram_tick(void) { struct datagram *entry; struct datagram *next; (void) mutex_lock(&smb_dgq_mtx); for (entry = smb_datagram_queue.forw; entry != (struct datagram *)((uintptr_t)&smb_datagram_queue); entry = next) { next = entry->forw; if (--entry->discard_timer == 0) { /* Toss it */ QUEUE_CLIP(entry); free(entry); } } (void) mutex_unlock(&smb_dgq_mtx); } void smb_netbios_datagram_fini() { struct datagram *entry; (void) mutex_lock(&smb_dgq_mtx); while ((entry = smb_datagram_queue.forw) != (struct datagram *)((uintptr_t)&smb_datagram_queue)) { QUEUE_CLIP(entry); free(entry); } (void) mutex_unlock(&smb_dgq_mtx); } /* * Function: int smb_netbios_send_Bnode_datagram(unsigned char *data, * struct name_entry *source, struct name_entry *destination, * uint32_t broadcast) * * Description from rfc1002: * * 5.3.1. B NODE TRANSMISSION OF NetBIOS DATAGRAMS * * PROCEDURE send_datagram(data, source, destination, broadcast) * * (* * * user initiated processing on B node * *) * * BEGIN * group = FALSE; * * do name discovery on destination name, returns name type and * IP address; * * IF name type is group name THEN * BEGIN * group = TRUE; * END * * (* * * build datagram service UDP packet; * *) * convert source and destination NetBIOS names into * half-ASCII, biased encoded name; * SOURCE_NAME = cat(source, SCOPE_ID); * SOURCE_IP = this nodes IP address; * SOURCE_PORT = IPPORT_NETBIOS_DGM; * * IF NetBIOS broadcast THEN * BEGIN * DESTINATION_NAME = cat("*", SCOPE_ID) * END * ELSE * BEGIN * DESTINATION_NAME = cat(destination, SCOPE_ID) * END * * MSG_TYPE = select_one_from_set * {BROADCAST, DIRECT_UNIQUE, DIRECT_GROUP} * DGM_ID = next transaction id for Datagrams; * DGM_LENGTH = length of data + length of second level encoded * source and destination names; * * IF (length of the NetBIOS Datagram, including UDP and * IP headers, > MAX_DATAGRAM_LENGTH) THEN * BEGIN * (* * * fragment NetBIOS datagram into 2 UDP packets * *) * Put names into 1st UDP packet and any data that fits * after names; * Set MORE and FIRST bits in 1st UDP packets FLAGS; * OFFSET in 1st UDP = 0; * * Replicate NetBIOS Datagram header from 1st UDP packet * into 2nd UDP packet; * Put rest of data in 2nd UDP packet; * Clear MORE and FIRST bits in 2nd UDP packets FLAGS; * OFFSET in 2nd UDP = DGM_LENGTH - number of name and * data bytes in 1st UDP; * END * BEGIN * (* * * Only need one UDP packet * *) * USER_DATA = data; * Clear MORE bit and set FIRST bit in FLAGS; * OFFSET = 0; * END * * IF (group == TRUE) OR (NetBIOS broadcast) THEN * BEGIN * send UDP packet(s) to BROADCAST_ADDRESS; * END * ELSE * BEGIN * send UDP packet(s) to IP address returned by name * discovery; * END * END (* procedure *) * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MSG_TYPE | FLAGS | DGM_ID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SOURCE_IP | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SOURCE_PORT | DGM_LENGTH | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | PACKET_OFFSET | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * MSG_TYPE values (in hexidecimal): * * 10 - DIRECT_UNIQUE DATAGRAM * 11 - DIRECT_GROUP DATAGRAM * 12 - BROADCAST DATAGRAM * 13 - DATAGRAM ERROR * 14 - DATAGRAM QUERY REQUEST * 15 - DATAGRAM POSITIVE QUERY RESPONSE * 16 - DATAGRAM NEGATIVE QUERY RESPONSE * * Bit definitions of the FLAGS field: * * 0 1 2 3 4 5 6 7 * +---+---+---+---+---+---+---+---+ * | 0 | 0 | 0 | 0 | SNT | F | M | * +---+---+---+---+---+---+---+---+ * * Symbol Bit(s) Description * * M 7 MORE flag, If set then more NetBIOS datagram * fragments follow. * * F 6 FIRST packet flag, If set then this is first * (and possibly only) fragment of NetBIOS * datagram * * SNT 4,5 Source End-Node type: * 00 = B node * 01 = P node * 10 = M node * 11 = NBDD * RESERVED 0-3 Reserved, must be zero (0) * (But MS sets bit 3 in this field) * */ int smb_netbios_datagram_send(struct name_entry *src, struct name_entry *dest, unsigned char *data, int length) { smb_inaddr_t ipaddr; size_t count, srclen, destlen, sinlen; addr_entry_t *addr; struct sockaddr_in sin; char *buffer; char ha_source[NETBIOS_DOMAIN_NAME_MAX]; char ha_dest[NETBIOS_DOMAIN_NAME_MAX]; (void) smb_first_level_name_encode(src, (unsigned char *)ha_source, sizeof (ha_source)); srclen = strlen(ha_source) + 1; (void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest, sizeof (ha_dest)); destlen = strlen(ha_dest) + 1; /* give some extra room */ if ((buffer = malloc(MAX_DATAGRAM_LENGTH * 4)) == NULL) { syslog(LOG_ERR, "nbt datagram: send: %m"); return (-1); } buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE; switch (smb_node_type) { case 'B': buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST; break; case 'P': buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST; break; case 'M': buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST; break; case 'H': default: buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST; break; } datagram_id++; BE_OUT16(&buffer[2], datagram_id); (void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr, sizeof (uint32_t)); (void) memcpy(&buffer[8], &src->addr_list.sin.sin_port, sizeof (uint16_t)); BE_OUT16(&buffer[10], length + srclen + destlen); BE_OUT16(&buffer[12], 0); bcopy(ha_source, &buffer[14], srclen); bcopy(ha_dest, &buffer[14 + srclen], destlen); bcopy(data, &buffer[14 + srclen + destlen], length); count = &buffer[14 + srclen + destlen + length] - buffer; bzero(&sin, sizeof (sin)); sin.sin_family = AF_INET; sinlen = sizeof (sin); addr = &dest->addr_list; do { ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; ipaddr.a_family = AF_INET; /* Don't send anything to myself... */ if (smb_nic_is_local(&ipaddr)) goto next; sin.sin_addr.s_addr = ipaddr.a_ipv4; sin.sin_port = addr->sin.sin_port; (void) sendto(datagram_sock, buffer, count, 0, (struct sockaddr *)&sin, sinlen); next: addr = addr->forw; } while (addr != &dest->addr_list); free(buffer); return (0); } int smb_netbios_datagram_send_to_net(struct name_entry *src, struct name_entry *dest, char *data, int length) { smb_inaddr_t ipaddr; size_t count, srclen, destlen, sinlen; addr_entry_t *addr; struct sockaddr_in sin; char *buffer; char ha_source[NETBIOS_DOMAIN_NAME_MAX]; char ha_dest[NETBIOS_DOMAIN_NAME_MAX]; (void) smb_first_level_name_encode(src, (unsigned char *)ha_source, sizeof (ha_source)); srclen = strlen(ha_source) + 1; (void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest, sizeof (ha_dest)); destlen = strlen(ha_dest) + 1; /* give some extra room */ if ((buffer = malloc(MAX_DATAGRAM_LENGTH * 4)) == NULL) { syslog(LOG_ERR, "nbt datagram: send_to_net: %m"); return (-1); } buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE; switch (smb_node_type) { case 'B': buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST; break; case 'P': buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST; break; case 'M': buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST; break; case 'H': default: buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST; break; } datagram_id++; BE_OUT16(&buffer[2], datagram_id); (void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr, sizeof (uint32_t)); (void) memcpy(&buffer[8], &src->addr_list.sin.sin_port, sizeof (uint16_t)); BE_OUT16(&buffer[10], length + srclen + destlen); BE_OUT16(&buffer[12], 0); bcopy(ha_source, &buffer[14], srclen); bcopy(ha_dest, &buffer[14 + srclen], destlen); bcopy(data, &buffer[14 + srclen + destlen], length); count = &buffer[14 + srclen + destlen + length] - buffer; bzero(&sin, sizeof (sin)); sin.sin_family = AF_INET; sinlen = sizeof (sin); addr = &dest->addr_list; do { ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; ipaddr.a_family = AF_INET; if (smb_nic_is_local(&ipaddr)) goto next; sin.sin_addr.s_addr = ipaddr.a_ipv4; sin.sin_port = addr->sin.sin_port; (void) sendto(datagram_sock, buffer, count, 0, (struct sockaddr *)&sin, sinlen); next: addr = addr->forw; } while (addr != &dest->addr_list); free(buffer); return (0); } int smb_datagram_decode(struct datagram *datagram, int bytes) { unsigned char *ha_src; unsigned char *ha_dest; unsigned char *data; if (bytes == DATAGRAM_ERR_HEADER_LENGTH) { if (datagram->rawbuf[0] == DATAGRAM_TYPE_ERROR_DATAGRAM) smb_netbios_datagram_error(datagram->rawbuf); return (-1); } if (bytes >= DATAGRAM_HEADER_LENGTH) { ha_src = &datagram->rawbuf[DATAGRAM_HEADER_LENGTH]; ha_dest = ha_src + strlen((char *)ha_src) + 1; data = ha_dest + strlen((char *)ha_dest) + 1; bzero(&datagram->src, sizeof (struct name_entry)); bzero(&datagram->dest, sizeof (struct name_entry)); datagram->rawbytes = bytes; datagram->packet_type = datagram->rawbuf[0]; datagram->flags = datagram->rawbuf[1]; datagram->datagram_id = BE_IN16(&datagram->rawbuf[2]); datagram->src.addr_list.sinlen = sizeof (struct sockaddr_in); (void) memcpy(&datagram->src.addr_list.sin.sin_addr.s_addr, &datagram->rawbuf[4], sizeof (uint32_t)); (void) memcpy(&datagram->src.addr_list.sin.sin_port, &datagram->rawbuf[8], sizeof (uint16_t)); datagram->src.addr_list.forw = datagram->src.addr_list.back = &datagram->src.addr_list; datagram->data = data; datagram->data_length = BE_IN16(&datagram->rawbuf[10]); datagram->offset = BE_IN16(&datagram->rawbuf[12]); if (smb_first_level_name_decode(ha_src, &datagram->src) < 0) { smb_tracef("NbtDatagram[%s]: invalid calling name", inet_ntoa(datagram->src.addr_list.sin.sin_addr)); smb_tracef("Calling name: <%02X>%32.32s", ha_src[0], &ha_src[1]); } datagram->dest.addr_list.forw = datagram->dest.addr_list.back = &datagram->dest.addr_list; if (smb_first_level_name_decode(ha_dest, &datagram->dest) < 0) { smb_tracef("NbtDatagram[%s]: invalid called name", inet_ntoa(datagram->src.addr_list.sin.sin_addr)); smb_tracef("Called name: <%02X>%32.32s", ha_dest[0], &ha_dest[1]); } return (0); } /* ignore other malformed datagram packets */ return (-1); } /* * 4.4.3. Datagram Error Packet */ static void smb_netbios_datagram_error(unsigned char *buf) { int error; int datagram_id; if (buf[0] != DATAGRAM_TYPE_ERROR_DATAGRAM) return; datagram_id = BE_IN16(&buf[2]); error = buf[DATAGRAM_ERR_HEADER_LENGTH - 1]; switch (error) { case DATAGRAM_INVALID_SOURCE_NAME_FORMAT: smb_tracef("NbtDatagramError[%d]: invalid source name format", datagram_id); break; case DATAGRAM_INVALID_DESTINATION_NAME_FORMAT: smb_tracef("NbtDatagramError[%d]: invalid destination name " "format", datagram_id); break; case DATAGRAM_DESTINATION_NAME_NOT_PRESENT: default: break; } } /* * Function: int smb_netbios_process_BPM_datagram(unsigned char *packet, * addr_entry_t *addr) * * Description from rfc1002: * * 5.3.3. RECEPTION OF NetBIOS DATAGRAMS BY ALL NODES * * The following algorithm discards out of order NetBIOS Datagram * fragments. An implementation which reassembles out of order * NetBIOS Datagram fragments conforms to this specification. The * fragment discard timer is initialized to the value FRAGMENT_TIMEOUT. * This value should be user configurable. The default value is * given in Section 6, "Defined Constants and Variables". * * PROCEDURE datagram_packet(packet) * * (* * * processing initiated by datagram packet reception * * on B, P and M nodes * *) * BEGIN * (* * * if this node is a P node, ignore * * broadcast packets. * *) * * IF this is a P node AND incoming packet is * a broadcast packet THEN * BEGIN * discard packet; * END * * CASE packet type OF * * DATAGRAM SERVICE: * BEGIN * IF FIRST bit in FLAGS is set THEN * BEGIN * IF MORE bit in FLAGS is set THEN * BEGIN * Save 1st UDP packet of the Datagram; * Set this Datagrams fragment discard * timer to FRAGMENT_TIMEOUT; * return; * END * ELSE * Datagram is composed of a single * UDP packet; * END * ELSE * BEGIN * (* Have the second fragment of a Datagram *) * * Search for 1st fragment by source IP address * and DGM_ID; * IF found 1st fragment THEN * Process both UDP packets; * ELSE * BEGIN * discard 2nd fragment UDP packet; * return; * END * END * * IF DESTINATION_NAME is '*' THEN * BEGIN * (* NetBIOS broadcast *) * * deliver USER_DATA from UDP packet(s) to all * outstanding receive broadcast * datagram requests; * return; * END * ELSE * BEGIN (* non-broadcast *) * (* Datagram for Unique or Group Name *) * * IF DESTINATION_NAME is not present in the * local name table THEN * BEGIN * (* destination not present *) * build DATAGRAM ERROR packet, clear * FIRST and MORE bit, put in * this nodes IP and PORT, set * ERROR_CODE; * send DATAGRAM ERROR packet to * source IP address and port * of UDP; * discard UDP packet(s); * return; * END * ELSE * BEGIN (* good *) * (* * * Replicate received NetBIOS datagram for * * each recipient * *) * FOR EACH pending NetBIOS users receive * datagram operation * BEGIN * IF source name of operation * matches destination name * of packet THEN * BEGIN * deliver USER_DATA from UDP * packet(s); * END * END (* for each *) * return; * END (* good *) * END (* non-broadcast *) * END (* datagram service *) * * DATAGRAM ERROR: * BEGIN * (* * * name service returned incorrect information * *) * * inform local name service that incorrect * information was provided; * * IF this is a P or M node THEN * BEGIN * (* * * tell NetBIOS Name Server that it may * * have given incorrect information * *) * * send NAME RELEASE REQUEST with name * and incorrect IP address to NetBIOS * Name Server; * END * END (* datagram error *) * * END (* case *) * END */ static struct datagram * smb_netbios_datagram_getq(struct datagram *datagram) { struct datagram *prev = 0; (void) mutex_lock(&smb_dgq_mtx); for (prev = smb_datagram_queue.forw; prev != (struct datagram *)((uintptr_t)&smb_datagram_queue); prev = prev->forw) { if (prev->src.addr_list.sin.sin_addr.s_addr == datagram->src.addr_list.sin.sin_addr.s_addr) { /* Something waiting */ QUEUE_CLIP(prev); (void) mutex_unlock(&smb_dgq_mtx); bcopy(datagram->data, &prev->data[prev->data_length], datagram->data_length); prev->data_length += datagram->data_length; free(datagram); return (prev); } } (void) mutex_unlock(&smb_dgq_mtx); return (0); } static void smb_netbios_BPM_datagram(struct datagram *datagram) { struct name_entry *entry = 0; struct datagram *qpacket = 0; pthread_t browser_dispatch; switch (datagram->packet_type) { case DATAGRAM_TYPE_BROADCAST : if (smb_node_type == 'P') { /* * if this node is a P node, ignore * broadcast packets. */ break; } /* FALLTHROUGH */ case DATAGRAM_TYPE_DIRECT_UNIQUE : case DATAGRAM_TYPE_DIRECT_GROUP : if ((datagram->flags & DATAGRAM_FLAGS_FIRST) != 0) { if (datagram->flags & DATAGRAM_FLAGS_MORE) { /* Save 1st UDP packet of the Datagram */ datagram->discard_timer = FRAGMENT_TIMEOUT; (void) mutex_lock(&smb_dgq_mtx); QUEUE_INSERT_TAIL(&smb_datagram_queue, datagram) (void) mutex_unlock(&smb_dgq_mtx); return; } /* process datagram */ } else { qpacket = smb_netbios_datagram_getq(datagram); if (qpacket) { datagram = qpacket; goto process_datagram; } break; } process_datagram: entry = 0; if ((strcmp((char *)datagram->dest.name, "*") == 0) || ((entry = smb_netbios_cache_lookup(&datagram->dest)) != 0)) { if (entry) { int is_local = IS_LOCAL(entry->attributes); smb_netbios_cache_unlock_entry(entry); if (is_local) { (void) pthread_create(&browser_dispatch, 0, smb_browser_dispatch, (void *)datagram); (void) pthread_detach(browser_dispatch); return; } } datagram->rawbuf[0] = DATAGRAM_TYPE_ERROR_DATAGRAM; datagram->rawbuf[1] &= DATAGRAM_FLAGS_SRC_TYPE; (void) memcpy(&datagram->rawbuf[4], &datagram->src.addr_list.sin.sin_addr.s_addr, sizeof (uint32_t)); BE_OUT16(&datagram->rawbuf[8], IPPORT_NETBIOS_DGM); (void) sendto(datagram_sock, datagram->rawbuf, datagram->rawbytes, 0, (struct sockaddr *)&datagram->src.addr_list.sin, datagram->src.addr_list.sinlen); } break; case DATAGRAM_TYPE_ERROR_DATAGRAM : break; } free(datagram); } /* * NetBIOS Datagram Service (port 138) */ /*ARGSUSED*/ void * smb_netbios_datagram_service(void *arg) { struct sockaddr_in sin; struct datagram *datagram; int bytes, flag = 1; smb_inaddr_t ipaddr; (void) mutex_lock(&smb_dgq_mtx); bzero(&smb_datagram_queue, sizeof (smb_datagram_queue)); smb_datagram_queue.forw = smb_datagram_queue.back = (struct datagram *)((uintptr_t)&smb_datagram_queue); (void) mutex_unlock(&smb_dgq_mtx); if ((datagram_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "nbt datagram: socket failed: %m"); smb_netbios_event(NETBIOS_EVENT_ERROR); return (NULL); } flag = 1; (void) setsockopt(datagram_sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof (flag)); bzero(&sin, sizeof (sin)); sin.sin_family = AF_INET; sin.sin_port = htons(IPPORT_NETBIOS_DGM); if (bind(datagram_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) { syslog(LOG_ERR, "nbt datagram: bind(%d) failed: %m", IPPORT_NETBIOS_DGM); (void) close(datagram_sock); smb_netbios_event(NETBIOS_EVENT_ERROR); return (NULL); } flag = 1; (void) setsockopt(datagram_sock, SOL_SOCKET, SO_BROADCAST, &flag, sizeof (flag)); smb_netbios_event(NETBIOS_EVENT_DGM_START); while (smb_netbios_running()) { if ((datagram = malloc(sizeof (struct datagram))) == NULL) { /* Sleep for 10 seconds and try again */ smb_netbios_sleep(10); continue; } ignore: bzero(&datagram->inaddr, sizeof (addr_entry_t)); datagram->inaddr.sinlen = sizeof (datagram->inaddr.sin); datagram->inaddr.forw = datagram->inaddr.back = &datagram->inaddr; if ((bytes = recvfrom(datagram_sock, datagram->rawbuf, MAX_DATAGRAM_LENGTH, 0, (struct sockaddr *)&datagram->inaddr.sin, &datagram->inaddr.sinlen)) < 0) { syslog(LOG_ERR, "nbt datagram: recvfrom failed: %m"); smb_netbios_event(NETBIOS_EVENT_ERROR); break; } /* Ignore any incoming packets from myself... */ ipaddr.a_ipv4 = datagram->inaddr.sin.sin_addr.s_addr; ipaddr.a_family = AF_INET; if (smb_nic_is_local(&ipaddr)) { goto ignore; } if (smb_datagram_decode(datagram, bytes) < 0) goto ignore; /* * This code was doing the wrong thing with responses from a * Windows2000 PDC because both DATAGRAM_FLAGS_H_NODE and * DATAGRAM_FLAGS_NBDD are defined to be the same value (see * netbios.h). Since the Windows2000 PDC wants to be an H-Node, * we need to handle all messages via smb_netbios_BPM_datagram. * * if ((datagram->flags & DATAGRAM_FLAGS_SRC_TYPE) == * DATAGRAM_FLAGS_NBDD) * smb_netbios_NBDD_datagram(datagram); * else * smb_netbios_BPM_datagram(datagram); */ smb_netbios_BPM_datagram(datagram); } smb_netbios_event(NETBIOS_EVENT_DGM_STOP); (void) smb_netbios_wait(NETBIOS_EVENT_BROWSER_STOP); (void) close(datagram_sock); smb_netbios_datagram_fini(); return (NULL); } static char /* LINTED - E_STATIC_UNUSED */ nb_fmt_flags(unsigned char flags) { switch (flags & DATAGRAM_FLAGS_SRC_TYPE) { case DATAGRAM_FLAGS_B_NODE: return ('B'); case DATAGRAM_FLAGS_P_NODE: return ('P'); case DATAGRAM_FLAGS_M_NODE: return ('M'); case DATAGRAM_FLAGS_H_NODE: return ('H'); default: return ('?'); } }