1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

Large changes from jra@cygnus.com. Mainly browser updates.

access.c: Fixed crash if yp domain unavailable.
includes.h: Moved ifdefs for minor platform.
interface.c: Changed name of ipgrp to wins_ip to make it clearer.
loadparm.c: Changed default of wins support to 'no'.
nameannounce.c: Many changes to fix cross subnet browsing.
namebrowse.c: Many changes to fix cross subnet browsing.
namedbname.c: Many changes to fix cross subnet browsing.
namedbresp.c: Many changes to fix cross subnet browsing.
namedbsubnet.c: Many changes to fix cross subnet browsing.
namedbwork.c: Many changes to fix cross subnet browsing.
nameelect.c: Many changes to fix cross subnet browsing.
namelogon.c: Many changes to fix cross subnet browsing.
namepacket.c: Many changes to fix cross subnet browsing.
nameresp.c: Many changes to fix cross subnet browsing.
nameserv.c: Many changes to fix cross subnet browsing.
nameserv.h: Many changes to fix cross subnet browsing.
nameservreply.c: Many changes to fix cross subnet browsing.
nameservresp.c: Many changes to fix cross subnet browsing.
namework.c: Many changes to fix cross subnet browsing.
nmbd.c: Change to search wins subnet.
nmbsync.c: Change to check if we are any master before proceeding.
proto.h: Added find_subnet_all() and check_work_servertype().
util.c: Moved 'done' settings on name resolution.
This commit is contained in:
Samba Release Account -
parent deedac6523
commit a82476eee2
23 changed files with 814 additions and 652 deletions

View File

@ -344,6 +344,7 @@ char *getwd(char *);
#endif
#ifdef SGI5
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/statvfs.h>
#include <string.h>
@ -427,6 +428,7 @@ char *mktemp(char *); /* No standard include */
#define SIGNAL_CAST ( void (*) (int) )
#define STATFS3
#define USE_F_FSIZE
#define USE_SETSID
#include <netinet/tcp.h>
#ifdef OSF1_ENH_SEC
#include <pwd.h>

View File

@ -75,6 +75,8 @@
#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER)
#define AM_DOMMST(work) (work->ServerType & SV_TYPE_DOMAIN_MASTER)
#define AM_DOMMEM(work) (work->ServerType & SV_TYPE_DOMAIN_MEMBER)
#define AM_ANY_MASTER(work) (check_work_servertype(work->work_group, \
SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER))
/* microsoft browser NetBIOS name */
#define MSBROWSE "\001\002__MSBROWSE__\002"
@ -124,7 +126,7 @@ enum state_type
NAME_QUERY_SRV_CHK,
NAME_QUERY_FIND_MST,
NAME_QUERY_MST_CHK,
NAME_QUERY_DOMAIN,
NAME_QUERY_DOMAIN
};
/* a netbios name structure */
@ -401,7 +403,8 @@ struct packet_struct
#define CHECK_TIME_MAX_HOST_ANNCE 12
/* announce as master to WINS server and any Primary Domain Controllers */
#define CHECK_TIME_MST_ANNOUNCE 15
/* ORIGINAL - changed for test by JRA #define CHECK_TIME_MST_ANNOUNCE 15 */
#define CHECK_TIME_MST_ANNOUNCE 1
/* do all remote announcements this often */
#define REMOTE_ANNOUNCE_INTERVAL 180

View File

@ -386,11 +386,9 @@ void expire_servers(time_t t);
struct subnet_record *find_subnet(struct in_addr bcast_ip);
struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast);
struct subnet_record *find_subnet_all(struct in_addr bcast_ip);
void add_subnet_interfaces(void);
void add_my_subnets(char *group);
struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
struct in_addr mask_ip,
char *name, BOOL add, BOOL lmhosts);
void write_browse_list(time_t t);
/*The following definitions come from namedbwork.c */
@ -401,6 +399,7 @@ struct work_record *remove_workgroup(struct subnet_record *d,
struct work_record *find_workgroupstruct(struct subnet_record *d,
fstring name, BOOL add);
void dump_workgroups(void);
int check_work_servertype(const char *work_name, int type_mask);
/*The following definitions come from nameelect.c */

View File

@ -209,6 +209,10 @@ static int string_match(char *tok,char *s)
if (!mydomain) yp_get_default_domain(&mydomain);
if (!mydomain) {
DEBUG(0,("Unable to get default yp domain.\n"));
return NO;
}
if (!(hostname = strdup(s))) {
DEBUG(1,("out of memory for strdup!\n"));
return NO;

View File

@ -24,7 +24,7 @@
extern int DEBUGLEVEL;
struct in_addr ipzero;
struct in_addr ipgrp;
struct in_addr wins_ip;
static struct in_addr default_ip;
static struct in_addr default_bcast;
static struct in_addr default_nmask;
@ -261,7 +261,7 @@ static void interpret_interfaces(char *s, struct interface **interfaces,
struct in_addr ip;
ipzero = *interpret_addr2("0.0.0.0");
ipgrp = *interpret_addr2("255.255.255.255");
wins_ip = *interpret_addr2("255.255.255.255");
while (next_token(&ptr,token,NULL)) {
/* parse it into an IP address/netmasklength pair */

View File

@ -3090,12 +3090,10 @@ char *client_name(void)
if (done)
return name_buf;
done = True;
strcpy(name_buf,"UNKNOWN");
if (getpeername(Client, &sa, &length) < 0) {
DEBUG(0,("getpeername failed\n"));
done = False;
return name_buf;
}
@ -3105,7 +3103,6 @@ char *client_name(void)
AF_INET)) == 0) {
DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr()));
StrnCpy(name_buf,client_addr(),sizeof(name_buf) - 1);
done = False;
} else {
StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1);
if (!matchname(name_buf, sockin->sin_addr)) {
@ -3113,6 +3110,7 @@ char *client_name(void)
strcpy(name_buf,"UNKNOWN");
}
}
done = True;
return name_buf;
}
@ -3129,7 +3127,6 @@ char *client_addr(void)
if (done)
return addr_buf;
done = True;
strcpy(addr_buf,"0.0.0.0");
if (getpeername(Client, &sa, &length) < 0) {
@ -3139,6 +3136,7 @@ char *client_addr(void)
strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
done = True;
return addr_buf;
}

View File

