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 /*
227f667e74Sjose 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 *
58*a0aa776eSAlan Wright * - IPPORT_NETBIOS_DGM: 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 *
106*a0aa776eSAlan Wright * IPPORT_NETBIOS_DGM 138 (decimal)
107da6c28aaSamw *
108da6c28aaSamw * FRAGMENT_TO 2 seconds (default)
109da6c28aaSamw */
110da6c28aaSamw
111*a0aa776eSAlan Wright #include <errno.h>
112da6c28aaSamw #include <stdlib.h>
113da6c28aaSamw #include <unistd.h>
114da6c28aaSamw #include <string.h>
115da6c28aaSamw #include <strings.h>
116da6c28aaSamw #include <syslog.h>
117da6c28aaSamw #include <synch.h>
118da6c28aaSamw #include <sys/socket.h>
119da6c28aaSamw #include <arpa/inet.h>
120da6c28aaSamw
121da6c28aaSamw #include <smbns_netbios.h>
122da6c28aaSamw
123da6c28aaSamw #include <smbsrv/libsmbns.h>
124da6c28aaSamw
125da6c28aaSamw static int datagram_sock = -1;
126da6c28aaSamw static short datagram_id = 1;
127da6c28aaSamw static struct datagram_queue smb_datagram_queue;
128da6c28aaSamw static mutex_t smb_dgq_mtx;
129da6c28aaSamw
1308b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States static void smb_netbios_datagram_error(unsigned char *buf);
1318b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
132da6c28aaSamw /*
133da6c28aaSamw * Function: smb_netbios_datagram_tick(void)
134da6c28aaSamw *
135da6c28aaSamw * Description:
136da6c28aaSamw *
137da6c28aaSamw * Called once a second to handle time to live timeouts in
138da6c28aaSamw * datagram assembly queue.
139da6c28aaSamw *
140da6c28aaSamw * Inputs:
141da6c28aaSamw *
142da6c28aaSamw * Returns:
143da6c28aaSamw * void -> Nothing at all...
144da6c28aaSamw */
145da6c28aaSamw
146da6c28aaSamw void
smb_netbios_datagram_tick(void)147da6c28aaSamw smb_netbios_datagram_tick(void)
148da6c28aaSamw {
149da6c28aaSamw struct datagram *entry;
150da6c28aaSamw struct datagram *next;
151da6c28aaSamw
152da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx);
153da6c28aaSamw
154da6c28aaSamw for (entry = smb_datagram_queue.forw;
155da6c28aaSamw entry != (struct datagram *)((uintptr_t)&smb_datagram_queue);
156da6c28aaSamw entry = next) {
157da6c28aaSamw next = entry->forw;
158da6c28aaSamw if (--entry->discard_timer == 0) {
159da6c28aaSamw /* Toss it */
160da6c28aaSamw QUEUE_CLIP(entry);
161da6c28aaSamw free(entry);
162da6c28aaSamw }
163da6c28aaSamw }
164da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx);
165da6c28aaSamw }
166da6c28aaSamw
167da6c28aaSamw void
smb_netbios_datagram_fini()168da6c28aaSamw smb_netbios_datagram_fini()
169da6c28aaSamw {
170da6c28aaSamw struct datagram *entry;
171da6c28aaSamw
172da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx);
173da6c28aaSamw while ((entry = smb_datagram_queue.forw) !=
174da6c28aaSamw (struct datagram *)((uintptr_t)&smb_datagram_queue)) {
175da6c28aaSamw QUEUE_CLIP(entry);
176da6c28aaSamw free(entry);
177da6c28aaSamw }
178da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx);
179da6c28aaSamw }
180da6c28aaSamw
181da6c28aaSamw /*
182da6c28aaSamw * Function: int smb_netbios_send_Bnode_datagram(unsigned char *data,
183da6c28aaSamw * struct name_entry *source, struct name_entry *destination,
184da6c28aaSamw * uint32_t broadcast)
185da6c28aaSamw *
186da6c28aaSamw * Description from rfc1002:
187da6c28aaSamw *
188da6c28aaSamw * 5.3.1. B NODE TRANSMISSION OF NetBIOS DATAGRAMS
189da6c28aaSamw *
190da6c28aaSamw * PROCEDURE send_datagram(data, source, destination, broadcast)
191da6c28aaSamw *
192da6c28aaSamw * (*
193da6c28aaSamw * * user initiated processing on B node
194da6c28aaSamw * *)
195da6c28aaSamw *
196da6c28aaSamw * BEGIN
197da6c28aaSamw * group = FALSE;
198da6c28aaSamw *
199da6c28aaSamw * do name discovery on destination name, returns name type and
200da6c28aaSamw * IP address;
201da6c28aaSamw *
202da6c28aaSamw * IF name type is group name THEN
203da6c28aaSamw * BEGIN
204da6c28aaSamw * group = TRUE;
205da6c28aaSamw * END
206da6c28aaSamw *
207da6c28aaSamw * (*
208da6c28aaSamw * * build datagram service UDP packet;
209da6c28aaSamw * *)
210da6c28aaSamw * convert source and destination NetBIOS names into
211da6c28aaSamw * half-ASCII, biased encoded name;
212da6c28aaSamw * SOURCE_NAME = cat(source, SCOPE_ID);
213da6c28aaSamw * SOURCE_IP = this nodes IP address;
214*a0aa776eSAlan Wright * SOURCE_PORT = IPPORT_NETBIOS_DGM;
215da6c28aaSamw *
216da6c28aaSamw * IF NetBIOS broadcast THEN
217da6c28aaSamw * BEGIN
218da6c28aaSamw * DESTINATION_NAME = cat("*", SCOPE_ID)
219da6c28aaSamw * END
220da6c28aaSamw * ELSE
221da6c28aaSamw * BEGIN
222da6c28aaSamw * DESTINATION_NAME = cat(destination, SCOPE_ID)
223da6c28aaSamw * END
224da6c28aaSamw *
225da6c28aaSamw * MSG_TYPE = select_one_from_set
226da6c28aaSamw * {BROADCAST, DIRECT_UNIQUE, DIRECT_GROUP}
227da6c28aaSamw * DGM_ID = next transaction id for Datagrams;
228da6c28aaSamw * DGM_LENGTH = length of data + length of second level encoded
229da6c28aaSamw * source and destination names;
230da6c28aaSamw *
231da6c28aaSamw * IF (length of the NetBIOS Datagram, including UDP and
232da6c28aaSamw * IP headers, > MAX_DATAGRAM_LENGTH) THEN
233da6c28aaSamw * BEGIN
234da6c28aaSamw * (*
235da6c28aaSamw * * fragment NetBIOS datagram into 2 UDP packets
236da6c28aaSamw * *)
237da6c28aaSamw * Put names into 1st UDP packet and any data that fits
238da6c28aaSamw * after names;
239da6c28aaSamw * Set MORE and FIRST bits in 1st UDP packets FLAGS;
240da6c28aaSamw * OFFSET in 1st UDP = 0;
241da6c28aaSamw *
242da6c28aaSamw * Replicate NetBIOS Datagram header from 1st UDP packet
243da6c28aaSamw * into 2nd UDP packet;
244da6c28aaSamw * Put rest of data in 2nd UDP packet;
245da6c28aaSamw * Clear MORE and FIRST bits in 2nd UDP packets FLAGS;
246da6c28aaSamw * OFFSET in 2nd UDP = DGM_LENGTH - number of name and
247da6c28aaSamw * data bytes in 1st UDP;
248da6c28aaSamw * END
249da6c28aaSamw * BEGIN
250da6c28aaSamw * (*
251da6c28aaSamw * * Only need one UDP packet
252da6c28aaSamw * *)
253da6c28aaSamw * USER_DATA = data;
254da6c28aaSamw * Clear MORE bit and set FIRST bit in FLAGS;
255da6c28aaSamw * OFFSET = 0;
256da6c28aaSamw * END
257da6c28aaSamw *
258da6c28aaSamw * IF (group == TRUE) OR (NetBIOS broadcast) THEN
259da6c28aaSamw * BEGIN
260da6c28aaSamw * send UDP packet(s) to BROADCAST_ADDRESS;
261da6c28aaSamw * END
262da6c28aaSamw * ELSE
263da6c28aaSamw * BEGIN
264da6c28aaSamw * send UDP packet(s) to IP address returned by name
265da6c28aaSamw * discovery;
266da6c28aaSamw * END
267da6c28aaSamw * END (* procedure *)
268da6c28aaSamw * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
269da6c28aaSamw * 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
270da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
271da6c28aaSamw * | MSG_TYPE | FLAGS | DGM_ID |
272da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
273da6c28aaSamw * | SOURCE_IP |
274da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
275da6c28aaSamw * | SOURCE_PORT | DGM_LENGTH |
276da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
277da6c28aaSamw * | PACKET_OFFSET |
278da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279da6c28aaSamw *
280da6c28aaSamw * MSG_TYPE values (in hexidecimal):
281da6c28aaSamw *
282da6c28aaSamw * 10 - DIRECT_UNIQUE DATAGRAM
283da6c28aaSamw * 11 - DIRECT_GROUP DATAGRAM
284da6c28aaSamw * 12 - BROADCAST DATAGRAM
285da6c28aaSamw * 13 - DATAGRAM ERROR
286da6c28aaSamw * 14 - DATAGRAM QUERY REQUEST
287da6c28aaSamw * 15 - DATAGRAM POSITIVE QUERY RESPONSE
288da6c28aaSamw * 16 - DATAGRAM NEGATIVE QUERY RESPONSE
289da6c28aaSamw *
290da6c28aaSamw * Bit definitions of the FLAGS field:
291da6c28aaSamw *
292da6c28aaSamw * 0 1 2 3 4 5 6 7
293da6c28aaSamw * +---+---+---+---+---+---+---+---+
294da6c28aaSamw * | 0 | 0 | 0 | 0 | SNT | F | M |
295da6c28aaSamw * +---+---+---+---+---+---+---+---+
296da6c28aaSamw *
297da6c28aaSamw * Symbol Bit(s) Description
298da6c28aaSamw *
299da6c28aaSamw * M 7 MORE flag, If set then more NetBIOS datagram
300da6c28aaSamw * fragments follow.
301da6c28aaSamw *
302da6c28aaSamw * F 6 FIRST packet flag, If set then this is first
303da6c28aaSamw * (and possibly only) fragment of NetBIOS
304da6c28aaSamw * datagram
305da6c28aaSamw *
306da6c28aaSamw * SNT 4,5 Source End-Node type:
307da6c28aaSamw * 00 = B node
308da6c28aaSamw * 01 = P node
309da6c28aaSamw * 10 = M node
310da6c28aaSamw * 11 = NBDD
311da6c28aaSamw * RESERVED 0-3 Reserved, must be zero (0)
312da6c28aaSamw * (But MS sets bit 3 in this field)
313da6c28aaSamw *
314da6c28aaSamw */
315da6c28aaSamw
316da6c28aaSamw int
smb_netbios_datagram_send(struct name_entry * src,struct name_entry * dest,unsigned char * data,int length)317da6c28aaSamw smb_netbios_datagram_send(struct name_entry *src, struct name_entry *dest,
318da6c28aaSamw unsigned char *data, int length)
319da6c28aaSamw {
3207f667e74Sjose borrego smb_inaddr_t ipaddr;
321da6c28aaSamw size_t count, srclen, destlen, sinlen;
322*a0aa776eSAlan Wright addr_entry_t *addr;
323da6c28aaSamw struct sockaddr_in sin;
324da6c28aaSamw char *buffer;
325da6c28aaSamw char ha_source[NETBIOS_DOMAIN_NAME_MAX];
326da6c28aaSamw char ha_dest[NETBIOS_DOMAIN_NAME_MAX];
327da6c28aaSamw
328da6c28aaSamw (void) smb_first_level_name_encode(src, (unsigned char *)ha_source,
329da6c28aaSamw sizeof (ha_source));
330da6c28aaSamw srclen = strlen(ha_source) + 1;
331da6c28aaSamw
332da6c28aaSamw (void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest,
333da6c28aaSamw sizeof (ha_dest));
334da6c28aaSamw destlen = strlen(ha_dest) + 1;
335da6c28aaSamw
336da6c28aaSamw /* give some extra room */
337*a0aa776eSAlan Wright if ((buffer = malloc(MAX_DATAGRAM_LENGTH * 4)) == NULL) {
338*a0aa776eSAlan Wright syslog(LOG_ERR, "nbt datagram: send: %m");
339da6c28aaSamw return (-1);
340da6c28aaSamw }
341da6c28aaSamw
342da6c28aaSamw buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE;
343da6c28aaSamw switch (smb_node_type) {
344da6c28aaSamw case 'B':
345da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST;
346da6c28aaSamw break;
347da6c28aaSamw case 'P':
348da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST;
349da6c28aaSamw break;
350da6c28aaSamw case 'M':
351da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST;
352da6c28aaSamw break;
353da6c28aaSamw case 'H':
354da6c28aaSamw default:
355da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST;
356da6c28aaSamw break;
357da6c28aaSamw }
358da6c28aaSamw
359da6c28aaSamw datagram_id++;
360da6c28aaSamw BE_OUT16(&buffer[2], datagram_id);
361da6c28aaSamw (void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr,
362da6c28aaSamw sizeof (uint32_t));
363da6c28aaSamw (void) memcpy(&buffer[8], &src->addr_list.sin.sin_port,
364da6c28aaSamw sizeof (uint16_t));
365da6c28aaSamw BE_OUT16(&buffer[10], length + srclen + destlen);
366da6c28aaSamw BE_OUT16(&buffer[12], 0);
367da6c28aaSamw
368da6c28aaSamw bcopy(ha_source, &buffer[14], srclen);
369da6c28aaSamw bcopy(ha_dest, &buffer[14 + srclen], destlen);
370da6c28aaSamw bcopy(data, &buffer[14 + srclen + destlen], length);
371da6c28aaSamw count = &buffer[14 + srclen + destlen + length] - buffer;
372da6c28aaSamw
373da6c28aaSamw bzero(&sin, sizeof (sin));
374da6c28aaSamw sin.sin_family = AF_INET;
375da6c28aaSamw sinlen = sizeof (sin);
376da6c28aaSamw addr = &dest->addr_list;
377da6c28aaSamw do {
3787f667e74Sjose borrego ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
3797f667e74Sjose borrego ipaddr.a_family = AF_INET;
380da6c28aaSamw /* Don't send anything to myself... */
381fc724630SAlan Wright if (smb_nic_is_local(&ipaddr))
382da6c28aaSamw goto next;
383da6c28aaSamw
3847f667e74Sjose borrego sin.sin_addr.s_addr = ipaddr.a_ipv4;
385da6c28aaSamw sin.sin_port = addr->sin.sin_port;
386da6c28aaSamw (void) sendto(datagram_sock, buffer, count, 0,
387da6c28aaSamw (struct sockaddr *)&sin, sinlen);
388da6c28aaSamw
389da6c28aaSamw next: addr = addr->forw;
390da6c28aaSamw } while (addr != &dest->addr_list);
391da6c28aaSamw free(buffer);
392da6c28aaSamw return (0);
393da6c28aaSamw }
394da6c28aaSamw
395da6c28aaSamw
396da6c28aaSamw int
smb_netbios_datagram_send_to_net(struct name_entry * src,struct name_entry * dest,char * data,int length)397da6c28aaSamw smb_netbios_datagram_send_to_net(struct name_entry *src,
398da6c28aaSamw struct name_entry *dest, char *data, int length)
399da6c28aaSamw {
4007f667e74Sjose borrego smb_inaddr_t ipaddr;
401da6c28aaSamw size_t count, srclen, destlen, sinlen;
402*a0aa776eSAlan Wright addr_entry_t *addr;
403da6c28aaSamw struct sockaddr_in sin;
404da6c28aaSamw char *buffer;
405da6c28aaSamw char ha_source[NETBIOS_DOMAIN_NAME_MAX];
406da6c28aaSamw char ha_dest[NETBIOS_DOMAIN_NAME_MAX];
407da6c28aaSamw
408da6c28aaSamw (void) smb_first_level_name_encode(src, (unsigned char *)ha_source,
409da6c28aaSamw sizeof (ha_source));
410da6c28aaSamw srclen = strlen(ha_source) + 1;
411da6c28aaSamw
412da6c28aaSamw (void) smb_first_level_name_encode(dest, (unsigned char *)ha_dest,
413da6c28aaSamw sizeof (ha_dest));
414da6c28aaSamw destlen = strlen(ha_dest) + 1;
415da6c28aaSamw
416da6c28aaSamw /* give some extra room */
417*a0aa776eSAlan Wright if ((buffer = malloc(MAX_DATAGRAM_LENGTH * 4)) == NULL) {
418*a0aa776eSAlan Wright syslog(LOG_ERR, "nbt datagram: send_to_net: %m");
419da6c28aaSamw return (-1);
420da6c28aaSamw }
421da6c28aaSamw
422da6c28aaSamw buffer[0] = DATAGRAM_TYPE_DIRECT_UNIQUE;
423da6c28aaSamw switch (smb_node_type) {
424da6c28aaSamw case 'B':
425da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_B_NODE | DATAGRAM_FLAGS_FIRST;
426da6c28aaSamw break;
427da6c28aaSamw case 'P':
428da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_P_NODE | DATAGRAM_FLAGS_FIRST;
429da6c28aaSamw break;
430da6c28aaSamw case 'M':
431da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_M_NODE | DATAGRAM_FLAGS_FIRST;
432da6c28aaSamw break;
433da6c28aaSamw case 'H':
434da6c28aaSamw default:
435da6c28aaSamw buffer[1] = DATAGRAM_FLAGS_H_NODE | DATAGRAM_FLAGS_FIRST;
436da6c28aaSamw break;
437da6c28aaSamw }
438da6c28aaSamw
439da6c28aaSamw datagram_id++;
440da6c28aaSamw BE_OUT16(&buffer[2], datagram_id);
441da6c28aaSamw (void) memcpy(&buffer[4], &src->addr_list.sin.sin_addr.s_addr,
442da6c28aaSamw sizeof (uint32_t));
443da6c28aaSamw (void) memcpy(&buffer[8], &src->addr_list.sin.sin_port,
444da6c28aaSamw sizeof (uint16_t));
445da6c28aaSamw BE_OUT16(&buffer[10], length + srclen + destlen);
446da6c28aaSamw BE_OUT16(&buffer[12], 0);
447da6c28aaSamw
448da6c28aaSamw bcopy(ha_source, &buffer[14], srclen);
449da6c28aaSamw bcopy(ha_dest, &buffer[14 + srclen], destlen);
450da6c28aaSamw bcopy(data, &buffer[14 + srclen + destlen], length);
451da6c28aaSamw count = &buffer[14 + srclen + destlen + length] - buffer;
452da6c28aaSamw
453da6c28aaSamw bzero(&sin, sizeof (sin));
454da6c28aaSamw sin.sin_family = AF_INET;
455da6c28aaSamw sinlen = sizeof (sin);
456da6c28aaSamw addr = &dest->addr_list;
457da6c28aaSamw do {
4587f667e74Sjose borrego ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
4597f667e74Sjose borrego ipaddr.a_family = AF_INET;
460fc724630SAlan Wright if (smb_nic_is_local(&ipaddr))
461da6c28aaSamw goto next;
4627b59d02dSjb
4637f667e74Sjose borrego sin.sin_addr.s_addr = ipaddr.a_ipv4;
464da6c28aaSamw sin.sin_port = addr->sin.sin_port;
465da6c28aaSamw (void) sendto(datagram_sock, buffer, count, 0,
466da6c28aaSamw (struct sockaddr *)&sin, sinlen);
467da6c28aaSamw
468da6c28aaSamw next: addr = addr->forw;
469da6c28aaSamw } while (addr != &dest->addr_list);
470da6c28aaSamw free(buffer);
471da6c28aaSamw return (0);
472da6c28aaSamw }
473da6c28aaSamw
474da6c28aaSamw
475da6c28aaSamw int
smb_datagram_decode(struct datagram * datagram,int bytes)476da6c28aaSamw smb_datagram_decode(struct datagram *datagram, int bytes)
477da6c28aaSamw {
478da6c28aaSamw unsigned char *ha_src;
479da6c28aaSamw unsigned char *ha_dest;
480da6c28aaSamw unsigned char *data;
481da6c28aaSamw
4828b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (bytes == DATAGRAM_ERR_HEADER_LENGTH) {
4838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (datagram->rawbuf[0] == DATAGRAM_TYPE_ERROR_DATAGRAM)
4848b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_netbios_datagram_error(datagram->rawbuf);
485da6c28aaSamw return (-1);
486da6c28aaSamw
487da6c28aaSamw }
488da6c28aaSamw
4898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (bytes >= DATAGRAM_HEADER_LENGTH) {
4908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States ha_src = &datagram->rawbuf[DATAGRAM_HEADER_LENGTH];
4918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States ha_dest = ha_src + strlen((char *)ha_src) + 1;
4928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States data = ha_dest + strlen((char *)ha_dest) + 1;
4938b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
4948b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States bzero(&datagram->src, sizeof (struct name_entry));
4958b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States bzero(&datagram->dest, sizeof (struct name_entry));
4968b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
4978b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->rawbytes = bytes;
4988b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->packet_type = datagram->rawbuf[0];
4998b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->flags = datagram->rawbuf[1];
5008b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->datagram_id = BE_IN16(&datagram->rawbuf[2]);
5018b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5028b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->src.addr_list.sinlen = sizeof (struct sockaddr_in);
5038b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States (void) memcpy(&datagram->src.addr_list.sin.sin_addr.s_addr,
5048b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States &datagram->rawbuf[4], sizeof (uint32_t));
5058b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States (void) memcpy(&datagram->src.addr_list.sin.sin_port,
5068b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States &datagram->rawbuf[8], sizeof (uint16_t));
5078b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->src.addr_list.forw = datagram->src.addr_list.back =
5088b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States &datagram->src.addr_list;
5098b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5108b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->data = data;
5118b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->data_length = BE_IN16(&datagram->rawbuf[10]);
5128b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->offset = BE_IN16(&datagram->rawbuf[12]);
5138b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5148b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (smb_first_level_name_decode(ha_src, &datagram->src) < 0) {
5158b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tracef("NbtDatagram[%s]: invalid calling name",
5168b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States inet_ntoa(datagram->src.addr_list.sin.sin_addr));
5178b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tracef("Calling name: <%02X>%32.32s",
5188b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States ha_src[0], &ha_src[1]);
5198b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
5208b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5218b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram->dest.addr_list.forw = datagram->dest.addr_list.back =
5228b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States &datagram->dest.addr_list;
5238b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5248b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (smb_first_level_name_decode(ha_dest, &datagram->dest) < 0) {
5258b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tracef("NbtDatagram[%s]: invalid called name",
5268b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States inet_ntoa(datagram->src.addr_list.sin.sin_addr));
5278b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tracef("Called name: <%02X>%32.32s", ha_dest[0],
5288b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States &ha_dest[1]);
5298b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
530da6c28aaSamw
5318b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return (0);
532da6c28aaSamw }
533da6c28aaSamw
5348b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /* ignore other malformed datagram packets */
5358b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return (-1);
5368b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
5378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5388b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /*
5398b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 4.4.3. Datagram Error Packet
5408b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States */
5418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States static void
smb_netbios_datagram_error(unsigned char * buf)5428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_netbios_datagram_error(unsigned char *buf)
5438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States {
5448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States int error;
5458b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States int datagram_id;
5468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (buf[0] != DATAGRAM_TYPE_ERROR_DATAGRAM)
5488b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return;
5498b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5508b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram_id = BE_IN16(&buf[2]);
5518b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States error = buf[DATAGRAM_ERR_HEADER_LENGTH - 1];
5528b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States switch (error) {
5538b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States case DATAGRAM_INVALID_SOURCE_NAME_FORMAT:
5548b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tracef("NbtDatagramError[%d]: invalid source name format",
5558b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States datagram_id);
5568b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States break;
5578b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5588b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States case DATAGRAM_INVALID_DESTINATION_NAME_FORMAT:
5598b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_tracef("NbtDatagramError[%d]: invalid destination name "
5608b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States "format", datagram_id);
5618b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States break;
5628b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
5638b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States case DATAGRAM_DESTINATION_NAME_NOT_PRESENT:
5648b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States default:
5658b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States break;
5668b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
567da6c28aaSamw }
568da6c28aaSamw
569da6c28aaSamw
570da6c28aaSamw /*
571da6c28aaSamw * Function: int smb_netbios_process_BPM_datagram(unsigned char *packet,
572*a0aa776eSAlan Wright * addr_entry_t *addr)
573da6c28aaSamw *
574da6c28aaSamw * Description from rfc1002:
575da6c28aaSamw *
576da6c28aaSamw * 5.3.3. RECEPTION OF NetBIOS DATAGRAMS BY ALL NODES
577da6c28aaSamw *
578da6c28aaSamw * The following algorithm discards out of order NetBIOS Datagram
579da6c28aaSamw * fragments. An implementation which reassembles out of order
580da6c28aaSamw * NetBIOS Datagram fragments conforms to this specification. The
581da6c28aaSamw * fragment discard timer is initialized to the value FRAGMENT_TIMEOUT.
582da6c28aaSamw * This value should be user configurable. The default value is
583da6c28aaSamw * given in Section 6, "Defined Constants and Variables".
584da6c28aaSamw *
585da6c28aaSamw * PROCEDURE datagram_packet(packet)
586da6c28aaSamw *
587da6c28aaSamw * (*
588da6c28aaSamw * * processing initiated by datagram packet reception
589da6c28aaSamw * * on B, P and M nodes
590da6c28aaSamw * *)
591da6c28aaSamw * BEGIN
592da6c28aaSamw * (*
593da6c28aaSamw * * if this node is a P node, ignore
594da6c28aaSamw * * broadcast packets.
595da6c28aaSamw * *)
596da6c28aaSamw *
597da6c28aaSamw * IF this is a P node AND incoming packet is
598da6c28aaSamw * a broadcast packet THEN
599da6c28aaSamw * BEGIN
600da6c28aaSamw * discard packet;
601da6c28aaSamw * END
602da6c28aaSamw *
603da6c28aaSamw * CASE packet type OF
604da6c28aaSamw *
605da6c28aaSamw * DATAGRAM SERVICE:
606da6c28aaSamw * BEGIN
607da6c28aaSamw * IF FIRST bit in FLAGS is set THEN
608da6c28aaSamw * BEGIN
609da6c28aaSamw * IF MORE bit in FLAGS is set THEN
610da6c28aaSamw * BEGIN
611da6c28aaSamw * Save 1st UDP packet of the Datagram;
612da6c28aaSamw * Set this Datagrams fragment discard
613da6c28aaSamw * timer to FRAGMENT_TIMEOUT;
614da6c28aaSamw * return;
615da6c28aaSamw * END
616da6c28aaSamw * ELSE
617da6c28aaSamw * Datagram is composed of a single
618da6c28aaSamw * UDP packet;
619da6c28aaSamw * END
620da6c28aaSamw * ELSE
621da6c28aaSamw * BEGIN
622da6c28aaSamw * (* Have the second fragment of a Datagram *)
623da6c28aaSamw *
624da6c28aaSamw * Search for 1st fragment by source IP address
625da6c28aaSamw * and DGM_ID;
626da6c28aaSamw * IF found 1st fragment THEN
627da6c28aaSamw * Process both UDP packets;
628da6c28aaSamw * ELSE
629da6c28aaSamw * BEGIN
630da6c28aaSamw * discard 2nd fragment UDP packet;
631da6c28aaSamw * return;
632da6c28aaSamw * END
633da6c28aaSamw * END
634da6c28aaSamw *
635da6c28aaSamw * IF DESTINATION_NAME is '*' THEN
636da6c28aaSamw * BEGIN
637da6c28aaSamw * (* NetBIOS broadcast *)
638da6c28aaSamw *
639da6c28aaSamw * deliver USER_DATA from UDP packet(s) to all
640da6c28aaSamw * outstanding receive broadcast
641da6c28aaSamw * datagram requests;
642da6c28aaSamw * return;
643da6c28aaSamw * END
644da6c28aaSamw * ELSE
645da6c28aaSamw * BEGIN (* non-broadcast *)
646da6c28aaSamw * (* Datagram for Unique or Group Name *)
647da6c28aaSamw *
648da6c28aaSamw * IF DESTINATION_NAME is not present in the
649da6c28aaSamw * local name table THEN
650da6c28aaSamw * BEGIN
651da6c28aaSamw * (* destination not present *)
652da6c28aaSamw * build DATAGRAM ERROR packet, clear
653da6c28aaSamw * FIRST and MORE bit, put in
654da6c28aaSamw * this nodes IP and PORT, set
655da6c28aaSamw * ERROR_CODE;
656da6c28aaSamw * send DATAGRAM ERROR packet to
657da6c28aaSamw * source IP address and port
658da6c28aaSamw * of UDP;
659da6c28aaSamw * discard UDP packet(s);
660da6c28aaSamw * return;
661da6c28aaSamw * END
662da6c28aaSamw * ELSE
663da6c28aaSamw * BEGIN (* good *)
664da6c28aaSamw * (*
665da6c28aaSamw * * Replicate received NetBIOS datagram for
666da6c28aaSamw * * each recipient
667da6c28aaSamw * *)
668da6c28aaSamw * FOR EACH pending NetBIOS users receive
669da6c28aaSamw * datagram operation
670da6c28aaSamw * BEGIN
671da6c28aaSamw * IF source name of operation
672da6c28aaSamw * matches destination name
673da6c28aaSamw * of packet THEN
674da6c28aaSamw * BEGIN
675da6c28aaSamw * deliver USER_DATA from UDP
676da6c28aaSamw * packet(s);
677da6c28aaSamw * END
678da6c28aaSamw * END (* for each *)
679da6c28aaSamw * return;
680da6c28aaSamw * END (* good *)
681da6c28aaSamw * END (* non-broadcast *)
682da6c28aaSamw * END (* datagram service *)
683da6c28aaSamw *
684da6c28aaSamw * DATAGRAM ERROR:
685da6c28aaSamw * BEGIN
686da6c28aaSamw * (*
687da6c28aaSamw * * name service returned incorrect information
688da6c28aaSamw * *)
689da6c28aaSamw *
690da6c28aaSamw * inform local name service that incorrect
691da6c28aaSamw * information was provided;
692da6c28aaSamw *
693da6c28aaSamw * IF this is a P or M node THEN
694da6c28aaSamw * BEGIN
695da6c28aaSamw * (*
696da6c28aaSamw * * tell NetBIOS Name Server that it may
697da6c28aaSamw * * have given incorrect information
698da6c28aaSamw * *)
699da6c28aaSamw *
700da6c28aaSamw * send NAME RELEASE REQUEST with name
701da6c28aaSamw * and incorrect IP address to NetBIOS
702da6c28aaSamw * Name Server;
703da6c28aaSamw * END
704da6c28aaSamw * END (* datagram error *)
705da6c28aaSamw *
706da6c28aaSamw * END (* case *)
707da6c28aaSamw * END
708da6c28aaSamw */
709da6c28aaSamw
710da6c28aaSamw static struct datagram *
smb_netbios_datagram_getq(struct datagram * datagram)711da6c28aaSamw smb_netbios_datagram_getq(struct datagram *datagram)
712da6c28aaSamw {
713da6c28aaSamw struct datagram *prev = 0;
714da6c28aaSamw
715da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx);
716da6c28aaSamw for (prev = smb_datagram_queue.forw;
717da6c28aaSamw prev != (struct datagram *)((uintptr_t)&smb_datagram_queue);
718da6c28aaSamw prev = prev->forw) {
719da6c28aaSamw if (prev->src.addr_list.sin.sin_addr.s_addr ==
720da6c28aaSamw datagram->src.addr_list.sin.sin_addr.s_addr) {
721da6c28aaSamw /* Something waiting */
722da6c28aaSamw QUEUE_CLIP(prev);
723da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx);
724da6c28aaSamw bcopy(datagram->data, &prev->data[prev->data_length],
725da6c28aaSamw datagram->data_length);
726da6c28aaSamw prev->data_length += datagram->data_length;
727da6c28aaSamw free(datagram);
728da6c28aaSamw return (prev);
729da6c28aaSamw }
730da6c28aaSamw }
731da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx);
732da6c28aaSamw
733da6c28aaSamw return (0);
734da6c28aaSamw }
735da6c28aaSamw
736da6c28aaSamw static void
smb_netbios_BPM_datagram(struct datagram * datagram)737da6c28aaSamw smb_netbios_BPM_datagram(struct datagram *datagram)
738da6c28aaSamw {
739da6c28aaSamw struct name_entry *entry = 0;
740da6c28aaSamw struct datagram *qpacket = 0;
741da6c28aaSamw pthread_t browser_dispatch;
742da6c28aaSamw
743da6c28aaSamw switch (datagram->packet_type) {
744da6c28aaSamw case DATAGRAM_TYPE_BROADCAST :
745da6c28aaSamw if (smb_node_type == 'P') {
746da6c28aaSamw /*
747da6c28aaSamw * if this node is a P node, ignore
748da6c28aaSamw * broadcast packets.
749da6c28aaSamw */
750da6c28aaSamw break;
751da6c28aaSamw }
752da6c28aaSamw /* FALLTHROUGH */
753da6c28aaSamw
754da6c28aaSamw case DATAGRAM_TYPE_DIRECT_UNIQUE :
755da6c28aaSamw case DATAGRAM_TYPE_DIRECT_GROUP :
756da6c28aaSamw if ((datagram->flags & DATAGRAM_FLAGS_FIRST) != 0) {
757da6c28aaSamw if (datagram->flags & DATAGRAM_FLAGS_MORE) {
758da6c28aaSamw /* Save 1st UDP packet of the Datagram */
759da6c28aaSamw datagram->discard_timer = FRAGMENT_TIMEOUT;
760da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx);
761da6c28aaSamw QUEUE_INSERT_TAIL(&smb_datagram_queue, datagram)
762da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx);
763da6c28aaSamw return;
764da6c28aaSamw }
765da6c28aaSamw /* process datagram */
766da6c28aaSamw } else {
767da6c28aaSamw qpacket = smb_netbios_datagram_getq(datagram);
768da6c28aaSamw if (qpacket) {
769da6c28aaSamw datagram = qpacket;
770da6c28aaSamw goto process_datagram;
771da6c28aaSamw }
772da6c28aaSamw break;
773da6c28aaSamw }
774da6c28aaSamw
775da6c28aaSamw process_datagram:
776da6c28aaSamw entry = 0;
777da6c28aaSamw if ((strcmp((char *)datagram->dest.name, "*") == 0) ||
778da6c28aaSamw ((entry =
779da6c28aaSamw smb_netbios_cache_lookup(&datagram->dest)) != 0)) {
780da6c28aaSamw if (entry) {
781da6c28aaSamw int is_local = IS_LOCAL(entry->attributes);
782da6c28aaSamw smb_netbios_cache_unlock_entry(entry);
783da6c28aaSamw
784da6c28aaSamw if (is_local) {
785da6c28aaSamw (void) pthread_create(&browser_dispatch,
786da6c28aaSamw 0, smb_browser_dispatch,
787da6c28aaSamw (void *)datagram);
788da6c28aaSamw (void) pthread_detach(browser_dispatch);
789da6c28aaSamw return;
790da6c28aaSamw }
791da6c28aaSamw }
792da6c28aaSamw
793da6c28aaSamw datagram->rawbuf[0] = DATAGRAM_TYPE_ERROR_DATAGRAM;
794da6c28aaSamw datagram->rawbuf[1] &= DATAGRAM_FLAGS_SRC_TYPE;
795da6c28aaSamw
796da6c28aaSamw (void) memcpy(&datagram->rawbuf[4],
797da6c28aaSamw &datagram->src.addr_list.sin.sin_addr.s_addr,
798da6c28aaSamw sizeof (uint32_t));
799*a0aa776eSAlan Wright BE_OUT16(&datagram->rawbuf[8], IPPORT_NETBIOS_DGM);
800da6c28aaSamw
801da6c28aaSamw (void) sendto(datagram_sock, datagram->rawbuf,
802da6c28aaSamw datagram->rawbytes, 0,
803da6c28aaSamw (struct sockaddr *)&datagram->src.addr_list.sin,
804da6c28aaSamw datagram->src.addr_list.sinlen);
805da6c28aaSamw }
806da6c28aaSamw break;
807da6c28aaSamw
808da6c28aaSamw case DATAGRAM_TYPE_ERROR_DATAGRAM :
809da6c28aaSamw break;
810da6c28aaSamw }
811da6c28aaSamw free(datagram);
812da6c28aaSamw }
813da6c28aaSamw
814da6c28aaSamw /*
815*a0aa776eSAlan Wright * NetBIOS Datagram Service (port 138)
816da6c28aaSamw */
817da6c28aaSamw /*ARGSUSED*/
818da6c28aaSamw void *
smb_netbios_datagram_service(void * arg)819*a0aa776eSAlan Wright smb_netbios_datagram_service(void *arg)
820da6c28aaSamw {
821da6c28aaSamw struct sockaddr_in sin;
822da6c28aaSamw struct datagram *datagram;
823da6c28aaSamw int bytes, flag = 1;
8247f667e74Sjose borrego smb_inaddr_t ipaddr;
825da6c28aaSamw
826da6c28aaSamw (void) mutex_lock(&smb_dgq_mtx);
827da6c28aaSamw bzero(&smb_datagram_queue, sizeof (smb_datagram_queue));
828da6c28aaSamw smb_datagram_queue.forw = smb_datagram_queue.back =
829da6c28aaSamw (struct datagram *)((uintptr_t)&smb_datagram_queue);
830da6c28aaSamw (void) mutex_unlock(&smb_dgq_mtx);
831da6c28aaSamw
832da6c28aaSamw if ((datagram_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
833*a0aa776eSAlan Wright syslog(LOG_ERR, "nbt datagram: socket failed: %m");
834*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_ERROR);
835*a0aa776eSAlan Wright return (NULL);
836da6c28aaSamw }
837da6c28aaSamw
838*a0aa776eSAlan Wright flag = 1;
839*a0aa776eSAlan Wright (void) setsockopt(datagram_sock, SOL_SOCKET, SO_REUSEADDR, &flag,
840*a0aa776eSAlan Wright sizeof (flag));
841*a0aa776eSAlan Wright
842da6c28aaSamw bzero(&sin, sizeof (sin));
843da6c28aaSamw sin.sin_family = AF_INET;
844*a0aa776eSAlan Wright sin.sin_port = htons(IPPORT_NETBIOS_DGM);
845da6c28aaSamw if (bind(datagram_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) {
846*a0aa776eSAlan Wright syslog(LOG_ERR, "nbt datagram: bind(%d) failed: %m",
847*a0aa776eSAlan Wright IPPORT_NETBIOS_DGM);
848da6c28aaSamw (void) close(datagram_sock);
849*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_ERROR);
850*a0aa776eSAlan Wright return (NULL);
851da6c28aaSamw }
852*a0aa776eSAlan Wright
853*a0aa776eSAlan Wright flag = 1;
854da6c28aaSamw (void) setsockopt(datagram_sock, SOL_SOCKET, SO_BROADCAST, &flag,
855da6c28aaSamw sizeof (flag));
856da6c28aaSamw
857*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_DGM_START);
858da6c28aaSamw
859*a0aa776eSAlan Wright while (smb_netbios_running()) {
860*a0aa776eSAlan Wright if ((datagram = malloc(sizeof (struct datagram))) == NULL) {
861*a0aa776eSAlan Wright /* Sleep for 10 seconds and try again */
862*a0aa776eSAlan Wright smb_netbios_sleep(10);
863da6c28aaSamw continue;
864da6c28aaSamw }
865da6c28aaSamw
866*a0aa776eSAlan Wright ignore: bzero(&datagram->inaddr, sizeof (addr_entry_t));
867da6c28aaSamw datagram->inaddr.sinlen = sizeof (datagram->inaddr.sin);
868da6c28aaSamw datagram->inaddr.forw = datagram->inaddr.back =
869da6c28aaSamw &datagram->inaddr;
870da6c28aaSamw
871da6c28aaSamw if ((bytes = recvfrom(datagram_sock, datagram->rawbuf,
872da6c28aaSamw MAX_DATAGRAM_LENGTH, 0,
873da6c28aaSamw (struct sockaddr *)&datagram->inaddr.sin,
874da6c28aaSamw &datagram->inaddr.sinlen)) < 0) {
875*a0aa776eSAlan Wright syslog(LOG_ERR, "nbt datagram: recvfrom failed: %m");
876*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_ERROR);
877da6c28aaSamw break;
878da6c28aaSamw }
879da6c28aaSamw
880da6c28aaSamw /* Ignore any incoming packets from myself... */
8817f667e74Sjose borrego ipaddr.a_ipv4 = datagram->inaddr.sin.sin_addr.s_addr;
8827f667e74Sjose borrego ipaddr.a_family = AF_INET;
883fc724630SAlan Wright if (smb_nic_is_local(&ipaddr)) {
884da6c28aaSamw goto ignore;
885da6c28aaSamw }
8867b59d02dSjb
887da6c28aaSamw if (smb_datagram_decode(datagram, bytes) < 0)
888da6c28aaSamw goto ignore;
889da6c28aaSamw
890da6c28aaSamw /*
891da6c28aaSamw * This code was doing the wrong thing with responses from a
892da6c28aaSamw * Windows2000 PDC because both DATAGRAM_FLAGS_H_NODE and
893da6c28aaSamw * DATAGRAM_FLAGS_NBDD are defined to be the same value (see
894da6c28aaSamw * netbios.h). Since the Windows2000 PDC wants to be an H-Node,
895da6c28aaSamw * we need to handle all messages via smb_netbios_BPM_datagram.
896da6c28aaSamw *
897da6c28aaSamw * if ((datagram->flags & DATAGRAM_FLAGS_SRC_TYPE) ==
898da6c28aaSamw * DATAGRAM_FLAGS_NBDD)
899da6c28aaSamw * smb_netbios_NBDD_datagram(datagram);
900da6c28aaSamw * else
901da6c28aaSamw * smb_netbios_BPM_datagram(datagram);
902da6c28aaSamw */
903da6c28aaSamw
904da6c28aaSamw smb_netbios_BPM_datagram(datagram);
905da6c28aaSamw }
906da6c28aaSamw
907*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_DGM_STOP);
908*a0aa776eSAlan Wright (void) smb_netbios_wait(NETBIOS_EVENT_BROWSER_STOP);
909da6c28aaSamw
910da6c28aaSamw (void) close(datagram_sock);
911da6c28aaSamw smb_netbios_datagram_fini();
912*a0aa776eSAlan Wright return (NULL);
913da6c28aaSamw }
914da6c28aaSamw
915da6c28aaSamw static char
916da6c28aaSamw /* LINTED - E_STATIC_UNUSED */
nb_fmt_flags(unsigned char flags)917da6c28aaSamw nb_fmt_flags(unsigned char flags)
918da6c28aaSamw {
919da6c28aaSamw switch (flags & DATAGRAM_FLAGS_SRC_TYPE) {
920da6c28aaSamw case DATAGRAM_FLAGS_B_NODE: return ('B');
921da6c28aaSamw case DATAGRAM_FLAGS_P_NODE: return ('P');
922da6c28aaSamw case DATAGRAM_FLAGS_M_NODE: return ('M');
923da6c28aaSamw case DATAGRAM_FLAGS_H_NODE: return ('H');
924da6c28aaSamw default: return ('?');
925da6c28aaSamw }
926da6c28aaSamw }
927