1/*
2   Unix SMB/CIFS implementation.
3   NBT netbios routines and daemon - version 2
4   Copyright (C) Andrew Tridgell 1994-1998
5   Copyright (C) Luke Kenneth Casson Leighton 1994-1998
6   Copyright (C) Jeremy Allison 1994-2003
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23
24#include "includes.h"
25
26/* This is our local master browser list database. */
27extern ubi_dlList lmb_browserlist[];
28
29/****************************************************************************
30As a domain master browser, do a sync with a local master browser.
31**************************************************************************/
32
33static void sync_with_lmb(struct browse_cache_record *browc)
34{
35	struct work_record *work;
36
37	if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) ) {
38		if( DEBUGLVL( 0 ) ) {
39			dbgtext( "sync_with_lmb:\n" );
40			dbgtext( "Failed to get a workgroup for a local master browser " );
41			dbgtext( "cache entry workgroup " );
42			dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
43		}
44		return;
45	}
46
47	/* We should only be doing this if we are a domain master browser for
48		the given workgroup. Ensure this is so. */
49
50	if(!AM_DOMAIN_MASTER_BROWSER(work)) {
51		if( DEBUGLVL( 0 ) ) {
52			dbgtext( "sync_with_lmb:\n" );
53			dbgtext( "We are trying to sync with a local master browser " );
54			dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
55			dbgtext( "and we are not a domain master browser on this workgroup.\n" );
56			dbgtext( "Error!\n" );
57		}
58		return;
59	}
60
61	if( DEBUGLVL( 2 ) ) {
62		dbgtext( "sync_with_lmb:\n" );
63		dbgtext( "Initiating sync with local master browser " );
64		dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
65		dbgtext( "for workgroup %s\n", browc->work_group );
66	}
67
68	sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
69
70	browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
71}
72
73/****************************************************************************
74Sync or expire any local master browsers.
75**************************************************************************/
76
77void dmb_expire_and_sync_browser_lists(time_t t)
78{
79	static time_t last_run = 0;
80	struct browse_cache_record *browc;
81
82	/* Only do this every 20 seconds. */
83	if (t - last_run < 20)
84		return;
85
86	last_run = t;
87
88	expire_lmb_browsers(t);
89
90	for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
91			browc;
92			browc = (struct browse_cache_record *)ubi_dlNext( browc ) ) {
93		if (browc->sync_time < t)
94			sync_with_lmb(browc);
95	}
96}
97
98/****************************************************************************
99As a local master browser, send an announce packet to the domain master browser.
100**************************************************************************/
101
102static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
103{
104	pstring outbuf;
105	unstring myname;
106	unstring dmb_name;
107	char *p;
108
109	if(ismyip(work->dmb_addr)) {
110		if( DEBUGLVL( 2 ) ) {
111			dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
112			dbgtext( "We are both a domain and a local master browser for " );
113			dbgtext( "workgroup %s.  ", work->work_group );
114			dbgtext( "Do not announce to ourselves.\n" );
115		}
116		return;
117	}
118
119	memset(outbuf,'\0',sizeof(outbuf));
120	p = outbuf;
121	SCVAL(p,0,ANN_MasterAnnouncement);
122	p++;
123
124	unstrcpy(myname, global_myname());
125	strupper_m(myname);
126	myname[15]='\0';
127	/* The call below does CH_UNIX -> CH_DOS conversion. JRA */
128	push_pstring_base(p, myname, outbuf);
129
130	p = skip_string(p,1);
131
132	if( DEBUGLVL( 4 ) ) {
133		dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
134		dbgtext( "Sending local master announce to " );
135		dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
136					work->work_group );
137	}
138
139	/* Target name for send_mailslot must be in UNIX charset. */
140	pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
141	send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
142		global_myname(), 0x0, dmb_name, 0x0,
143		work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
144}
145
146/****************************************************************************
147As a local master browser, do a sync with a domain master browser.
148**************************************************************************/
149
150static void sync_with_dmb(struct work_record *work)
151{
152	unstring dmb_name;
153
154	if( DEBUGLVL( 2 ) ) {
155		dbgtext( "sync_with_dmb:\n" );
156		dbgtext( "Initiating sync with domain master browser " );
157		dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
158		dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
159		dbgtext( "for workgroup %s\n", work->work_group );
160	}
161
162	pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
163	sync_browse_lists(work, dmb_name, work->dmb_name.name_type,
164		work->dmb_addr, False, True);
165}
166
167/****************************************************************************
168  Function called when a node status query to a domain master browser IP succeeds.
169****************************************************************************/
170
171static void domain_master_node_status_success(struct subnet_record *subrec,
172                                              struct userdata_struct *userdata,
173                                              struct res_rec *answers,
174                                              struct in_addr from_ip)
175{
176	struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
177
178	if( work == NULL ) {
179		if( DEBUGLVL( 0 ) ) {
180			dbgtext( "domain_master_node_status_success:\n" );
181			dbgtext( "Unable to find workgroup " );
182			dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
183		}
184		return;
185	}
186
187	if( DEBUGLVL( 3 ) ) {
188		dbgtext( "domain_master_node_status_success:\n" );
189		dbgtext( "Success in node status for workgroup " );
190		dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
191	}
192
193  /* Go through the list of names found at answers->rdata and look for
194     the first SERVER<0x20> name. */
195
196	if(answers->rdata != NULL) {
197		char *p = answers->rdata;
198		int numnames = CVAL(p, 0);
199
200		p += 1;
201
202		while (numnames--) {
203			unstring qname;
204			uint16 nb_flags;
205			int name_type;
206
207			pull_ascii_nstring(qname, sizeof(qname), p);
208			name_type = CVAL(p,15);
209			nb_flags = get_nb_flags(&p[16]);
210			trim_char(qname,'\0',' ');
211
212			p += 18;
213
214			if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {
215				struct nmb_name nmbname;
216
217				make_nmb_name(&nmbname, qname, name_type);
218
219				/* Copy the dmb name and IP address
220					into the workgroup struct. */
221
222				work->dmb_name = nmbname;
223				putip((char *)&work->dmb_addr, &from_ip);
224
225				/* Do the local master browser announcement to the domain
226					master browser name and IP. */
227				announce_local_master_browser_to_domain_master_browser( work );
228
229				/* Now synchronise lists with the domain master browser. */
230				sync_with_dmb(work);
231				break;
232			}
233		}
234	} else if( DEBUGLVL( 0 ) ) {
235		dbgtext( "domain_master_node_status_success:\n" );
236		dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
237		dbgtext( "%s.\n", inet_ntoa(from_ip) );
238	}
239}
240
241/****************************************************************************
242  Function called when a node status query to a domain master browser IP fails.
243****************************************************************************/
244
245static void domain_master_node_status_fail(struct subnet_record *subrec,
246                       struct response_record *rrec)
247{
248	struct userdata_struct *userdata = rrec->userdata;
249
250	if( DEBUGLVL( 0 ) ) {
251		dbgtext( "domain_master_node_status_fail:\n" );
252		dbgtext( "Doing a node status request to the domain master browser\n" );
253		dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
254		dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
255		dbgtext( "Cannot sync browser lists.\n" );
256	}
257}
258
259/****************************************************************************
260  Function called when a query for a WORKGROUP<1b> name succeeds.
261****************************************************************************/
262
263static void find_domain_master_name_query_success(struct subnet_record *subrec,
264                        struct userdata_struct *userdata_in,
265                        struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
266{
267	/*
268	 * Unfortunately, finding the IP address of the Domain Master Browser,
269	 * as we have here, is not enough. We need to now do a sync to the
270	 * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
271	 * respond to the SMBSERVER name. To get this name from IP
272	 * address we do a Node status request, and look for the first
273	 * NAME<0x20> in the response, and take that as the server name.
274	 * We also keep a cache of the Domain Master Browser name for this
275	 * workgroup in the Workgroup struct, so that if the same IP addess
276	 * is returned every time, we don't need to do the node status
277	 * request.
278	 */
279
280	struct work_record *work;
281	struct nmb_name nmbname;
282	struct userdata_struct *userdata;
283	size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
284	unstring qname;
285
286	pull_ascii_nstring(qname, sizeof(qname), q_name->name);
287	if( !(work = find_workgroup_on_subnet(subrec, qname)) ) {
288		if( DEBUGLVL( 0 ) ) {
289			dbgtext( "find_domain_master_name_query_success:\n" );
290			dbgtext( "Failed to find workgroup %s\n", qname);
291		}
292	return;
293  }
294
295  /* First check if we already have a dmb for this workgroup. */
296
297	if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip)) {
298		/* Do the local master browser announcement to the domain
299			master browser name and IP. */
300		announce_local_master_browser_to_domain_master_browser( work );
301
302		/* Now synchronise lists with the domain master browser. */
303		sync_with_dmb(work);
304		return;
305	} else {
306		zero_ip(&work->dmb_addr);
307	}
308
309	/* Now initiate the node status request. */
310
311	/* We used to use the name "*",0x0 here, but some Windows
312	 * servers don't answer that name. However we *know* they
313	 * have the name workgroup#1b (as we just looked it up).
314	 * So do the node status request on this name instead.
315	 * Found at LBL labs. JRA.
316	 */
317
318	make_nmb_name(&nmbname,work->work_group,0x1b);
319
320	/* Put the workgroup name into the userdata so we know
321	 what workgroup we're talking to when the reply comes
322	 back. */
323
324	/* Setup the userdata_struct - this is copied so we can use
325	a stack variable for this. */
326
327	if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
328		DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
329		return;
330	}
331
332	userdata->copy_fn = NULL;
333	userdata->free_fn = NULL;
334	userdata->userdata_len = strlen(work->work_group)+1;
335	overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
336
337	node_status( subrec, &nmbname, answer_ip,
338		domain_master_node_status_success,
339		domain_master_node_status_fail,
340		userdata);
341
342	zero_free(userdata, size);
343}
344
345/****************************************************************************
346  Function called when a query for a WORKGROUP<1b> name fails.
347  ****************************************************************************/
348
349static void find_domain_master_name_query_fail(struct subnet_record *subrec,
350                                    struct response_record *rrec,
351                                    struct nmb_name *question_name, int fail_code)
352{
353	if( DEBUGLVL( 0 ) ) {
354		dbgtext( "find_domain_master_name_query_fail:\n" );
355		dbgtext( "Unable to find the Domain Master Browser name " );
356		dbgtext( "%s for the workgroup %s.\n",
357			nmb_namestr(question_name), question_name->name );
358		dbgtext( "Unable to sync browse lists in this workgroup.\n" );
359	}
360}
361
362/****************************************************************************
363As a local master browser for a workgroup find the domain master browser
364name, announce ourselves as local master browser to it and then pull the
365full domain browse lists from it onto the given subnet.
366**************************************************************************/
367
368void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
369                                                   struct work_record *work)
370{
371	/* Only do this if we are using a WINS server. */
372	if(we_are_a_wins_client() == False) {
373		if( DEBUGLVL( 10 ) ) {
374			dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
375			dbgtext( "Ignoring, as we are not a WINS client.\n" );
376		}
377		return;
378	}
379
380	/* First, query for the WORKGROUP<1b> name from the WINS server. */
381	query_name(unicast_subnet, work->work_group, 0x1b,
382             find_domain_master_name_query_success,
383             find_domain_master_name_query_fail,
384             NULL);
385}
386
387/****************************************************************************
388  Function called when a node status query to a domain master browser IP succeeds.
389  This function is only called on query to a Samba 1.9.18 or above WINS server.
390
391  Note that adding the workgroup name is enough for this workgroup to be
392  browsable by clients, as clients query the WINS server or broadcast
393  nets for the WORKGROUP<1b> name when they want to browse a workgroup
394  they are not in. We do not need to do a sync with this Domain Master
395  Browser in order for our browse clients to see machines in this workgroup.
396  JRA.
397****************************************************************************/
398
399static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
400                                              struct userdata_struct *userdata,
401                                              struct res_rec *answers,
402                                              struct in_addr from_ip)
403{
404	struct work_record *work;
405	unstring server_name;
406
407	server_name[0] = 0;
408
409	if( DEBUGLVL( 3 ) ) {
410		dbgtext( "get_domain_master_name_node_status_success:\n" );
411		dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
412	}
413
414	/*
415	 * Go through the list of names found at answers->rdata and look for
416	 * the first WORKGROUP<0x1b> name.
417	 */
418
419	if(answers->rdata != NULL) {
420		char *p = answers->rdata;
421		int numnames = CVAL(p, 0);
422
423		p += 1;
424
425		while (numnames--) {
426			unstring qname;
427			uint16 nb_flags;
428			int name_type;
429
430			pull_ascii_nstring(qname, sizeof(qname), p);
431			name_type = CVAL(p,15);
432			nb_flags = get_nb_flags(&p[16]);
433			trim_char(qname,'\0',' ');
434
435			p += 18;
436
437			if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
438					server_name[0] == 0) {
439				/* this is almost certainly the server netbios name */
440				unstrcpy(server_name, qname);
441				continue;
442			}
443
444			if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
445				if( DEBUGLVL( 5 ) ) {
446					dbgtext( "get_domain_master_name_node_status_success:\n" );
447					dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
448					dbgtext( "is a domain master browser for workgroup " );
449					dbgtext( "%s. Adding this name.\n", qname );
450				}
451
452				/*
453				 * If we don't already know about this workgroup, add it
454				 * to the workgroup list on the unicast_subnet.
455				 */
456
457				if((work = find_workgroup_on_subnet( subrec, qname)) == NULL) {
458					struct nmb_name nmbname;
459					/*
460					 * Add it - with an hour in the cache.
461					 */
462					if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
463						return;
464
465					/* remember who the master is */
466					unstrcpy(work->local_master_browser_name, server_name);
467					make_nmb_name(&nmbname, server_name, 0x20);
468					work->dmb_name = nmbname;
469					work->dmb_addr = from_ip;
470				}
471				break;
472			}
473		}
474	} else if( DEBUGLVL( 0 ) ) {
475		dbgtext( "get_domain_master_name_node_status_success:\n" );
476		dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
477		dbgtext( "%s.\n", inet_ntoa(from_ip) );
478	}
479}
480
481/****************************************************************************
482  Function called when a node status query to a domain master browser IP fails.
483****************************************************************************/
484
485static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
486                       struct response_record *rrec)
487{
488	if( DEBUGLVL( 0 ) ) {
489		dbgtext( "get_domain_master_name_node_status_fail:\n" );
490		dbgtext( "Doing a node status request to the domain master browser " );
491		dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
492		dbgtext( "Cannot get workgroup name.\n" );
493	}
494}
495
496/****************************************************************************
497  Function called when a query for *<1b> name succeeds.
498****************************************************************************/
499
500static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
501                        struct userdata_struct *userdata_in,
502                        struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
503{
504	/*
505	 * We now have a list of all the domain master browsers for all workgroups
506	 * that have registered with the WINS server. Now do a node status request
507	 * to each one and look for the first 1b name in the reply. This will be
508	 * the workgroup name that we will add to the unicast subnet as a 'non-local'
509	 * workgroup.
510	 */
511
512	struct nmb_name nmbname;
513	struct in_addr send_ip;
514	int i;
515
516	if( DEBUGLVL( 5 ) ) {
517		dbgtext( "find_all_domain_master_names_query_succes:\n" );
518		dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
519		dbgtext( "IP addresses for Domain Master Browsers.\n" );
520	}
521
522	for(i = 0; i < rrec->rdlength / 6; i++) {
523		/* Initiate the node status requests. */
524		make_nmb_name(&nmbname, "*", 0);
525
526		putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
527
528		/*
529		 * Don't send node status requests to ourself.
530		 */
531
532		if(ismyip( send_ip )) {
533			if( DEBUGLVL( 5 ) ) {
534				dbgtext( "find_all_domain_master_names_query_succes:\n" );
535				dbgtext( "Not sending node status to our own IP " );
536				dbgtext( "%s.\n", inet_ntoa(send_ip) );
537			}
538			continue;
539		}
540
541		if( DEBUGLVL( 5 ) ) {
542			dbgtext( "find_all_domain_master_names_query_success:\n" );
543			dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
544		}
545
546		node_status( subrec, &nmbname, send_ip,
547				get_domain_master_name_node_status_success,
548				get_domain_master_name_node_status_fail,
549				NULL);
550	}
551}
552
553/****************************************************************************
554  Function called when a query for *<1b> name fails.
555  ****************************************************************************/
556static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
557                                    struct response_record *rrec,
558                                    struct nmb_name *question_name, int fail_code)
559{
560	if( DEBUGLVL( 10 ) ) {
561		dbgtext( "find_domain_master_name_query_fail:\n" );
562		dbgtext( "WINS server did not reply to a query for name " );
563		dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
564		dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
565	}
566}
567
568/****************************************************************************
569 If we are a domain master browser on the unicast subnet, do a query to the
570 WINS server for the *<1b> name. This will only work to a Samba WINS server,
571 so ignore it if we fail. If we succeed, contact each of the IP addresses in
572 turn and do a node status request to them. If this succeeds then look for a
573 <1b> name in the reply - this is the workgroup name. Add this to the unicast
574 subnet. This is expensive, so we only do this every 15 minutes.
575**************************************************************************/
576
577void collect_all_workgroup_names_from_wins_server(time_t t)
578{
579	static time_t lastrun = 0;
580	struct work_record *work;
581
582	/* Only do this if we are using a WINS server. */
583	if(we_are_a_wins_client() == False)
584		return;
585
586	/* Check to see if we are a domain master browser on the unicast subnet. */
587	if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL) {
588		if( DEBUGLVL( 0 ) ) {
589			dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
590			dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
591			dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
592		}
593		return;
594	}
595
596	if(!AM_DOMAIN_MASTER_BROWSER(work))
597		return;
598
599	if ((lastrun != 0) && (t < lastrun + (15 * 60)))
600		return;
601
602	lastrun = t;
603
604	/* First, query for the *<1b> name from the WINS server. */
605	query_name(unicast_subnet, "*", 0x1b,
606		find_all_domain_master_names_query_success,
607		find_all_domain_master_names_query_fail,
608		NULL);
609}
610
611
612/****************************************************************************
613 If we are a domain master browser on the unicast subnet, do a regular sync
614 with all other DMBs that we know of on that subnet.
615
616To prevent exponential network traffic with large numbers of workgroups
617we use a randomised system where sync probability is inversely proportional
618to the number of known workgroups
619**************************************************************************/
620
621void sync_all_dmbs(time_t t)
622{
623	static time_t lastrun = 0;
624	struct work_record *work;
625	int count=0;
626
627	/* Only do this if we are using a WINS server. */
628	if(we_are_a_wins_client() == False)
629		return;
630
631	/* Check to see if we are a domain master browser on the
632           unicast subnet. */
633	work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
634	if (!work)
635		return;
636
637	if (!AM_DOMAIN_MASTER_BROWSER(work))
638		return;
639
640	if ((lastrun != 0) && (t < lastrun + (5 * 60)))
641		return;
642
643	/* count how many syncs we might need to do */
644	for (work=unicast_subnet->workgrouplist; work; work = work->next) {
645		if (strcmp(lp_workgroup(), work->work_group)) {
646			count++;
647		}
648	}
649
650	/* sync with a probability of 1/count */
651	for (work=unicast_subnet->workgrouplist; work; work = work->next) {
652		if (strcmp(lp_workgroup(), work->work_group)) {
653			unstring dmb_name;
654
655			if (((unsigned)sys_random()) % count != 0)
656				continue;
657
658			lastrun = t;
659
660			if (!work->dmb_name.name[0]) {
661				/* we don't know the DMB - assume it is
662				   the same as the unicast local master */
663				make_nmb_name(&work->dmb_name,
664					      work->local_master_browser_name,
665					      0x20);
666			}
667
668			pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
669
670			DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
671				 dmb_name, inet_ntoa(work->dmb_addr)));
672
673			sync_browse_lists(work,
674					  dmb_name,
675					  work->dmb_name.name_type,
676					  work->dmb_addr, False, False);
677		}
678	}
679}
680