@ -45,7 +45,7 @@ extern struct subnet_record *subnetlist;
extern int updatecount;
extern int workgroup_count;
extern struct in_addr ipgrp;
extern struct in_addr wins_ip;
@ -216,7 +216,7 @@ void announce_server(struct subnet_record *d, struct work_record *work,
(SV_TYPE_SERVER_UNIX, for example)
*/
uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
BOOL wins_iface = ip_equal(d->bcast_ip, ipgrp);
BOOL wins_iface = ip_equal(d->bcast_ip, wins_ip);
if (wins_iface && server_type != 0)
{
@ -261,7 +261,7 @@ void announce_server(struct subnet_record *d, struct work_record *work,
do_announce_host(ANN_LocalMasterAnnouncement,
name , 0x00, d->myip,
work->work_group, 0x1e, d->bcast_ip,
ttl*1000,
ttl,
name, server_type, comment);
DEBUG(3,("sending domain announce to %s for %s\n",
@ -273,7 +273,7 @@ void announce_server(struct subnet_record *d, struct work_record *work,
do_announce_host(ANN_DomainAnnouncement,
name , 0x00, d->myip,
MSBROWSE, 0x01, d->bcast_ip,
ttl*1000,
ttl,
work->work_group, server_type ? domain_type : 0,
name);
}
@ -286,7 +286,7 @@ void announce_server(struct subnet_record *d, struct work_record *work,
do_announce_host(ANN_HostAnnouncement,
name , 0x00, d->myip,
work->work_group, 0x1d, d->bcast_ip,
ttl*1000,
ttl,
name, server_type, comment);
}
}
@ -309,24 +309,24 @@ void announce_host(time_t t)
{
struct work_record *work;
if (ip_equal(d->bcast_ip, ipgrp)) continue;
if (ip_equal(d->bcast_ip, wins_ip)) continue;
for (work = d->workgrouplist; work; work = work->next)
{
uint32 stype = work->ServerType;
struct server_record *s;
BOOL announce = False;
/* must work on the code that does announcements at up to
30 seconds later if a master browser sends us a request
announce.
*/
/* must work on the code that does announcements at up to
30 seconds later if a master browser sends us a request
announce.
*/
if (work->needannounce) {
/* drop back to a max 3 minute announce - this is to prevent a
single lost packet from stuffing things up for too long */
work->announce_interval = MIN(work->announce_interval,
CHECK_TIME_MIN_HOST_ANNCE*60);
CHECK_TIME_MIN_HOST_ANNCE*60);
work->lastannounce_time = t - (work->announce_interval+1);
}
@ -339,7 +339,7 @@ void announce_host(time_t t)
work->announce_interval += 60;
work->lastannounce_time = t;
for (s = work->serverlist; s; s = s->next) {
if (strequal(myname, s->serv.name)) {
announce = True;
@ -353,18 +353,18 @@ void announce_host(time_t t)
}
if (work->needannounce)
{
{
work->needannounce = False;
break;
/* sorry: can't do too many announces. do some more later */
}
}
}
}
}
}
/****************************************************************************
announce myself as a master to all other primary domain conrollers.
announce myself as a master to all other domain master browsers.
this actually gets done in search_and_sync_workgroups() via the
NAME_QUERY_DOM_SRV_CHK command, if there is a response from the
@ -393,86 +393,77 @@ void announce_master(time_t t)
}
}
}
DEBUG(4,( "announce_master: am_master = %d for workgroup %s\n", am_master, lp_workgroup()));
if (!am_master) return; /* only proceed if we are a master browser */
/* Note that we don't do this if we are domain master browser. */
for (d = subnetlist; d; d = d->next)
{
struct work_record *work;
for (work = d->workgrouplist; work; work = work->next)
{
struct server_record *s;
for (s = work->serverlist; s; s = s->next)
{
if (strequal(s->serv.name, myname)) continue;
/* all DOMs (which should also be master browsers) */
if (s->serv.type & SV_TYPE_DOMAIN_CTRL)
{
/* check the existence of a pdc for this workgroup, and if
one exists at the specified ip, sync with it and announce
ourselves as a master browser to it */
if (!*lp_domain_controller() ||
!strequal(lp_domain_controller(), s->serv.name))
{
if (!lp_wins_support() && *lp_wins_server())
{
queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
NAME_QUERY_DOM_SRV_CHK,
work->work_group,0x1b,0,0,0,NULL,NULL,
False, False, ipzero, ipzero);
}
else
{
struct subnet_record *d2;
for (d2 = subnetlist; d2; d2 = d2->next)
{
queue_netbios_packet(d,ClientNMB,NMB_QUERY,
NAME_QUERY_DOM_SRV_CHK,
work->work_group,0x1b,0,0,0,NULL,NULL,
True, False, d2->bcast_ip, d2->bcast_ip);
}
}
}
}
}
/* now do primary domain controller - the one that's not
necessarily in our browse lists, although it ought to be
this pdc is the one that we get TOLD about through smb.conf.
basically, if it's on a subnet that we know about, it may end
up in our browse lists (which is why it's explicitly excluded
in the code above) */
if (*lp_domain_controller())
{
struct in_addr ip;
BOOL bcast = False;
ip = *interpret_addr2(lp_domain_controller());
if (zero_ip(ip)) {
ip = d->bcast_ip;
bcast = True;
}
/* Try and find our workgroup on this subnet */
struct work_record *work = find_workgroupstruct(d, lp_workgroup(), True);
DEBUG(2, ("Searching for DOM %s at %s\n",
lp_domain_controller(), inet_ntoa(ip)));
/* check the existence of a pdc for this workgroup, and if
one exists at the specified ip, sync with it and announce
ourselves as a master browser to it */
queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
work->work_group,0x1b,0,0,0,NULL,NULL,
bcast, False, ip, ip);
if (work)
{
char *name;
int type;
if (*lp_domain_controller())
{
/* the domain controller option is used to manually specify
the domain master browser to sync with
*/
/* XXXX i'm not sure we should be using the domain controller
option for this purpose.
*/
name = lp_domain_controller();
type = 0x20;
}
else
{
/* assume that the domain master browser we want to sync
with is our own domain.
*/
name = work->work_group;
type = 0x1b;
}
/* check the existence of a dmb for this workgroup, and if
one exists at the specified ip, sync with it and announce
ourselves as a master browser to it
*/
if (!lp_wins_support() && *lp_wins_server() &&
ip_equal(d->bcast_ip, wins_ip))
{
DEBUG(4, ("Local Announce: find %s<%02x> from WINS server %s\n",
name, type, lp_wins_server()));
queue_netbios_pkt_wins(d,ClientNMB,
NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
name, type, 0,0,0,
work->work_group,NULL,
False, False, ipzero, ipzero);
}
else
{
DEBUG(4, ("Local Announce: find %s<%02x> on %s\n",
name, type, inet_ntoa(d->bcast_ip)));
queue_netbios_packet(d,ClientNMB,
NMB_QUERY,NAME_QUERY_DOM_SRV_CHK,
name, type, 0,0,0,
work->work_group,NULL,
True, False, d->bcast_ip, d->bcast_ip);
}
}
}
}
/****************************************************************************
do all the "remote" announcements. These are used to put ourselves
on a remote browse list. They are done blind, no checking is done to

View File

@ -32,6 +32,8 @@ extern int ClientNMB;
extern int DEBUGLEVEL;
extern struct in_addr wins_ip;
/* this is our browse master/backup cache database */
static struct browse_cache_record *browserlist = NULL;
@ -89,7 +91,6 @@ void expire_browse_cache(time_t t)
}
}
/****************************************************************************
add a browser entry
****************************************************************************/
@ -166,21 +167,48 @@ static void start_sync_browse_entry(struct browse_cache_record *b)
struct subnet_record *d;
struct work_record *work;
if (!(d = find_subnet(b->ip))) return;
/* Look for the workgroup first on the local subnet. If this
fails try WINS - we may need to sync with the domain master,
or we may be the domain master and need to sync with subnet
masters.
*/
if (!(work = find_workgroupstruct(d, b->group, False))) return;
if (!(d = find_subnet_all(b->ip))) {
DEBUG(0, ("start_sync_browse_entry: failed to get a \
subnet for a browse cache entry workgroup %s, server %s\n",
b->group, b->name));
return;
}
/* only sync if we are the master */
if (AM_MASTER(work)) {
if (!(work = find_workgroupstruct(d, b->group, False))) {
DEBUG(0, ("start_sync_browse_entry: failed to get a \
workgroup for a browse cache entry workgroup %s, server %s\n",
b->group, b->name));
return;
}
/* first check whether the group we intend to sync with exists. if it
doesn't, the server must have died. o dear. */
/* only sync if we are a subnet master or domain master - but
we sync if we are a master for this workgroup on *any*
of our interfaces. */
if (AM_MASTER(work) || AM_DOMMST(work) || AM_ANY_MASTER(work)) {
/* see response_netbios_packet() or expire_netbios_response_entries() */
queue_netbios_packet(d,ClientNMB,NMB_QUERY,
b->local?NAME_QUERY_SYNC_LOCAL:NAME_QUERY_SYNC_REMOTE,
b->group,0x20,0,0,0,NULL,NULL,
False,False,b->ip,b->ip);
DEBUG(4, ("start_sync_browse_entry: Initiating %s sync with %s<0x20>, \
workgroup %s\n",
b->local ? "local" : "remote", b->name, b->group));
/* first check whether the server we intend to sync with exists. if it
doesn't, the server must have died. o dear. */
/* see response_netbios_packet() or expire_netbios_response_entries() */
/* We cheat here by using the my_comment field of the response_record
struct as the workgroup name we are going to do the sync for.
This is because the reply packet doesn't include the workgroup, but
we need it when the reply comes back.
*/
queue_netbios_packet(d,ClientNMB,NMB_QUERY,
b->local?NAME_QUERY_SYNC_LOCAL:NAME_QUERY_SYNC_REMOTE,
b->name,0x20,0,0,0,NULL,b->group,
False,False,b->ip,b->ip);
}
b->synced = True;
@ -195,10 +223,14 @@ void do_browser_lists(time_t t)
struct browse_cache_record *b;
static time_t last = 0;
if (t-last < 20) return; /* don't do too many of these at once! */
if (t-last < 20)
{
DEBUG(9,("do_browser_lists: returning due to t(%d) - last(%d) < 20\n",
t, last));
return; /* don't do too many of these at once! */
/* XXXX equally this period should not be too long
the server may die in the intervening gap */
}
last = t;
/* pick any entry in the list, preferably one whose time is up */
@ -210,9 +242,15 @@ void do_browser_lists(time_t t)
if (b && !b->synced)
{
/* sync with the selected entry then remove some dead entries */
DEBUG(4,("do_browser_lists: Initiating sync with %s, workgroup %s\n",
b->name, b->group));
start_sync_browse_entry(b);
expire_browse_cache(t - 60);
}
else
{
DEBUG(9, ("do_browser_lists: no entries to sync.\n"));
}
}

View File

@ -35,7 +35,7 @@ extern int DEBUGLEVEL;
extern pstring scope;
extern struct in_addr ipzero;
extern struct in_addr ipgrp;
extern struct in_addr wins_ip;
extern struct subnet_record *subnetlist;
@ -153,10 +153,11 @@ struct name_record *find_name(struct name_record *n,
{
continue;
}
DEBUG(9,("find_name: found name %s\n", name->name));
return ret;
}
}
DEBUG(9,("find_name: name %s NOT FOUND\n", name->name));
return NULL;
}
@ -172,27 +173,27 @@ struct name_record *find_name_search(struct subnet_record **d,
struct nmb_name *name,
int search, struct in_addr ip)
{
if (d == NULL) return NULL; /* bad error! */
if (d == NULL) return NULL; /* bad error! */
if (search & FIND_LOCAL) {
if (*d != NULL) {
struct name_record *n = find_name((*d)->namelist, name, search);
DEBUG(4,("find_name on local: %s %s search %x\n",
namestr(name),inet_ntoa(ip), search));
if (n) return n;
}
if (search & FIND_LOCAL) {
if (*d != NULL) {
struct name_record *n = find_name((*d)->namelist, name, search);
DEBUG(4,("find_name on local: %s %s search %x\n",
namestr(name),inet_ntoa(ip), search));
if (n) return n;
}
}
if (!(search & FIND_WINS)) return NULL;
if (!(search & FIND_WINS)) return NULL;
/* find WINS subnet record. */
*d = find_subnet(ipgrp);
if (*d == NULL) return NULL;
DEBUG(4,("find_name on WINS: %s %s search %x\n",
namestr(name),inet_ntoa(ip), search));
return find_name((*d)->namelist, name, search);
/* find WINS subnet record. */
*d = find_subnet(wins_ip);
if (*d == NULL) return NULL;
DEBUG(4,("find_name on WINS: %s %s search %x\n",
namestr(name),inet_ntoa(ip), search));
return find_name((*d)->namelist, name, search);
}
@ -245,7 +246,7 @@ void dump_names(void)
}
DEBUG(4,("\n"));
if (f && ip_equal(d->bcast_ip, ipgrp) && n->source == REGISTER)
if (f && ip_equal(d->bcast_ip, wins_ip) && n->source == REGISTER)
{
/* XXXX i have little imagination as to how to output nb_flags as
anything other than as a hexadecimal number :-) */
@ -281,7 +282,7 @@ void dump_names(void)
****************************************************************************/
void load_netbios_names(void)
{
struct subnet_record *d = find_subnet(ipgrp);
struct subnet_record *d = find_subnet(wins_ip);
fstring fname;
FILE *f;
@ -466,8 +467,9 @@ struct name_record *add_netbios_entry(struct subnet_record *d,
if (!n2) add_name(d,n);
DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x\n",
namestr(&n->name),inet_ntoa(ip),ttl,nb_flags));
DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x to interface %s\n",
namestr(&n->name),inet_ntoa(ip),ttl,nb_flags,
ip_equal(d->bcast_ip, wins_ip) ? "WINS" : inet_ntoa(d->bcast_ip)));
return(n);
}
@ -520,7 +522,7 @@ struct name_record *dns_name_search(struct nmb_name *question, int Time)
char *r;
BOOL dns_type = (name_type == 0x20 || name_type == 0);
struct in_addr dns_ip;
struct subnet_record *d = find_subnet(ipgrp);
struct subnet_record *d = find_subnet(wins_ip);
if (d == NULL) return NULL;

View File

@ -34,7 +34,6 @@ extern int DEBUGLEVEL;
extern pstring scope;
extern pstring myname;
extern struct in_addr ipzero;
extern struct in_addr ipgrp;
int num_response_packets = 0;
@ -117,9 +116,14 @@ struct response_record *make_response_queue_record(enum state_type state,
n->recurse = recurse;
n->send_ip = send_ip;
n->reply_to_ip = reply_to_ip;
StrnCpy(my_name , n->my_name , sizeof(n->my_name )-1);
StrnCpy(my_comment, n->my_comment, sizeof(n->my_comment)-1);
if(my_name)
StrnCpy(n->my_name, my_name, sizeof(n->my_name)-1);
else
*n->my_name = 0;
if(my_comment)
StrnCpy(n->my_comment, my_comment, sizeof(n->my_comment)-1);
else
*n->my_comment = 0;
n->repeat_interval = 1; /* XXXX should be in ms */
n->repeat_count = 3; /* 3 retries */
n->repeat_time = time(NULL) + n->repeat_interval; /* initial retry time */

View File

@ -36,7 +36,7 @@ extern int ClientDGRAM;
extern int DEBUGLEVEL;
extern struct in_addr ipgrp;
extern struct in_addr wins_ip;
extern struct in_addr ipzero;
extern pstring myname;
@ -52,6 +52,11 @@ struct subnet_record *subnetlist = NULL;
extern uint16 nb_type; /* samba's NetBIOS name type */
/* Forward references. */
static struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
struct in_addr mask_ip,
char *name, BOOL add, BOOL lmhosts);
/****************************************************************************
add a domain into the list
**************************************************************************/
@ -81,31 +86,30 @@ static void add_subnet(struct subnet_record *d)
struct subnet_record *find_subnet(struct in_addr bcast_ip)
{
struct subnet_record *d;
struct in_addr wins_ip = ipgrp;
/* search through subnet list for broadcast/netmask that matches
the source ip address. a subnet 255.255.255.255 represents the
WINS list. */
for (d = subnetlist; d; d = d->next)
for (d = subnetlist; d; d = d->next)
{
if (ip_equal(bcast_ip, wins_ip))
if (ip_equal(bcast_ip, wins_ip))
{
if (ip_equal(bcast_ip, d->bcast_ip))
{
if (ip_equal(bcast_ip, d->bcast_ip))
{
return d;
}
}
else if (same_net(bcast_ip, d->bcast_ip, d->mask_ip))
{
if (!ip_equal(d->bcast_ip, wins_ip))
{
return d;
}
return d;
}
}
else if (same_net(bcast_ip, d->bcast_ip, d->mask_ip))
{
if (!ip_equal(d->bcast_ip, wins_ip))
{
return d;
}
}
}
return (NULL);
return (NULL);
}
@ -122,9 +126,19 @@ struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast)
return find_subnet(*iface_bcast(ip));
}
/* find the subnet under the pseudo-ip of 255.255.255.255 */
return find_subnet(ipgrp);
return find_subnet(wins_ip);
}
/****************************************************************************
find a subnet in the subnetlist - if the subnet is not found
then return the WINS subnet.
**************************************************************************/
struct subnet_record *find_subnet_all(struct in_addr bcast_ip)
{
struct subnet_record *d = find_subnet(bcast_ip);
if(!d)
return find_subnet( wins_ip);
}
/****************************************************************************
create a domain entry
@ -157,24 +171,24 @@ static struct subnet_record *make_subnet(struct in_addr bcast_ip, struct in_addr
****************************************************************************/
void add_subnet_interfaces(void)
{
struct interface *i;
struct interface *i;
/* loop on all local interfaces */
for (i = local_interfaces; i; i = i->next)
{
/* add the interface into our subnet database */
if (!find_subnet(i->bcast))
{
make_subnet(i->bcast,i->nmask);
}
}
/* add the pseudo-ip interface for WINS: 255.255.255.255 */
if (lp_wins_support() || (*lp_wins_server()))
/* loop on all local interfaces */
for (i = local_interfaces; i; i = i->next)
{
struct in_addr wins_bcast = ipgrp;
struct in_addr wins_nmask = ipzero;
make_subnet(wins_bcast, wins_nmask);
/* add the interface into our subnet database */
if (!find_subnet(i->bcast))
{
make_subnet(i->bcast,i->nmask);
}
}
/* add the pseudo-ip interface for WINS: 255.255.255.255 */
if (lp_wins_support() || (*lp_wins_server()))
{
struct in_addr wins_bcast = wins_ip;
struct in_addr wins_nmask = ipzero;
make_subnet(wins_bcast, wins_nmask);
}
}
@ -205,7 +219,7 @@ void add_my_subnets(char *group)
add a domain entry. creates a workgroup, if necessary, and adds the domain
to the named a workgroup.
****************************************************************************/
struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
static struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
struct in_addr mask_ip,
char *name, BOOL add, BOOL lmhosts)
{
@ -215,7 +229,7 @@ struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
in the DEBUG comment. i assume that the DEBUG comment below actually
intends to refer to bcast_ip? i don't know.
struct in_addr ip = ipgrp;
struct in_addr ip = wins_ip;
*/
@ -223,6 +237,8 @@ struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
bcast_ip = *iface_bcast(bcast_ip);
/* add the domain into our domain database */
/* Note that we never add into the WINS subnet as add_subnet_entry
is only called to add our local interfaces. */
if ((d = find_subnet(bcast_ip)) ||
(d = make_subnet(bcast_ip, mask_ip)))
{

View File

@ -38,7 +38,7 @@ extern int DEBUGLEVEL;
/* this is our domain/workgroup/server database */
extern struct subnet_record *subnetlist;
extern struct in_addr ipgrp;
extern struct in_addr wins_ip;
int workgroup_count = 0; /* unique index key: one for each workgroup */
@ -201,7 +201,7 @@ struct work_record *find_workgroupstruct(struct subnet_record *d,
if ((work = make_workgroup(name)))
{
if (!ip_equal(d->bcast_ip, ipgrp) &&
if (!ip_equal(d->bcast_ip, wins_ip) &&
lp_preferred_master() &&
strequal(lp_workgroup(), name))
{
@ -248,3 +248,42 @@ void dump_workgroups(void)
}
}
}
/****************************************************************************
check to see if a ServerType bit is set in any workgroup on any interface
except WINS. Used to determine if a nmbd is a master browser or domain
master browser in a particular workgroup on any subnet.
**************************************************************************/
int check_work_servertype(const char *work_name, int type_mask)
{
struct subnet_record *d;
for (d = subnetlist; d; d = d->next)
{
if(ip_equal(d->bcast_ip, wins_ip))
{
/* WINS ip */
DEBUG(10,("check_work_servertype: ignoring WINS subnet\n"));
continue;
}
if (d->workgrouplist)
{
struct work_record *work;
for (work = d->workgrouplist; work; work = work->next)
{
if(strequal(work->work_group, (char *)work_name) &&
(type_mask & work->ServerType) != 0)
{
DEBUG(10, ("check_work_servertype: Workgroup %s has \
ServerType %x - match for type_mask %x\n", work_name, work->ServerType,
type_mask));
return 1;
}
}
}
}
DEBUG(10, ("check_work_servertype: Workgroup %s has no match for \
type mask %x\n", work_name, type_mask));
return 0;
}

View File

@ -41,7 +41,7 @@ extern pstring scope;
extern pstring myname;
extern struct in_addr ipzero;
extern struct in_addr ipgrp;
extern struct in_addr wins_ip;
/* here are my election parameters */
@ -71,6 +71,10 @@ void check_master_browser(time_t t)
{
struct work_record *work;
/* don't do election stuff on the WINS subnet */
if (ip_equal(d->bcast_ip,wins_ip))
continue;
for (work = d->workgrouplist; work; work = work->next)
{
if (!AM_MASTER(work))
@ -116,7 +120,7 @@ void browser_gone(char *work_name, struct in_addr ip)
if (!work || !d) return;
/* don't do election stuff on the WINS subnet */
if (ip_equal(d->bcast_ip,ipgrp))
if (ip_equal(d->bcast_ip,wins_ip))
return;
if (strequal(work->work_group, lp_workgroup()))
@ -350,6 +354,9 @@ void become_local_master(struct subnet_record *d, struct work_record *work)
/* update our server status */
work->ServerType |= SV_TYPE_MASTER_BROWSER;
DEBUG(3,("become_local_master: updating our server %s to type %x\n", myname, work->ServerType));
add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
if (work->serverlist == NULL) /* no servers! */
@ -638,6 +645,14 @@ void run_elections(time_t t)
for (d = subnetlist; d; d = d->next)
{
struct work_record *work;
if(ip_equal(d->bcast_ip, wins_ip))
{
/* WINS ip */
DEBUG(10,("run_elections: ignoring WINS subnet\n"));
continue;
}
for (work = d->workgrouplist; work; work = work->next)
{
if (work->RunningElection)
@ -710,7 +725,7 @@ void process_election(struct packet_struct *p,char *buf)
if (!d) return;
if (ip_equal(d->bcast_ip,ipgrp)) {
if (ip_equal(d->bcast_ip,wins_ip)) {
DEBUG(3,("Unexpected election request from %s %s on WINS net\n",
name, inet_ntoa(p->ip)));
return;

View File

@ -47,104 +47,114 @@ void process_logon_packet(struct packet_struct *p,char *buf,int len)
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
struct subnet_record *d = find_subnet(ip);
struct subnet_record *d = find_subnet_all(ip);
char *logname,*q;
fstring reply_name;
BOOL add_slashes = False;
pstring outbuf;
int code,reply_code;
struct work_record *work;
char unknown_byte = 0;
uint16 request_count = 0;
uint16 token = 0;
char unknown_byte = 0;
uint16 request_count = 0;
uint16 token = 0;
if (!d) return;
if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False))) return;
if (!lp_domain_logons())
{
DEBUG(3,("No domain logons\n"));
return;
}
code = SVAL(buf,0);
switch (code)
{
case 0:
if (!lp_domain_logons())
{
char *machine = buf+2;
char *user = skip_string(machine,1);
char *tmp;
logname = skip_string(user,1);
tmp = skip_string(logname,1);
unknown_byte = CVAL(tmp,0);
request_count = SVAL(tmp,1);
token = SVAL(tmp,3);
reply_code = 0x6;
strcpy(reply_name,myname);
strupper(reply_name);
add_slashes = True;
DEBUG(3,("Domain login request from %s(%s) user=%s token=%x\n",
machine,inet_ntoa(p->ip),user,token));
break;
}
case 7:
{
char *machine = buf+2;
logname = skip_string(machine,1);
token = SVAL(skip_string(logname,1),0);
strcpy(reply_name,lp_domain_controller());
if (!*reply_name)
{
/* oo! no domain controller. must be us, then */
strcpy(reply_name,myname);
reply_code = 0xC;
}
else
{
/* refer logon request to the domain controller */
reply_code = 0x7;
DEBUG(3,("No domain logons\n"));
return;
}
if (!d)
{
DEBUG(0,("process_logon_packet: Cannot find subnet for logon request from %s\n",
inet_ntoa(p->ip) ));
return;
}
if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False)))
{
DEBUG(0,("process_logon_packet: Cannot find WORKGROUP %s for logon request fomr %s\n",
dgram->dest_name.name, inet_ntoa(p->ip) ));
return;
}
code = SVAL(buf,0);
switch (code)
{
case 0:
{
char *machine = buf+2;
char *user = skip_string(machine,1);
char *tmp;
logname = skip_string(user,1);
tmp = skip_string(logname,1);
unknown_byte = CVAL(tmp,0);
request_count = SVAL(tmp,1);
token = SVAL(tmp,3);
reply_code = 0x6;
strcpy(reply_name,myname);
strupper(reply_name);
add_slashes = True;
DEBUG(3,("Domain login request from %s(%s) user=%s token=%x\n",
machine,inet_ntoa(p->ip),user,token));
break;
}
case 7:
{
char *machine = buf+2;
logname = skip_string(machine,1);
token = SVAL(skip_string(logname,1),0);
strcpy(reply_name,lp_domain_controller());
if (!*reply_name)
{
/* oo! no domain controller. must be us, then */
strcpy(reply_name,myname);
reply_code = 0xC;
}
else
{
/* refer logon request to the domain controller */
reply_code = 0x7;
}
strupper(reply_name);
DEBUG(3,("GETDC request from %s(%s), reporting %s 0x%x token=%x\n",
machine,inet_ntoa(p->ip), reply_name, reply_code,token));
break;
}
default:
{
DEBUG(3,("Unknown domain request %d\n",code));
return;
}
}
strupper(reply_name);
DEBUG(3,("GETDC request from %s(%s), reporting %s 0x%x token=%x\n",
machine,inet_ntoa(p->ip), reply_name, reply_code,token));
break;
}
default:
{
DEBUG(3,("Unknown domain request %d\n",code));
return;
}
}
bzero(outbuf,sizeof(outbuf));
q = outbuf;
SSVAL(q,0,reply_code);
q += 2;
if (token == 0xffff || /* LM 2.0 or later */
token == 0xfffe) /* WfWg networking */
if (token == 0xffff || /* LM 2.0 or later */
token == 0xfffe) /* WfWg networking */
{
if (add_slashes)
{
if (add_slashes)
{
strcpy(q,"\\\\");
q += 2;
}
strcpy(q, reply_name);
strupper(q);
q = skip_string(q,1);
if (token == 0xffff) /* LM 2.0 or later */
{
SSVAL(q,0,token);
q += 2;
}
strcpy(q,"\\\\");
q += 2;
}
strcpy(q, reply_name);
strupper(q);
q = skip_string(q,1);
if (token == 0xffff) /* LM 2.0 or later */
{
SSVAL(q,0,token);
q += 2;
}
}
SSVAL(q,0,0xFFFF);
q += 2;

View File

@ -36,7 +36,7 @@ extern int num_response_packets;
BOOL CanRecurse = True;
extern pstring scope;
extern struct in_addr ipgrp;
extern struct in_addr wins_ip;
static uint16 name_trn_id=0;
@ -91,9 +91,9 @@ static void update_name_trn_id(void)
initiate a netbios packet
****************************************************************************/
void initiate_netbios_packet(uint16 *id,
int fd,int quest_type,char *name,int name_type,
int nb_flags,BOOL bcast,BOOL recurse,
struct in_addr to_ip)
int fd,int quest_type,char *name,int name_type,
int nb_flags,BOOL bcast,BOOL recurse,
struct in_addr to_ip)
{
struct packet_struct p;
struct nmb_packet *nmb = &p.packet.nmb;
@ -323,8 +323,10 @@ static BOOL listening(struct packet_struct *p,struct nmb_name *n)
struct subnet_record *d;
struct name_record *n1;
/* We explicitly don't search WINS here - this will be done
in find_name_search is it was a packet from a non-local subnet. */
d = find_subnet(p->ip);
n1 = find_name_search(&d,n,FIND_LOCAL|FIND_WINS|FIND_SELF,p->ip);
return (n1 != NULL);
@ -565,7 +567,6 @@ BOOL send_mailslot_reply(BOOL unique, char *mailslot,int fd,char *buf,int len,ch
{
struct packet_struct p;
struct dgram_packet *dgram = &p.packet.dgram;
struct in_addr wins_ip = ipgrp;
char *ptr,*p2;
char tmp[4];

View File

@ -33,7 +33,7 @@ extern int DEBUGLEVEL;
extern pstring scope;
extern struct in_addr ipzero;
extern struct in_addr ipgrp;
extern struct in_addr wins_ip;
/***************************************************************************
@ -51,146 +51,146 @@ static void dead_netbios_entry(struct subnet_record *d,
{
case NAME_QUERY_CONFIRM:
{
if (!lp_wins_support()) return; /* only if we're a WINS server */
if (n->num_msgs == 0)
if (!lp_wins_support()) return; /* only if we're a WINS server */
if (n->num_msgs == 0)
{
/* oops. name query had no response. check that the name is
unique and then remove it from our WINS database */
/* IMPORTANT: see query_refresh_names() */
if ((!NAME_GROUP(n->nb_flags)))
{
struct subnet_record *d1 = find_subnet(ipgrp);
if (d1)
{
/* remove the name that had been registered with us,
and we're now getting no response when challenging.
see rfc1001.txt 15.5.2
*/
remove_netbios_name(d1, n->name.name, n->name.name_type,
REGISTER, n->send_ip);
}
}
/* oops. name query had no response. check that the name is
unique and then remove it from our WINS database */
/* IMPORTANT: see query_refresh_names() */
if ((!NAME_GROUP(n->nb_flags)))
{
struct subnet_record *d1 = find_subnet(wins_ip);
if (d1)
{
/* remove the name that had been registered with us,
and we're now getting no response when challenging.
see rfc1001.txt 15.5.2
*/
remove_netbios_name(d1, n->name.name, n->name.name_type,
REGISTER, n->send_ip);
}
break;
}
}
break;
}
case NAME_QUERY_MST_CHK:
{
/* if no response received, the master browser must have gone
down on that subnet, without telling anyone. */
/* IMPORTANT: see response_netbios_packet() */
if (n->num_msgs == 0)
browser_gone(n->name.name, n->send_ip);
break;
}
case NAME_RELEASE:
{
/* if no response received, it must be OK for us to release the
name. nobody objected (including a potentially dead or deaf
WINS server) */
/* IMPORTANT: see response_name_release() */
if (ismyip(n->send_ip))
{
name_unregister_work(d,n->name.name,n->name.name_type);
}
if (!n->bcast && n->num_msgs == 0)
{
DEBUG(0,("WINS server did not respond to name release!\n"));
/* XXXX whoops. we have problems. must deal with this */
}
break;
}
case NAME_REGISTER_CHALLENGE:
{
/* name challenge: no reply. we can reply to the person that
wanted the unique name and tell them that they can have it
*/
add_name_respond(d,n->fd,d->myip, n->response_id ,&n->name,
n->nb_flags, GET_TTL(0),
n->reply_to_ip, False, n->reply_to_ip);
if (!n->bcast && n->num_msgs == 0)
{
DEBUG(1,("WINS server did not respond to name registration!\n"));
/* XXXX whoops. we have problems. must deal with this */
}
break;
}
case NAME_REGISTER:
{
/* if no response received, and we are using a broadcast registration
method, it must be OK for us to register the name: nobody objected
on that subnet. if we are using a WINS server, then the WINS
server must be dead or deaf.
*/
if (n->num_msgs == 0)
{
if (n->bcast)
{
/* broadcast method: implicit acceptance of the name registration
by not receiving any objections. */
/* IMPORTANT: see response_name_reg() */
name_register_work(d,n->name.name,n->name.name_type,
n->nb_flags, n->ttl, n->reply_to_ip, n->bcast);
}
else
{
/* received no response. rfc1001.txt states that after retrying,
we should assume the WINS server is dead, and fall back to
broadcasting (see bits about M nodes: can't find any right
now) */
DEBUG(1,("WINS server did not respond to name registration!\n"));
/* XXXX whoops. we have problems. must deal with this */
}
}
break;
}
case NAME_QUERY_DOMAIN:
{
/* if no response received, there is no domain controller on
this local subnet. it's ok for us to register
*/
if (!n->bcast)
{
DEBUG(0,("NAME_QUERY_DOMAIN incorrectly used - contact samba-bugs!\n"));
/* XXXX whoops. someone's using this to unicast a packet. this state
should only be used for broadcast checks
*/
break;
}
if (n->num_msgs == 0)
{
struct work_record *work = find_workgroupstruct(d,n->name.name,False);
if (work && d)
{
become_domain_master(d,work);
}
}
break;
}
case NAME_QUERY_MST_CHK:
{
/* if no response received, the master browser must have gone
down on that subnet, without telling anyone. */
/* IMPORTANT: see response_netbios_packet() */
if (n->num_msgs == 0)
browser_gone(n->name.name, n->send_ip);
break;
}
case NAME_RELEASE:
{
/* if no response received, it must be OK for us to release the
name. nobody objected (including a potentially dead or deaf
WINS server) */
/* IMPORTANT: see response_name_release() */
if (ismyip(n->send_ip))
{
name_unregister_work(d,n->name.name,n->name.name_type);
}
if (!n->bcast && n->num_msgs == 0)
{
DEBUG(0,("WINS server did not respond to name release!\n"));
/* XXXX whoops. we have problems. must deal with this */
}
break;
}
case NAME_REGISTER_CHALLENGE:
{
/* name challenge: no reply. we can reply to the person that
wanted the unique name and tell them that they can have it
*/
add_name_respond(d,n->fd,d->myip, n->response_id ,&n->name,
n->nb_flags, GET_TTL(0),
n->reply_to_ip, False, n->reply_to_ip);
if (!n->bcast && n->num_msgs == 0)
{
DEBUG(1,("WINS server did not respond to name registration!\n"));
/* XXXX whoops. we have problems. must deal with this */
}
default:
{
/* nothing to do but delete the dead expected-response structure */
/* this is normal. */
break;
}
case NAME_REGISTER:
{
/* if no response received, and we are using a broadcast registration
method, it must be OK for us to register the name: nobody objected
on that subnet. if we are using a WINS server, then the WINS
server must be dead or deaf.
*/
if (n->num_msgs == 0)
{
if (n->bcast)
{
/* broadcast method: implicit acceptance of the name registration
by not receiving any objections. */
/* IMPORTANT: see response_name_reg() */
name_register_work(d,n->name.name,n->name.name_type,
n->nb_flags, n->ttl, n->reply_to_ip, n->bcast);
}
else
{
/* received no response. rfc1001.txt states that after retrying,
we should assume the WINS server is dead, and fall back to
broadcasting (see bits about M nodes: can't find any right
now) */
DEBUG(1,("WINS server did not respond to name registration!\n"));
/* XXXX whoops. we have problems. must deal with this */
}
}
break;
}
case NAME_QUERY_DOMAIN:
{
/* if no response received, there is no domain controller on
this local subnet. it's ok for us to register
*/
if (!n->bcast)
{
DEBUG(0,("NAME_QUERY_DOMAIN incorrectly used - contact samba-bugs!\n"));
/* XXXX whoops. someone's using this to unicast a packet. this state
should only be used for broadcast checks
*/
break;
}
if (n->num_msgs == 0)
{
struct work_record *work = find_workgroupstruct(d,n->name.name,False);
if (work && d)
{
become_domain_master(d,work);
}
}
break;
}
default:
{
/* nothing to do but delete the dead expected-response structure */
/* this is normal. */
break;
}
}
}
}
@ -300,10 +300,9 @@ struct response_record *queue_netbios_packet(struct subnet_record *d,
int fd,int quest_type,enum state_type state,char *name,
int name_type,int nb_flags, time_t ttl,
int server_type, char *my_name, char *my_comment,
BOOL bcast,BOOL recurse,
BOOL bcast,BOOL recurse,
struct in_addr send_ip, struct in_addr reply_to_ip)
{
struct in_addr wins_ip = ipgrp;
struct response_record *n;
uint16 id = 0xffff;
@ -311,7 +310,7 @@ struct response_record *queue_netbios_packet(struct subnet_record *d,
if (ip_equal(wins_ip, send_ip)) return NULL;
initiate_netbios_packet(&id, fd, quest_type, name, name_type,
nb_flags, bcast, recurse, send_ip);
nb_flags, bcast, recurse, send_ip);
if (id == 0xffff) {
DEBUG(4,("did not initiate netbios packet: %s\n", inet_ntoa(send_ip)));
@ -319,9 +318,9 @@ struct response_record *queue_netbios_packet(struct subnet_record *d,
}
if ((n = make_response_queue_record(state,id,fd,
quest_type,name,name_type,nb_flags,ttl,
server_type,my_name, my_comment,
bcast,recurse,send_ip,reply_to_ip)))
quest_type,name,name_type,nb_flags,ttl,
server_type,my_name, my_comment,
bcast,recurse,send_ip,reply_to_ip)))
{
add_response_record(d,n);
return n;

View File

@ -38,7 +38,7 @@ extern int DEBUGLEVEL;
extern pstring scope;
extern pstring myname;
extern struct in_addr ipzero;
extern struct in_addr ipgrp;
extern struct in_addr wins_ip;
extern struct subnet_record *subnetlist;
@ -80,7 +80,7 @@ void remove_name_entry(struct subnet_record *d, char *name,int type)
don't really own */
remove_netbios_name(d,name,type,SELF,n2->ip_flgs[0].ip);
if (ip_equal(d->bcast_ip, ipgrp))
if (ip_equal(d->bcast_ip, wins_ip))
{
if (!lp_wins_support())
{
@ -125,7 +125,7 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags)
name entry to a local-subnet name database. see rfc1001.txt 15.1.1 p28
regarding the point about M-nodes. */
if (ip_equal(d->bcast_ip, ipgrp))
if (ip_equal(d->bcast_ip, wins_ip))
{
if (lp_wins_support())
{
@ -194,10 +194,16 @@ void add_domain_names(time_t t)
if (lp_domain_master() && work && work->dom_state == DOMAIN_NONE)
{
DEBUG(0,("add_domain_names:Checking for domain master on workgroup %s\n", lp_workgroup()));
make_nmb_name(&n,lp_workgroup(),0x1b,scope);
if (!find_name(d->namelist, &n, FIND_SELF))
{
if (ip_equal(d->bcast_ip,ipgrp))
DEBUG(0,("add_domain_names: attempting to become domain master browser on workgroup %s, bcast %s\n",
lp_workgroup(), inet_ntoa(d->bcast_ip)));
if (ip_equal(d->bcast_ip,wins_ip))
{
if (lp_wins_support())
{
@ -221,6 +227,8 @@ void add_domain_names(time_t t)
NetBIOS name 0x1b.
*/
DEBUG(0,("add_domain_names:querying for domain master on workgroup %s\n", lp_workgroup()));
queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_DOMAIN,
lp_workgroup(), 0x1b,
0, 0,0,NULL,NULL,
@ -246,7 +254,7 @@ void add_my_names(void)
for (d = subnetlist; d; d = d->next)
{
BOOL wins = lp_wins_support() && ip_equal(d->bcast_ip,ipgrp);
BOOL wins = lp_wins_support() && ip_equal(d->bcast_ip,wins_ip);
struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
add_my_name_entry(d, myname,0x20,nb_type|NB_ACTIVE);
@ -339,7 +347,7 @@ void refresh_my_names(time_t t)
void query_refresh_names(time_t t)
{
struct name_record *n;
struct subnet_record *d = find_subnet(ipgrp);
struct subnet_record *d = find_subnet(wins_ip);
static time_t lasttime = 0;

View File

@ -36,7 +36,7 @@ extern int ClientNMB;
extern int DEBUGLEVEL;
extern struct in_addr ipgrp;
extern struct in_addr wins_ip;
/****************************************************************************
@ -120,35 +120,35 @@ void reply_name_release(struct packet_struct *p)
namestr(&nmb->question.question_name)));
if (!(d = find_req_subnet(p->ip, bcast)))
{
DEBUG(3,("response packet: bcast %s not known\n",
inet_ntoa(p->ip)));
return;
}
{
DEBUG(3,("response packet: bcast %s not known\n",
inet_ntoa(p->ip)));
return;
}
if (bcast)
search |= FIND_LOCAL;
search |= FIND_LOCAL;
else
search |= FIND_WINS;
search |= FIND_WINS;
n = find_name_search(&d, &nmb->question.question_name,
search, ip);
search, ip);
/* XXXX under what conditions should we reject the removal?? */
if (n && n->ip_flgs[0].nb_flags == nb_flags)
{
{
success = True;
remove_name(d,n);
n = NULL;
}
}
if (bcast) return;
/* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REL,
success, False,
&nmb->question.question_name, nb_flags, 0, ip);
success, False,
&nmb->question.question_name, nb_flags, 0, ip);
}
@ -190,7 +190,7 @@ void reply_name_reg(struct packet_struct *p)
{
/* apparently we should return 255.255.255.255 for group queries
(email from MS) */
ip = ipgrp;
ip = wins_ip;
}
if (!(d = find_req_subnet(p->ip, bcast)))
@ -393,8 +393,8 @@ void reply_name_status(struct packet_struct *p)
if (!strequal(n->name.name,"*") &&
!strequal(n->name.name,"__SAMBA__") &&
(name_type < 0x1b || name_type > 0x20 ||
ques_type < 0x1b || ques_type > 0x20 ||
(name_type < 0x1b || name_type >= 0x20 ||
ques_type < 0x1b || ques_type >= 0x20 ||
strequal(qname, n->name.name)))
{
/* start with first bit of putting info in buffer: the name */
@ -433,7 +433,7 @@ void reply_name_status(struct packet_struct *p)
/* end of this name list: add wins names too? */
struct subnet_record *w_d;
if (!(w_d = find_subnet(ipgrp))) break;
if (!(w_d = find_subnet(wins_ip))) break;
if (w_d != d)
{
@ -520,7 +520,7 @@ void reply_name_query(struct packet_struct *p)
}
else
{
if (!(d = find_subnet(ipgrp)))
if (!(d = find_subnet(wins_ip)))
{
DEBUG(3,("name query: wins search %s not known\n",
inet_ntoa(p->ip)));

View File

@ -192,10 +192,13 @@ static void response_server_check(struct nmb_name *ans_name,
enum state_type cmd = (n->state == NAME_QUERY_DOM_SRV_CHK) ?
NAME_STATUS_DOM_SRV_CHK : NAME_STATUS_SRV_CHK;
/* initiate a name status check on the server that replied */
/* initiate a name status check on the server that replied
in addition, the workgroup being checked has been stored
in the response_record->my_name (see announce_master) we
also propagate this into the same field. */
queue_netbios_packet(d,ClientNMB,NMB_STATUS, cmd,
ans_name->name, ans_name->name_type,
0,0,0,NULL,NULL,
0,0,0,n->my_name,NULL,
False,False,n->send_ip,n->reply_to_ip);
}
@ -243,10 +246,12 @@ static BOOL interpret_node_status(struct subnet_record *d,
if (NAME_MFLAG (nb_flags)) { strcat(flags,"M "); }
if (NAME_HFLAG (nb_flags)) { strcat(flags,"H "); }
if (NAME_DEREG (nb_flags)) { strcat(flags,"<DEREGISTERING> "); }
if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); add=True;}
if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); }
if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
/* I don't think we should be messing with our namelist here... JRA */
#if 0
/* might as well update our namelist while we're at it */
if (add)
{
@ -262,9 +267,10 @@ static BOOL interpret_node_status(struct subnet_record *d,
}
add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast);
}
#endif /* JRA */
/* we want the server name */
if (serv_name && !*serv_name && !group && t == 0)
if (serv_name && !*serv_name && !group && type == 0x20)
{
StrnCpy(serv_name,qname,15);
serv_name[15] = 0;
@ -275,8 +281,8 @@ static BOOL interpret_node_status(struct subnet_record *d,
{
/* take a guess at some of the name types we're going to ask for.
evaluate whether they are group names or no... */
if (((t == 0x1b || t == 0x1d ) && !group) ||
((t == 0x20 || t == 0x1c || t == 0x1e) && group))
if (((t == 0x1b || t == 0x1d || t == 0x20 ) && !group) ||
((t == 0x1c || t == 0x1e ) && group))
{
found = True;
make_nmb_name(name,qname,type,scope);
@ -306,17 +312,20 @@ static void response_name_status_check(struct in_addr ip,
fstring serv_name;
if (interpret_node_status(d,nmb->answers->rdata,
&name,name.name_type,serv_name,ip,bcast))
&name,0x20,serv_name,ip,bcast))
{
if (*serv_name)
{
/* response_record->my_name contains the
workgroup name to sync with. See
response_server_check() */
sync_server(n->state,serv_name,
name.name,name.name_type, n->send_ip);
n->my_name,name.name_type, n->send_ip);
}
}
else
{
DEBUG(1,("No 0x1d name type in interpret_node_status()\n"));
DEBUG(1,("No 0x20 name type in interpret_node_status()\n"));
}
}
@ -409,69 +418,74 @@ static void response_name_query_sync(struct nmb_packet *nmb,
struct nmb_name *ans_name, BOOL bcast,
struct response_record *n, struct subnet_record *d)
{
DEBUG(4, ("Name query at %s ip %s - ",
namestr(&n->name), inet_ntoa(n->send_ip)));
DEBUG(4, ("Name query at %s ip %s - ",
namestr(&n->name), inet_ntoa(n->send_ip)));
if (!name_equal(&n->name, ans_name))
{
/* someone gave us the wrong name as a reply. oops. */
DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
return;
}
if (nmb->header.rcode == 0 && nmb->answers->rdata)
if (!name_equal(&n->name, ans_name))
{
int nb_flags = nmb->answers->rdata[0];
struct in_addr found_ip;
/* someone gave us the wrong name as a reply. oops. */
DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
return;
}
putip((char*)&found_ip,&nmb->answers->rdata[2]);
if (!ip_equal(n->send_ip, found_ip))
{
/* someone gave us the wrong ip as a reply. oops. */
DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
return;
}
DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
if (n->state == NAME_QUERY_SYNC_LOCAL ||
n->state == NAME_QUERY_SYNC_REMOTE)
{
struct work_record *work = NULL;
if ((work = find_workgroupstruct(d, ans_name->name, False)))
{
BOOL local_list_only = n->state == NAME_QUERY_SYNC_LOCAL;
/* the server is there: sync quick before it (possibly) dies! */
sync_browse_lists(d, work, ans_name->name, ans_name->name_type,
found_ip, local_list_only);
}
}
else
{
/* update our netbios name list (re-register it if necessary) */
add_netbios_entry(d, ans_name->name, ans_name->name_type,
nb_flags,GET_TTL(0),REGISTER,
found_ip,False,!bcast);
}
}
else
if (nmb->header.rcode == 0 && nmb->answers->rdata)
{
int nb_flags = nmb->answers->rdata[0];
struct in_addr found_ip;
putip((char*)&found_ip,&nmb->answers->rdata[2]);
if (!ip_equal(n->send_ip, found_ip))
{
DEBUG(4, (" NEGATIVE RESPONSE!\n"));
if (n->state == NAME_QUERY_CONFIRM)
{
/* XXXX remove_netbios_entry()? */
/* lots of things we ought to do, here. if we get here,
then we're in a mess: our name database doesn't match
reality. sort it out
*/
remove_netbios_name(d,n->name.name, n->name.name_type,
REGISTER,n->send_ip);
}
/* someone gave us the wrong ip as a reply. oops. */
DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
return;
}
DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
if (n->state == NAME_QUERY_SYNC_LOCAL ||
n->state == NAME_QUERY_SYNC_REMOTE)
{
struct work_record *work = NULL;
/* We cheat here as we know that the workgroup name has
been placed in the my_comment field of the
response_record struct by the code in
start_sync_browse_entry().
*/
if ((work = find_workgroupstruct(d, n->my_comment, False)))
{
BOOL local_list_only = n->state == NAME_QUERY_SYNC_LOCAL;
/* the server is there: sync quick before it (possibly) dies! */
sync_browse_lists(d, work, ans_name->name, ans_name->name_type,
found_ip, local_list_only);
}
}
else
{
/* update our netbios name list (re-register it if necessary) */
add_netbios_entry(d, ans_name->name, ans_name->name_type,
nb_flags,GET_TTL(0),REGISTER,
found_ip,False,!bcast);
}
}
else
{
DEBUG(4, (" NEGATIVE RESPONSE!\n"));
if (n->state == NAME_QUERY_CONFIRM)
{
/* XXXX remove_netbios_entry()? */
/* lots of things we ought to do, here. if we get here,
then we're in a mess: our name database doesn't match
reality. sort it out
*/
remove_netbios_name(d,n->name.name, n->name.name_type,
REGISTER,n->send_ip);
}
}
}
@ -481,13 +495,13 @@ static void response_name_query_sync(struct nmb_packet *nmb,
static void debug_rr_type(int rr_type)
{
switch (rr_type)
{
case NMB_STATUS: DEBUG(3,("Name status ")); break;
case NMB_QUERY : DEBUG(3,("Name query ")); break;
case NMB_REG : DEBUG(3,("Name registration ")); break;
case NMB_REL : DEBUG(3,("Name release ")); break;
default : DEBUG(1,("wrong response packet type received")); break;
}
{
case NMB_STATUS: DEBUG(3,("Name status ")); break;
case NMB_QUERY : DEBUG(3,("Name query ")); break;
case NMB_REG : DEBUG(3,("Name registration ")); break;
case NMB_REL : DEBUG(3,("Name release ")); break;
default : DEBUG(1,("wrong response packet type received")); break;
}
}
/****************************************************************************
@ -497,8 +511,8 @@ void debug_state_type(int state)
{
/* report the state type to help debugging */
switch (state)
{
case NAME_QUERY_DOM_SRV_CHK : DEBUG(4,("MASTER_SVR_CHECK\n")); break;
{
case NAME_QUERY_DOM_SRV_CHK : DEBUG(4,("NAME_QUERY_DOM_SRV_CHK\n")); break;
case NAME_QUERY_SRV_CHK : DEBUG(4,("NAME_QUERY_SRV_CHK\n")); break;
case NAME_QUERY_FIND_MST : DEBUG(4,("NAME_QUERY_FIND_MST\n")); break;
case NAME_QUERY_MST_CHK : DEBUG(4,("NAME_QUERY_MST_CHK\n")); break;
@ -506,17 +520,17 @@ void debug_state_type(int state)
case NAME_QUERY_SYNC_LOCAL : DEBUG(4,("NAME_QUERY_SYNC_LOCAL\n")); break;
case NAME_QUERY_SYNC_REMOTE : DEBUG(4,("NAME_QUERY_SYNC_REMOTE\n")); break;
case NAME_QUERY_ANNOUNCE_HOST: DEBUG(4,("NAME_QUERY_ANNCE_HOST\n"));break;
case NAME_REGISTER : DEBUG(4,("NAME_REGISTER\n")); break;
case NAME_REGISTER_CHALLENGE : DEBUG(4,("NAME_REGISTER_CHALLENGE\n"));break;
case NAME_RELEASE : DEBUG(4,("NAME_RELEASE\n")); break;
case NAME_STATUS_DOM_SRV_CHK : DEBUG(4,("NAME_STAT_MST_CHK\n")); break;
case NAME_STATUS_DOM_SRV_CHK : DEBUG(4,("NAME_STATUS_DOM_SRV_CHK\n")); break;
case NAME_STATUS_SRV_CHK : DEBUG(4,("NAME_STATUS_SRV_CHK\n")); break;
default: break;
}
}
}
/****************************************************************************
@ -528,87 +542,95 @@ static BOOL response_problem_check(struct response_record *n,
struct nmb_packet *nmb, char *ans_name)
{
switch (nmb->answers->rr_type)
{
case NMB_REL:
{
case NMB_REL:
{
if (n->num_msgs > 1)
{
{
DEBUG(1,("more than one release name response received!\n"));
return True;
}
}
break;
}
}
case NMB_REG:
{
{
if (n->num_msgs > 1)
{
{
DEBUG(1,("more than one register name response received!\n"));
return True;
}
}
break;
}
}
case NMB_QUERY:
{
if (n->num_msgs > 1)
{
if (nmb->header.rcode == 0 && nmb->answers->rdata)
{
if (n->num_msgs > 1)
{
if (nmb->header.rcode == 0 && nmb->answers->rdata)
{
int nb_flags = nmb->answers->rdata[0];
if ((!NAME_GROUP(nb_flags)))
{
int nb_flags = nmb->answers->rdata[0];
if ((!NAME_GROUP(nb_flags)))
/* oh dear. more than one person responded to a
unique name.
there is either a network problem, a
configuration problem
or a server is mis-behaving */
/* XXXX mark the name as in conflict, and then let the
person who just responded know that they
must also mark it
as in conflict, and therefore must NOT use it.
see rfc1001.txt 15.1.3.5 */
/* this may cause problems for some
early versions of nmbd */
switch (n->state)
{
case NAME_QUERY_FIND_MST:
{
/* oh dear. more than one person responded to a unique name.
there is either a network problem, a configuration problem
or a server is mis-behaving */
/* XXXX mark the name as in conflict, and then let the
person who just responded know that they must also mark it
as in conflict, and therefore must NOT use it.
see rfc1001.txt 15.1.3.5 */
/* this may cause problems for some early versions of nmbd */
switch (n->state)
{
case NAME_QUERY_FIND_MST:
{
/* query for ^1^2__MSBROWSE__^2^1 expect lots of responses */
return False;
}
case NAME_QUERY_ANNOUNCE_HOST:
case NAME_QUERY_DOM_SRV_CHK:
case NAME_QUERY_SRV_CHK:
case NAME_QUERY_MST_CHK:
{
if (!strequal(ans_name,n->name.name))
{
/* one subnet, one master browser per workgroup */
/* XXXX force an election? */
DEBUG(3,("more than one master browser replied!\n"));
return True;
}
break;
}
default: break;
}
DEBUG(3,("Unique Name conflict detected!\n"));
return True;
/* query for ^1^2__MSBROWSE__^2^1 expect
lots of responses */
return False;
}
case NAME_QUERY_ANNOUNCE_HOST:
case NAME_QUERY_DOM_SRV_CHK:
case NAME_QUERY_SRV_CHK:
case NAME_QUERY_MST_CHK:
{
if (!strequal(ans_name,n->name.name))
{
/* one subnet, one master browser
per workgroup */
/* XXXX force an election? */
DEBUG(3,("more than one master browser replied!\n"));
return True;
}
break;
}
default: break;
}
DEBUG(3,("Unique Name conflict detected!\n"));
return True;
}
else
{
/* we have received a negative reply, having already received
at least one response (pos/neg). something's really wrong! */
DEBUG(3,("wierd name query problem detected!\n"));
return True;
}
}
}
else
{
/* we have received a negative reply,
having already received
at least one response (pos/neg).
something's really wrong! */
DEBUG(3,("wierd name query problem detected!\n"));
return True;
}
}
}
}
}
return False;
}
@ -685,73 +707,73 @@ static BOOL response_compatible(struct response_record *n,
process the response packet received
****************************************************************************/
static void response_process(struct subnet_record *d, struct packet_struct *p,
struct response_record *n, struct nmb_packet *nmb,
BOOL bcast, struct nmb_name *ans_name)
struct response_record *n, struct nmb_packet *nmb,
BOOL bcast, struct nmb_name *ans_name)
{
switch (n->state)
{
case NAME_RELEASE:
{
case NAME_RELEASE:
{
response_name_release(ans_name, d, p);
break;
}
}
case NAME_REGISTER:
{
{
response_name_reg(ans_name, d, p);
break;
}
}
case NAME_REGISTER_CHALLENGE:
{
{
response_name_query_register(nmb, ans_name, n, d);
break;
}
}
case NAME_QUERY_DOM_SRV_CHK:
case NAME_QUERY_SRV_CHK:
case NAME_QUERY_FIND_MST:
{
response_server_check(ans_name, n, d);
break;
}
{
response_server_check(ans_name, n, d);
break;
}
case NAME_STATUS_DOM_SRV_CHK:
case NAME_STATUS_SRV_CHK:
{
response_name_status_check(p->ip, nmb, bcast, n, d);
break;
}
{
response_name_status_check(p->ip, nmb, bcast, n, d);
break;
}
case NAME_QUERY_ANNOUNCE_HOST:
{
response_announce_host(ans_name, nmb, n, d);
break;
}
{
response_announce_host(ans_name, nmb, n, d);
break;
}
case NAME_QUERY_CONFIRM:
case NAME_QUERY_SYNC_LOCAL:
case NAME_QUERY_SYNC_REMOTE:
{
response_name_query_sync(nmb, ans_name, bcast, n, d);
break;
}
{
response_name_query_sync(nmb, ans_name, bcast, n, d);
break;
}
case NAME_QUERY_MST_CHK:
{
/* no action required here. it's when NO responses are received
that we need to do something. see expire_name_query_entries() */
{
/* no action required here. it's when NO responses are received
that we need to do something. see expire_name_query_entries() */
DEBUG(4, ("Master browser exists for %s at %s (just checking!)\n",
namestr(&n->name), inet_ntoa(n->send_ip)));
break;
}
DEBUG(4, ("Master browser exists for %s at %s (just checking!)\n",
namestr(&n->name), inet_ntoa(n->send_ip)));
break;
}
default:
{
DEBUG(1,("unknown state type received in response_netbios_packet\n"));
break;
{
DEBUG(1,("unknown state type received in response_netbios_packet\n"));
break;
}
}
}
}
@ -772,43 +794,41 @@ void response_netbios_packet(struct packet_struct *p)
}
if (!d)
{
DEBUG(2,("response packet: subnet %s not known\n", inet_ntoa(p->ip)));
return;
}
{
DEBUG(2,("response packet: subnet %s not known\n", inet_ntoa(p->ip)));
return;
}
/* args wrong way round: spotted by ccm@shentel.net */
if (!same_net(d->bcast_ip, p->ip, d->mask_ip)) /* copes with WINS 'subnet' */
{
DEBUG(2,("response from %s. ", inet_ntoa(p->ip)));
DEBUG(2,("expected on subnet %s. hmm.\n", inet_ntoa(d->bcast_ip)));
}
{
DEBUG(2,("response from %s. ", inet_ntoa(p->ip)));
DEBUG(2,("expected on subnet %s. hmm.\n", inet_ntoa(d->bcast_ip)));
}
if (nmb->answers == NULL)
{
{
/* hm. the packet received was a response, but with no answer. wierd! */
DEBUG(2,("NMB packet response from %s (bcast=%s) - UNKNOWN\n",
inet_ntoa(p->ip), BOOLSTR(bcast)));
return;
}
}
ans_name = &nmb->answers->rr_name;
DEBUG(3,("response for %s from %s (bcast=%s)\n",
namestr(ans_name), inet_ntoa(p->ip), BOOLSTR(bcast)));
debug_rr_type(nmb->answers->rr_type);
n->num_msgs++; /* count number of responses received */
n->repeat_count = 0; /* don't resend: see expire_netbios_packets() */
debug_state_type(n->state);
/* problem checking: multiple responses etc */
if (response_problem_check(n, nmb, ans_name->name))
return;
/* now deal with the current state */
response_process(d, p, n, nmb, bcast, ans_name);
}

View File

@ -173,10 +173,10 @@ BOOL same_context(struct dgram_packet *dgram)
resources. We just have to pass it to smbd (via browser.dat) and let
the client choose using bit masks.
******************************************************************/
static void process_announce(struct packet_struct *p,uint16 command,char *buf)
static void process_localnet_announce(struct packet_struct *p,uint16 command,char *buf)
{
struct dgram_packet *dgram = &p->packet.dgram;
struct subnet_record *d = find_subnet(p->ip);
struct subnet_record *d = find_subnet(p->ip); /* Explicitly exclude WINS - local nets only */
int update_count = CVAL(buf,0);
int ttl = IVAL(buf,1)/1000;
@ -278,25 +278,33 @@ static void process_announce(struct packet_struct *p,uint16 command,char *buf)
static void process_master_announce(struct packet_struct *p,char *buf)
{
struct dgram_packet *dgram = &p->packet.dgram;
struct subnet_record *d = find_subnet(p->ip);
struct subnet_record *d = find_subnet_all(p->ip); /* Explicitly include WINS */
char *name = buf;
struct work_record *work;
name[15] = 0;
DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
DEBUG(3,("process_master_announce: Master Announce from %s (%s)\n",name,inet_ntoa(p->ip)));
if (same_context(dgram)) return;
if (!d) return;
if (!d)
{
DEBUG(3,("process_master_announce: Cannot find interface\n"));
return;
}
if (!lp_domain_master()) return;
if (!lp_domain_master())
{
DEBUG(3,("process_master_announce: Not configured as domain master - ignoring master announce.\n"));
return;
}
for (work = d->workgrouplist; work; work = work->next)
{
if (AM_MASTER(work))
if (AM_MASTER(work) || AM_DOMMST(work) || AM_ANY_MASTER(work))
{
/* merge browse lists with them */
add_browser_entry(name,0x1b, work->work_group,30,p->ip,True);
add_browser_entry(name,0x1d, work->work_group,30,p->ip,True);
}
}
}
@ -612,13 +620,13 @@ static void process_announce_request(struct packet_struct *p,char *buf)
struct dgram_packet *dgram = &p->packet.dgram;
struct work_record *work;
struct in_addr ip = dgram->header.source_ip;
struct subnet_record *d = find_subnet(ip);
struct subnet_record *d = find_subnet(ip); /* Explicitly NO WINS */
int token = CVAL(buf,0);
char *name = buf+1;
name[15] = 0;
DEBUG(3,("Announce request from %s to %s token=0x%X\n",
DEBUG(3,("process_announce_request: Announce request from %s to %s token=0x%X\n",
name,namestr(&dgram->dest_name), token));
if (strequal(dgram->source_name.name,myname)) return;
@ -630,8 +638,13 @@ static void process_announce_request(struct packet_struct *p,char *buf)
if (strequal(dgram->dest_name, lp_workgroup()) return; ???
*/
if (!d) return;
if (!d)
{
DEBUG(3,("process_announce_request: No local interface to announce to %s\n",
name));
return;
}
for (work = d->workgrouplist; work; work = work->next)
{
/* XXXX BUG: the destination name type should also be checked,
@ -660,7 +673,7 @@ void process_browse_packet(struct packet_struct *p,char *buf,int len)
case ANN_LocalMasterAnnouncement:
{
debug_browse_data(buf, len);
process_announce(p,command,buf+1);
process_localnet_announce(p,command,buf+1);
break;
}

View File

@ -272,7 +272,7 @@ static void load_hosts_file(char *fname)
}
ipaddr = *interpret_addr2(ip);
d = find_subnet(ipaddr);
d = find_subnet_all(ipaddr);
if (d) {
add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True,True);
add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);

View File

@ -140,7 +140,7 @@ void sync_browse_lists(struct subnet_record *d, struct work_record *work,
{
uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
if (!d || !work || !AM_MASTER(work)) return;
if (!d || !work || !AM_ANY_MASTER(work)) return;
pid = getpid();
uid = getuid();

View File

@ -600,7 +600,7 @@ static void init_globals(void)
Globals.bDomainMaster = False;
Globals.bDomainLogons = False;
Globals.bBrowseList = True;
Globals.bWINSsupport = True;
Globals.bWINSsupport = False;
Globals.bWINSproxy = False;
Globals.ReadSize = 16*1024;