1/*
2 * Copyright (c) 1988-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 *   0.01 05/12/94	Laurent Dumont		Creation
30 *
31 *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
32 */
33/*
34 *
35 * Router ZIP protocol functions:
36 *
37 * This file contains Routing specifics to handle ZIP requests and responses
38 * sent and received by a router node.
39 *
40 * The entry point for the zip input in ddp is valid only when we're
41 * running in router mode.
42 *
43 */
44
45#include <sys/errno.h>
46#include <sys/types.h>
47#include <sys/param.h>
48#include <machine/spl.h>
49#include <sys/systm.h>
50#include <sys/kernel.h>
51#include <sys/proc.h>
52#include <sys/filedesc.h>
53#include <sys/fcntl.h>
54#include <sys/mbuf.h>
55#include <sys/ioctl.h>
56#include <sys/malloc.h>
57#include <sys/socket.h>
58#include <sys/socketvar.h>
59
60#include <net/if.h>
61#include <net/if_types.h>
62
63#include <netat/sysglue.h>
64#include <netat/appletalk.h>
65#include <netat/at_pcb.h>
66#include <netat/at_var.h>
67#include <netat/ddp.h>
68#include <netat/nbp.h>
69#include <netat/zip.h>
70#include <netat/atp.h>
71#include <netat/routing_tables.h>
72#include <netat/rtmp.h>
73#include <netat/debug.h>
74
75#include <sys/kern_event.h>
76
77/* globals */
78extern at_ifaddr_t *ifID_table[], *ifID_home;
79extern short	ErrorZIPoverflow;
80
81/**********************************************************************
82 * Remarks :
83 *	ZIP is implemented as a "peer" of DDP, so the packets coming in
84 *	to ZIP have the same headers as those coming in to DDP {ddp...}.
85 *	Same applies to outgoing packets. Also, unlike DDP, ZIP assumes
86 *	that an incoming packet is in a contiguous gbuf_t.
87 *
88 **********************************************************************/
89
90static	int	netinfo_reply_pending;
91static	void	zip_netinfo_reply(at_x_zip_t *, at_ifaddr_t *);
92static	void	zip_getnetinfo(at_ifaddr_t *);
93static	void	zip_getnetinfo_locked(void *);
94static	void	send_phony_reply(void *);
95
96int zip_reply_received(gbuf_t *, at_ifaddr_t *, int);
97int zip_reply_to_getlocalzones(at_ifaddr_t *, gbuf_t *);
98int zip_reply_to_getzonelist(at_ifaddr_t *, gbuf_t *);
99static void zip_reply_to_getmyzone(at_ifaddr_t *, gbuf_t *);
100gbuf_t *zip_prep_query_packet(at_ifaddr_t *, at_net_al, at_node);
101
102static void zip_send_reply_to_query(gbuf_t *, at_ifaddr_t *);
103static void zip_send_ext_reply_to_query(gbuf_t *, at_ifaddr_t *, RT_entry *, u_short);
104static gbuf_t *prep_ZIP_reply_packet(gbuf_t *, at_ifaddr_t *);
105static void zip_send_getnetinfo_reply(gbuf_t *, at_ifaddr_t *);
106
107/*
108 * zip_send_getnetinfo_reply: we received a GetNetInfo packet, we need to reply
109 *		   with the right information for the port.
110 */
111static void zip_send_getnetinfo_reply(m, ifID)
112     register gbuf_t	*m;
113     register at_ifaddr_t	*ifID;
114{
115	at_nvestr_t	*zname;
116	gbuf_t *m_sent;
117	at_ddp_t	*ddp, *ddp_sent;
118	short ZoneNameProvided = FALSE;
119	short RequestIsBroadcasted = FALSE;
120	u_short znumber, len, packet_length = 0, size, status;
121	RT_entry *Entry;
122	char GNIReply[128];
123
124	ddp = (at_ddp_t *)gbuf_rptr(m);
125
126	/* access the Zone Name info part of the GetNetInfo Request */
127
128	zname = (at_nvestr_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 6);
129
130	if (zname->len > ZIP_MAX_ZONE_LENGTH) {
131		dPrintf(D_M_ZIP, D_L_WARNING,
132			("zip_s_gni_r: zone len too long l=%d ddplen=%d\n",
133			 zname->len, DDPLEN_VALUE(ddp)));
134		return;
135	}
136
137
138	if (zname->len)
139		ZoneNameProvided = TRUE;
140
141	GNIReply[0] = ZIP_NETINFO_REPLY;
142	GNIReply[1] = ZIP_ZONENAME_INVALID;
143
144	/* check if we are the originator is in the cable range for this interface */
145
146	if ((NET_VALUE(ddp->src_net) < CableStart || NET_VALUE(ddp->src_net) > CableStop) &&
147		(NET_VALUE(ddp->dst_net) == 0 && ddp->dst_node == 0xff)) {
148			RequestIsBroadcasted = TRUE;
149	}
150	Entry = rt_blookup(CableStop);
151
152	if (Entry != NULL && RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */
153
154		GNIReply[2] = (Entry->NetStart & 0xFF00) >> 8;
155		GNIReply[3] = (Entry->NetStart & 0x00FF);
156		GNIReply[4] = (Entry->NetStop & 0xFF00) >> 8;
157		GNIReply[5] = (Entry->NetStop & 0x00FF);
158
159		/* copy the zone name found in the request */
160
161		GNIReply[6] = zname->len;
162		bcopy(&zname->str, &GNIReply[7], zname->len);
163
164
165		if ((znumber = zt_find_zname(zname))) {
166
167			if (ZT_ISIN_ZMAP((znumber), Entry->ZoneBitMap)) {
168
169			  GNIReply[1] = 0; /* Zone Valid */
170
171			  if ((len = zt_get_zmcast(ifID, zname, &GNIReply[8+zname->len])))
172				GNIReply[7+zname->len] = len;
173			  else {
174				GNIReply[1] |= ZIP_USE_BROADCAST;
175				GNIReply[7+zname->len] = 0; /* multicast address length */
176			  }
177			  packet_length = 8 + zname->len + len;
178		    }
179		}
180
181	}
182
183	else {	/* should not happen, we are supposed to know our net */
184	  dPrintf(D_M_ZIP, D_L_WARNING, ("zip_s_gni_r: Don't know about our zone infos!!!\n"));
185		return;
186	}
187
188	if (zt_ent_zcount(Entry) == 1)
189		GNIReply[1] |= ZIP_ONE_ZONE;
190
191	if (GNIReply[1] & ZIP_ZONENAME_INVALID) {
192
193		short Index = ifID->ifDefZone;
194
195		if (Index <= 0 || Index >= ZT_MAXEDOUT) {
196	  		dPrintf(D_M_ZIP, D_L_WARNING,
197			  ("zip_s_gni_r: Invalid starting index =%d port%d\n",
198				 Index, ifID->ifPort));
199			return;
200		}
201
202
203		Index--;
204
205		if ((len = zt_get_zmcast(ifID, &ZT_table[Index].Zone, &GNIReply[8+zname->len])))
206			GNIReply[7+zname->len] = len;
207		else {
208			GNIReply[1] |= ZIP_USE_BROADCAST;
209			GNIReply[7+zname->len] = 0; /* multicast address length */
210		}
211
212		packet_length = 7 + zname->len + len;
213
214		/* in the case the zone name asked for in the request was invalid, we need
215		 * to copy the good default zone for this net
216		 */
217
218		GNIReply[packet_length + 1] = ZT_table[Index].Zone.len;
219		bcopy(&ZT_table[Index].Zone.str, &GNIReply[packet_length + 2],
220				ZT_table[Index].Zone.len);
221		packet_length = packet_length +2 + ZT_table[Index].Zone.len;
222	}
223
224
225	/*
226	 * we're finally ready to send out the GetNetInfo Reply
227	 *
228	 */
229
230
231	size =  DDP_X_HDR_SIZE + packet_length;
232	if ((m_sent = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) {
233	  return; /* was return(ENOBUFS); */
234	}
235
236	gbuf_rinc(m_sent,AT_WR_OFFSET);
237	gbuf_wset(m_sent,size);
238	ddp_sent = (at_ddp_t *)(gbuf_rptr(m_sent));
239
240	/* Prepare the DDP header */
241
242	ddp_sent->unused = ddp_sent->hopcount = 0;
243	UAS_ASSIGN(ddp->checksum, 0);
244	DDPLEN_ASSIGN(ddp_sent, size);
245	NET_ASSIGN(ddp_sent->src_net, ifID->ifThisNode.s_net);
246	ddp_sent->src_node = ifID->ifThisNode.s_node;
247	ddp_sent->src_socket = ZIP_SOCKET;
248	ddp_sent->dst_socket = ddp->src_socket;
249
250	if (RequestIsBroadcasted) { /* if this was a broadcast, must respond from that */
251
252		NET_ASSIGN(ddp_sent->dst_net, 0);
253		ddp_sent->dst_node = 0xFF;
254	}
255	else {
256
257	  NET_NET(ddp_sent->dst_net, ddp->src_net);
258	  ddp_sent->dst_node = ddp->src_node;
259	}
260	ddp_sent->type = DDP_ZIP;
261
262	bcopy(&GNIReply, &ddp_sent->data, packet_length);
263
264	dPrintf(D_M_ZIP_LOW, D_L_ROUTING,
265		("zip_s_gni_r: send to %d:%d port#%d pack_len=%d\n",
266		 NET_VALUE(ddp_sent->dst_net), ddp_sent->dst_node,
267		 ifID->ifPort, packet_length));
268	if ((status =
269	     ddp_router_output(m_sent, ifID, AT_ADDR,
270			      NET_VALUE(ddp_sent->dst_net), ddp_sent->dst_node, 0))) {
271	  dPrintf(D_M_ZIP, D_L_ERROR,
272		  ("zip_s_gni_r: ddp_router_output returns =%d\n", status));
273	  return; /* was return(status); */
274	}
275} /* zip_send_getnetinfo_reply */
276
277
278/*
279 * build_ZIP_reply_packet: is used to create and send a DDP packet and use the
280 * provided buffer as a ZIP reply. This is used by zip_send_ext_reply_to_query
281 * and zip_send_reply_to_query for sending their replies to ZIP queries.
282 */
283gbuf_t *prep_ZIP_reply_packet(m, ifID)
284     register gbuf_t *m;		/* this is the original zip query */
285     register at_ifaddr_t *ifID;
286{
287	register gbuf_t *m_sent;
288	register at_ddp_t	*ddp, *src_ddp;
289
290	/* access the source Net and Node informations */
291
292	src_ddp = (at_ddp_t *)gbuf_rptr(m);
293
294	if ((m_sent = gbuf_alloc (AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
295		return((gbuf_t *)NULL);
296	}
297	gbuf_rinc(m_sent,AT_WR_OFFSET);
298	gbuf_wset(m_sent,DDP_X_HDR_SIZE);
299	ddp = (at_ddp_t *)(gbuf_rptr(m_sent));
300
301	/* Prepare the DDP header */
302
303	ddp->unused = ddp->hopcount = 0;
304	UAS_ASSIGN(ddp->checksum, 0);
305
306	NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
307	ddp->src_node = ifID->ifThisNode.s_node;
308	ddp->src_socket = ZIP_SOCKET;
309
310	ddp->dst_socket = src_ddp->src_socket;
311	NET_NET(ddp->dst_net, src_ddp->src_net);
312	ddp->dst_node = src_ddp->src_node;
313
314	ddp->type = DDP_ZIP;
315
316	return(m_sent);
317}
318/*
319 * zip_send_ext_reply_to_query: this function deals with ZIP Queries for extended nets.
320 *  When we recognize an extended net (that might have several zone name associated with
321 *  it), we send A SEPARATE ZIP reply for that network. This is called from the
322 *  regular zip_send_reply_to_query, that just deals with non-ext nets.
323 */
324
325static void zip_send_ext_reply_to_query(mreceived, ifID, Entry, NetAsked)
326     register gbuf_t	*mreceived;
327     register at_ifaddr_t	*ifID;
328     RT_entry *Entry;		/* info about the network we're looking for */
329     u_short NetAsked;
330{
331	register gbuf_t	*m;
332	register at_ddp_t	*ddp;
333	short i, j, reply_length, Index, zone_count, status;
334	u_char	*zmap;
335	char *ReplyBuff, *ZonesInPacket;
336
337	zone_count = zt_ent_zcount(Entry);
338	zmap = Entry->ZoneBitMap;
339	i = ZT_BYTES -1;
340
341
342newPacket:
343
344	if (!(m = prep_ZIP_reply_packet (mreceived, ifID))) {
345	  return; /* was return(ENOBUFS); */
346	}
347
348	ddp = (at_ddp_t *)(gbuf_rptr(m));
349	ReplyBuff = (char *)(ddp->data);
350
351
352	*ReplyBuff++ = 8;	/* ZIP function = 8 [extended reply] */
353
354	ZonesInPacket= ReplyBuff;
355	*ZonesInPacket= 0;
356	ReplyBuff ++;
357	reply_length = 2;	/* 1st byte is ZIP reply code, 2nd is network count */
358	j= 0;
359
360	/* For all zones, we check if they belong to the map for that Network */
361
362	for (;  i >= 0; i--) {
363
364		/* find the zones defined in this entry bitmap */
365
366		if (zmap[i]) {
367			for (; j < 8 ; j++)
368				if (zmap[i] << j & 0x80) { /* bingo */
369
370					Index = i*8 + j; /* zone index in zone table */
371
372					if (reply_length + 3 + ZT_table[Index].Zone.len  > DDP_DATA_SIZE) {
373
374					/* we need to send the packet before, this won't fit... */
375
376						zone_count -= *ZonesInPacket;
377
378						DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE));
379						gbuf_winc(m,reply_length);
380						if ((status =
381						     ddp_router_output(m, ifID, AT_ADDR,
382								       NET_VALUE(ddp->dst_net), ddp->dst_node, 0))) {
383						  dPrintf(D_M_ZIP, D_L_ERROR,
384							  ("zip_s_ext_repl: ddp_router_output returns =%d\n",
385							   status));
386						  return; /* was return (status); */
387						}
388
389						goto newPacket;
390
391					}
392					/* this should fit in this packet, build the NetNumber, ZoneLen,
393				 	* ZoneName triple
394				 	*/
395
396					if (ZT_table[Index].Zone.len) {
397						*ZonesInPacket += 1; /* bump NetCount field */
398						*ReplyBuff++ = (NetAsked & 0xFF00) >> 8;
399						*ReplyBuff++ = (NetAsked & 0x00FF) ;
400						*ReplyBuff++ = ZT_table[Index].Zone.len;
401
402						bcopy(&ZT_table[Index].Zone.str, ReplyBuff,
403								ZT_table[Index].Zone.len);
404
405						ReplyBuff += ZT_table[Index].Zone.len;
406						reply_length += ZT_table[Index].Zone.len +3;
407					}
408
409				}
410			}
411			j= 0;	/* reset the bit count */
412	}
413
414	/* if we have some zone info in a half-empty packet, send it now.
415	 * Remember, for extended nets we send *at least* one Reply
416	 */
417
418	if (zone_count) {
419			DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE));
420			gbuf_winc(m,reply_length);
421			if ((status =
422			     ddp_router_output(m, ifID, AT_ADDR,
423					       NET_VALUE(ddp->dst_net), ddp->dst_node, 0))) {
424			  dPrintf(D_M_ZIP, D_L_ERROR,
425				  ("zip_s_ext_reply: ddp_router_output returns =%d\n", status));
426			  return; /* was return (status); */
427			}
428	}
429	else  /* free the buffer not used */
430
431		gbuf_freem(m);
432} /* zip_send_ext_reply_to_query */
433
434/*
435 * zip_send_reply_to_query: we received a ZIPQuery packet, we need to reply
436 *	with the right information for the nets requested (if we have
437 *	the right information.
438 */
439static void zip_send_reply_to_query(mreceived, ifID)
440     register gbuf_t	*mreceived;
441     register at_ifaddr_t	*ifID;
442{
443	register gbuf_t	*m;
444	register at_ddp_t	*ddp = NULL, *ddp_received;
445	RT_entry *Entry;
446	short i, reply_length, Index, status;
447	u_char	network_count;
448	u_short *NetAsked;
449	char *ReplyBuff, *ZonesInPacket;
450
451	ddp_received = (at_ddp_t *)gbuf_rptr(mreceived);
452
453	/* access the number of nets requested in the Query */
454	network_count  = *((char *)(ddp_received->data) + 1);
455	NetAsked = (u_short *)(ddp_received->data + 2);
456
457	/* check the validity of the Query packet */
458
459	if (DDPLEN_VALUE(ddp_received) !=
460	    (2 + network_count * 2 + DDP_X_HDR_SIZE)) {
461
462	  	dPrintf(D_M_ZIP, D_L_WARNING,
463			("zip_s_reply_to_q: bad length netcount=%d len=%d\n",
464			 network_count, DDPLEN_VALUE(ddp)));
465		return; /* was return(1); */
466	}
467
468	/* walk the Query Network list */
469	/* we want to build a response with the network number followed by the zone name
470     * length and the zone name. If there is more than one zone per network asked,
471	 * we repeat the network number and stick the zone length and zone name.
472	 * We need to be carefull with the max DDP size for data. If we see that a new
473     * NetNum, ZoneLen, ZoneName sequence won't fit, we send the previous packet and
474     * begin to build a new one.
475	 */
476
477newPacket:
478
479	if (!(m = prep_ZIP_reply_packet (mreceived, ifID))) {
480	  return; /* was return(ENOBUFS); */
481	}
482
483	ddp = (at_ddp_t *)(gbuf_rptr(m));
484	ReplyBuff = (char *)(ddp->data);
485
486	*ReplyBuff++ = 2;	/* ZIP function = 2 [Non extended reply] */
487	ZonesInPacket = ReplyBuff;
488	*ZonesInPacket = 0;
489	ReplyBuff++;
490	reply_length = 2;	/* 1st byte is ZIP reply code, 2nd is network count */
491
492	for (i = 0 ; i < network_count ; i ++, NetAsked++) {
493	  Entry = rt_blookup(ntohs(*NetAsked));
494
495	  if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
496	      RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */
497
498	    if (Entry->NetStart == 0) { /* asking for a NON EXTENDED network */
499
500	      if ( (Index = zt_ent_zindex(Entry->ZoneBitMap)) == 0)
501		continue;
502
503	      Index--;
504
505	      if (reply_length + 3 + ZT_table[Index].Zone.len  > DDP_DATA_SIZE) {
506
507			/* we need to send the packet before, this won't fit... */
508
509			DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE));
510			gbuf_winc(m,reply_length);
511
512			if ((status =
513			     ddp_router_output(m, ifID, AT_ADDR,
514					       NET_VALUE(ddp->dst_net),
515					       ddp->dst_node, 0))) {
516			  dPrintf(D_M_ZIP, D_L_ERROR,
517				  ("zip_s_reply: ddp_router_output returns =%d\n",
518				   status));
519			  return; /* was return (status); */
520			}
521
522			/* this is not nice, I know, but we reenter the loop with
523			 * a packet is sent with the next network field in the Query
524			 */
525
526			network_count -= i;
527			goto newPacket;
528
529	      }
530
531	      /* this should fit in this packet, build the NetNumber, ZoneLen,
532	       * ZoneName triple
533	       */
534
535	      if (ZT_table[Index].Zone.len) {
536	      		ZonesInPacket += 1; /* bump NetCount field */
537			*ReplyBuff++	= (*NetAsked & 0xFF00) >> 8;
538			*ReplyBuff++ 	= (*NetAsked & 0x00FF) ;
539			*ReplyBuff++ 	= ZT_table[Index].Zone.len;
540			bcopy(&ZT_table[Index].Zone.str, ReplyBuff,
541			      ZT_table[Index].Zone.len);
542
543			ReplyBuff += ZT_table[Index].Zone.len;
544
545			reply_length += ZT_table[Index].Zone.len + 3;
546
547
548	      }
549
550
551	    }
552	    else {	/* extended network, check for multiple zone name attached
553			 * and build a separate packet for each extended network requested
554			 */
555
556	    	zip_send_ext_reply_to_query(mreceived, ifID, Entry, ntohs(*NetAsked));
557
558	    }
559	  }
560	}
561
562	/* If we have a non extended packet (code 2) with some stuff in it,
563	 * we need to send it now
564	 */
565
566	if ( reply_length > 2)  {
567		DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE));
568		gbuf_winc(m,reply_length);
569		if ((status =
570		     ddp_router_output(m, ifID, AT_ADDR,
571				       NET_VALUE(ddp->dst_net),
572				       ddp->dst_node, 0))) {
573			dPrintf(D_M_ZIP, D_L_ERROR,
574			 	("zip_send_reply: ddp_router_output returns =%d\n", status));
575			return; /* was return (status); */
576		}
577	}
578	else  /* free the buffer not used */
579		gbuf_freem(m);
580} /* zip_send_reply_to_query */
581
582/***********************************************************************
583 * zip_router_input()
584 *
585 **********************************************************************/
586
587void zip_router_input (m, ifID)
588     register gbuf_t	*m;
589     register at_ifaddr_t	*ifID;
590{
591	register at_ddp_t	*ddp;
592	register at_atp_t	*atp;
593	register at_zip_t	*zip;
594	u_char	 user_bytes[4];
595	register u_short user_byte;
596
597	/* variables for ZipNotify processing */
598	register char	old_zone_len;
599	register char	new_zone_len;
600	register char	*old_zone;
601	char		*new_zone;
602
603	if (gbuf_type(m) != MSG_DATA) {
604		/* If this is a M_ERROR message, DDP is shutting down,
605		 * nothing to do here...If it's something else, we don't
606		 * understand what it is
607		 */
608	  	dPrintf(D_M_ZIP, D_L_WARNING, ("zip_router_input: not an M_DATA message\n"));
609		gbuf_freem(m);
610		return;
611	}
612
613	if (!ifID) {
614	  	dPrintf(D_M_ZIP, D_L_WARNING, ("zip_router_input: BAD ifID\n"));
615		gbuf_freem(m);
616		return;
617	}
618
619	/*
620	 * The ZIP listener receives two types of requests:
621	 *
622	 * ATP requests: GetZoneList, GetLocalZone, or GetMyZone
623	 * ZIP requests: Netinfo, Query, Reply, takedown, bringup
624	 */
625
626	ddp = (at_ddp_t *)gbuf_rptr(m);
627
628	if (ddp->type == DDP_ZIP) {
629		zip = (at_zip_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
630		dPrintf(D_M_ZIP_LOW, D_L_INPUT,
631			("zip_input: received a ZIP_DDP command=%d\n",
632			 zip->command));
633		switch (zip->command) {
634		    case ZIP_QUERY : /* we received a Zip Query request */
635			dPrintf(D_M_ZIP, D_L_INPUT,
636				("zip_input: Received a Zip Query in from %d.%d\n",
637				 NET_VALUE(ddp->src_net), ddp->src_node));
638
639			if (!RT_LOOKUP_OKAY(ifID, ddp)) {
640				dPrintf(D_M_ZIP, D_L_INPUT,
641					("zip_input:: refused ZIP_QUERY from %d:%d\n",
642					NET_VALUE(ddp->src_net), ddp->src_node));
643			}
644			else
645				zip_send_reply_to_query(m, ifID);
646			gbuf_freem(m);
647			break;
648
649		case ZIP_REPLY : /* we received a Zip Query Reply packet */
650		case ZIP_EXTENDED_REPLY:
651			if (ifID->ifRoutingState == PORT_OFFLINE) {
652				dPrintf(D_M_ZIP, D_L_INPUT,
653					("zip_input: Received a Zip Reply in user mode\n"));
654			}
655			else
656				zip_reply_received(m, ifID, zip->command);
657			gbuf_freem(m);
658			break;
659
660		case ZIP_TAKEDOWN :
661			/* we received a Zip Takedown packet */
662			dPrintf(D_M_ZIP, D_L_WARNING, ("zip_input: Received a Zip takedown!!!\n"));
663			gbuf_freem(m);
664			break;
665
666		case ZIP_BRINGUP :
667			/* we received a Zip BringUp packet */
668			dPrintf(D_M_ZIP, D_L_WARNING, ("zip_input: Received a Zip BringUp!!!\n"));
669			gbuf_freem(m);
670			break;
671
672		case ZIP_GETNETINFO: /* we received a GetNetInfo request */
673			dPrintf(D_M_ZIP, D_L_INPUT,
674				("zip_input: Received a GetNetInfo Req in from %d.%d\n",
675				NET_VALUE(ddp->src_net), ddp->src_node));
676			if (RT_LOOKUP_OKAY(ifID, ddp)) {
677				dPrintf(D_M_ZIP, D_L_OUTPUT,
678					("zip_input: we, as node %d:%d send GNI reply to %d:%d\n",
679					 ifID->ifThisNode.s_net, ifID->ifThisNode.s_node,
680					 NET_VALUE(ddp->src_net), ddp->src_node));
681			      	zip_send_getnetinfo_reply(m, ifID);
682			}
683			gbuf_freem(m);
684			break;
685
686
687		case ZIP_NETINFO_REPLY :
688
689			/* If we are not waiting for a GetNetInfo reply
690			 * to arrive, this must be a broadcast
691			 * message for someone else on the zone, so
692			 * no need to even look at it!
693			 */
694			if (!ROUTING_MODE &&
695			    ((NET_VALUE(ddp->src_net) != ifID->ifThisNode.s_net) ||
696			     (ddp->src_node != ifID->ifThisNode.s_node)) && netinfo_reply_pending)
697			{
698				dPrintf(D_M_ZIP, D_L_INPUT,
699					("zip_input: Received a GetNetInfo Reply from %d.%d\n",
700					NET_VALUE(ddp->src_net), ddp->src_node));
701				trackrouter(ifID, NET_VALUE(ddp->src_net), ddp->src_node);
702				zip_netinfo_reply((at_x_zip_t *)zip, ifID);
703			}
704
705			gbuf_freem(m);
706			break;
707
708		case ZIP_NOTIFY :
709			/* processing of ZipNotify message : first, change
710			 * our zone name, then if NIS is open, let NBP demon
711				  process know of this change...(just forward the
712			 * Notify packet
713			 */
714			/* First, check if this is really a packet for us */
715			old_zone = &zip->data[4];
716			if (!zonename_equal(&ifID->ifZoneName,
717					    (at_nvestr_t *)old_zone)) {
718				/* the old zone name in the packet is not the
719				 * same as ours, so this packet couldn't be
720				 * for us.
721				 */
722				gbuf_freem(m);
723				break;
724
725			}
726			old_zone_len = *old_zone;
727			new_zone_len = zip->data[4 + old_zone_len + 1];
728			new_zone = old_zone + old_zone_len;
729
730			/* Reset the zone multicast address */
731			(void)at_unreg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr);
732			bzero((caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN);
733
734			/* change the zone name - copy both the length and the string */
735			bcopy((caddr_t)new_zone, (caddr_t)&ifID->ifZoneName,
736			      new_zone_len+1);
737
738			/* Send network zone change event and new zone for this interface. */
739			atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName));
740			atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONELISTCHANGED, 0, 0);
741
742			/* add the new zone to the list of local zones */
743			if (!MULTIPORT_MODE && !DEFAULT_ZONE(&ifID->ifZoneName))
744				(void)setLocalZones(&ifID->ifZoneName,
745						    (ifID->ifZoneName.len+1));
746
747			/* Before trying to request our new multicast address,
748			 * wait a while... someone might have alredy requested
749			 * it, so we may see some broadcast messages flying
750			 * by...  Set up the structures so that it appears that
751			 * we have already requested the NetInfo.
752			 */
753			ifID->ifNumRetries = ZIP_NETINFO_RETRIES;
754			netinfo_reply_pending = 1;
755			ifID->ifGNIScheduled = 1;
756			timeout(zip_sched_getnetinfo, (caddr_t) ifID,
757				 2*ZIP_TIMER_INT);
758
759			gbuf_freem(m);
760			break;
761		default :
762			routing_needed(m, ifID, TRUE);
763			break;
764		}
765	}
766	else if (ddp->type == DDP_ATP &&
767		 RT_LOOKUP_OKAY(ifID, ddp)) {
768		if (gbuf_len(m) > DDP_X_HDR_SIZE)
769			atp = (at_atp_t *)(gbuf_rptr(m)+DDP_X_HDR_SIZE);
770		else
771			atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
772
773		/* Get the user bytes in network order */
774
775		*((u_long*)user_bytes) = UAL_VALUE(atp->user_bytes);
776		user_byte = user_bytes[0]; /* Get the zeroth byte */
777
778		dPrintf(D_M_ZIP, D_L_INPUT,
779			("zip_input: received a ZIP_ATP command=%d\n", user_byte));
780
781		switch (user_byte) {
782			case ZIP_GETMYZONE:
783				zip_reply_to_getmyzone(ifID, m);
784				gbuf_freem(m);
785				break;
786
787			case ZIP_GETZONELIST:
788				zip_reply_to_getzonelist(ifID, m);
789				gbuf_freem(m);
790				break;
791
792			case ZIP_GETLOCALZONES:
793				zip_reply_to_getlocalzones(ifID, m);
794				gbuf_freem(m);
795				break;
796
797			default:
798				dPrintf(D_M_ZIP, D_L_WARNING,
799					("zip_input: received unknown ZIP_ATP command=%d\n", user_byte));
800				routing_needed(m, ifID, TRUE);
801				break;
802		}
803	} else {
804		gbuf_freem(m);
805	}
806	return;
807} /* zip_router_input */
808
809/***********************************************************************
810 * zonename_equal()
811 *
812 * Remarks :
813 *
814 **********************************************************************/
815int zonename_equal (zone1, zone2)
816     register at_nvestr_t	*zone1, *zone2;
817{
818	register char c1, c2;
819	register int	i;
820
821	if (zone1->len != zone2->len)
822		return(0);
823
824	for (i=0; i< (int) zone1->len; i++) {
825		c1 = zone1->str[i];
826		c2 = zone2->str[i];
827		if (c1 >= 'a' && c1 <= 'z')
828			c1 += 'A' - 'a';
829		if (c2 >= 'a' && c2 <= 'z')
830			c2 += 'A' - 'a';
831		if (c1 & 0x80)
832			c1 = upshift8(c1);
833		if (c2 & 0x80)
834			c2 = upshift8(c2);
835		if (c1 != c2)
836			return(0);
837	}
838	return(1);
839}
840
841
842char	upshift8 (ch)
843     register char	ch;
844{
845	register int	i;
846
847	static	unsigned char	lower_case[] =
848		{0x8a, 0x8c, 0x8d, 0x8e, 0x96, 0x9a, 0x9f, 0xbe,
849		 0xbf, 0xcf, 0x9b, 0x8b, 0x88, 0};
850	static	unsigned char	upper_case[] =
851		{0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xae,
852		 0xaf, 0xce, 0xcd, 0xcc, 0xcb, 0};
853
854	for (i=0; lower_case[i]; i++)
855		if (ch == lower_case[i])
856			return (upper_case[i]);
857
858	return(ch);
859}
860
861
862/***********************************************************************
863 * zip_netinfo_reply ()
864 *
865 * Remarks :
866 *
867 **********************************************************************/
868static void zip_netinfo_reply (netinfo, ifID)
869     register at_x_zip_t	*netinfo;
870     register at_ifaddr_t	*ifID;
871{
872	u_char	mcast_len;
873	register at_net_al	this_net;
874	char	*default_zone;
875	register u_char	zone_name_len;
876
877	/* There may be multiple zones on the cable.... we need to
878	 * worry about whether or not this packet is addressed
879	 * to us.
880	 */
881	/* *** Do we really need to check this? *** */
882	if (!zonename_equal((at_nvestr_t *)netinfo->data, &ifID->ifZoneName)) {
883		dPrintf(D_M_ZIP, D_L_INFO, ("zip_netinfo_reply, !zonename_equal!!!"));
884		return;
885	}
886
887	ifID->ifThisCableStart = NET_VALUE(netinfo->cable_range_start);
888	ifID->ifThisCableEnd = NET_VALUE(netinfo->cable_range_end);
889	dPrintf(D_M_ZIP, D_L_OUTPUT, ("Zip_netinfo_reply: Set cable to %d-%d\n",
890		 ifID->ifThisCableStart, ifID->ifThisCableEnd));
891
892	/* The packet is in response to our request */
893	ifID->ifGNIScheduled = 0;
894	untimeout (zip_sched_getnetinfo, (caddr_t) ifID);
895	netinfo_reply_pending = 0;
896	zone_name_len = netinfo->data[0];
897	mcast_len = netinfo->data[zone_name_len + 1];
898
899	if (netinfo->flags & ZIP_ZONENAME_INVALID) {
900		/* copy out the default zone name from packet */
901		default_zone = (char *)&netinfo->data[zone_name_len+1+mcast_len+1];
902		bcopy((caddr_t)default_zone, (caddr_t)&ifID->ifZoneName,
903		      *default_zone + 1);
904	}
905
906	/* add the new zone to the list of local zones */
907	if (!MULTIPORT_MODE && !DEFAULT_ZONE(&ifID->ifZoneName))
908		(void)setLocalZones(&ifID->ifZoneName, (ifID->ifZoneName.len+1));
909
910	/* get the multicast address out of the GetNetInfo reply, if there is one */
911	if (!(netinfo->flags & ZIP_USE_BROADCAST)) {
912		/* If ZIP_USE_BROADCAST is set, we will use the cable
913		   broadcast address as the multicast address, however
914		   the cable multicast address has already been registered.
915		 */
916		/* This packet contains a multicast address, so
917		 * send to elap to register it.
918		 */
919	  	if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
920			ddp_bit_reverse(&netinfo->data[zone_name_len + 2]);
921
922		bcopy((caddr_t)&netinfo->data[zone_name_len + 2],
923		      (caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN);
924		(void)at_reg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr);
925	}
926
927	this_net = ifID->ifThisNode.s_net;
928	if ((this_net >= ifID->ifThisCableStart) &&
929	    (this_net <= ifID->ifThisCableEnd)) {
930		/* ThisNet is in the range of valid network numbers
931		 * for the cable. Do nothing.
932		 */
933	} else {
934		/* ThisNet is not in the range of valid network
935		 * numbers for the cable. This may be either because
936		 * the chosen number was from start-up range, or
937		 * because the user has a misconception of where the
938		 * machine is!!  Since ThisCableRange is set up, next
939		 * time aarp is invoked, it would select address in
940		 * the right range.
941		 */
942
943		/* to reset initial_net and initial_node to zero, so
944		 * that aarp is forced to choose new values
945		 */
946		ifID->initial_addr.s_net = 0;
947		ifID->initial_addr.s_node = 0;
948
949		/* Wake up elap_online sleeping on this interface. */
950		ZIPwakeup(ifID, ZIP_RE_AARP);
951		return;
952	}
953
954	if (!ifID->startup_inprogress) {
955		/* Send event with zone info. This covers case where we get zone info
956			after startup. During startup this event is sent from ZIPwakeup. */
957		atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName));
958	}
959
960	ZIPwakeup(ifID, 0); /* no error */
961	return;
962} /* zip_netinfo_reply */
963
964
965/**********************************************************************
966 * zip_control()
967 *
968 **********************************************************************/
969int zip_control (ifID, control)
970     register at_ifaddr_t	*ifID;
971     int	control;
972{
973	dPrintf(D_M_ZIP, D_L_INFO, ("zip_control called port=%d control=%d\n",
974			 ifID->ifPort, control));
975	switch (control) {
976	case ZIP_ONLINE :
977	case ZIP_LATE_ROUTER :
978		if (!ifID->ifGNIScheduled) {
979			ifID->ifNumRetries = 0;
980			/* Get the desired zone name from elap and put it in
981		 	* ifID for zip_getnetinfo() to use.
982		 	*/
983			if (ifID->startup_zone.len)
984				ifID->ifZoneName = ifID->startup_zone;
985			zip_getnetinfo(ifID);
986		}
987		break;
988	case ZIP_NO_ROUTER :
989		ifID->ifZoneName.len = 1;
990		ifID->ifZoneName.str[0] = '*';
991		ifID->ifZoneName.str[1] = '\0';
992
993		/* Send event with zone info. */
994		atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName));
995
996		break;
997	default :
998		break;
999	}
1000	return (0);
1001}
1002
1003/* locked version of zip_getnetinfo */
1004static void
1005zip_getnetinfo_locked(void *arg)
1006{
1007	at_ifaddr_t       *ifID;
1008
1009	atalk_lock();
1010	if (arg != NULL) {		// make sure it hasn't been closed
1011		ifID = (at_ifaddr_t *)arg;
1012		ifID->ifGNIScheduled = 0;
1013		zip_getnetinfo(ifID);
1014	}
1015	atalk_unlock();
1016}
1017
1018
1019/**********************************************************************
1020 * zip_getnetinfo()
1021 *
1022 **********************************************************************/
1023static void zip_getnetinfo (ifID)
1024     register at_ifaddr_t       *ifID;
1025{
1026	register at_x_zip_t	*zip;
1027	gbuf_t			*m;
1028	register at_ddp_t	*ddp;
1029	register struct	atalk_addr	*at_dest;
1030	register int		size;
1031
1032
1033	size =  DDP_X_HDR_SIZE + ZIP_X_HDR_SIZE + ifID->ifZoneName.len + 1
1034		+ sizeof(struct atalk_addr) + 1;
1035	if ((m = gbuf_alloc (AT_WR_OFFSET+size, PRI_HI)) == NULL) {
1036		/* This time, we're unable to allocate buffer to
1037		 * send a packet out, so schedule to send a packet
1038		 * out later, and exit.
1039		 */
1040		dPrintf(D_M_ZIP, D_L_WARNING, ("zip_getnetinfo: no buffer, call later port=%d\n",
1041			ifID->ifPort));
1042		ifID->ifGNIScheduled = 1;
1043		timeout (zip_getnetinfo_locked, (caddr_t) ifID, ZIP_TIMER_INT/10);
1044		return;
1045	}
1046
1047	gbuf_rinc(m,AT_WR_OFFSET);
1048	gbuf_wset(m,0);
1049	*(u_char *)gbuf_rptr(m) = AT_ADDR;
1050	at_dest = (struct atalk_addr *)(gbuf_rptr(m) + 1);
1051	ddp = (at_ddp_t *)(gbuf_rptr(m) + sizeof(struct atalk_addr) + 1);
1052	zip = (at_x_zip_t *)ddp->data;
1053	gbuf_winc(m,size);
1054
1055	zip->command = ZIP_GETNETINFO;
1056	zip->flags = 0;
1057	NET_ASSIGN(zip->cable_range_start, 0);
1058	NET_ASSIGN(zip->cable_range_end, 0);
1059	if (ifID->ifZoneName.len)	/* has to match reply exactly */
1060		bcopy((caddr_t)&ifID->ifZoneName, (caddr_t)zip->data,
1061		      ifID->ifZoneName.len + 1);
1062	else
1063		zip->data[0] = 0; /* No zone name is availbale */
1064
1065	/* let the lap fields be uninitialized, 'cause it doesn't
1066	 * matter.
1067	 */
1068	DDPLEN_ASSIGN(ddp, (size - (sizeof(struct atalk_addr) + 1)));
1069	UAS_ASSIGN(ddp->checksum, 0);
1070	ddp->hopcount = ddp->unused = 0;
1071	NET_ASSIGN(ddp->dst_net, 0); /* cable-wide broadcast */
1072	NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
1073		/* By this time, AARP is done */
1074
1075	ddp->dst_node = 0xff;
1076	ddp->src_node = ifID->ifThisNode.s_node;
1077	ddp->dst_socket = ZIP_SOCKET;
1078	ddp->src_socket = ZIP_SOCKET;
1079	ddp->type = DDP_ZIP;
1080
1081	at_dest->atalk_unused = 0;
1082	NET_NET(at_dest->atalk_net, ddp->dst_net);
1083	at_dest->atalk_node = ddp->dst_node;
1084
1085	dPrintf(D_M_ZIP, D_L_INPUT, ("zip_getnetinfo: called for port=%d\n",
1086		 ifID->ifPort));
1087
1088	if (elap_dataput(m, ifID, 0, NULL)) {
1089	 dPrintf(D_M_ZIP, D_L_ERROR,
1090		 ("zip_getnetinfo: error sending zip_getnetinfo\n"));
1091		return;
1092	}
1093
1094	ifID->ifNumRetries++;
1095	netinfo_reply_pending = 1;
1096	ifID->ifGNIScheduled = 1;
1097	timeout (zip_sched_getnetinfo, (caddr_t) ifID, ZIP_TIMER_INT);
1098} /* zip_getnetinfo */
1099
1100
1101/**********************************************************************
1102 * zip_sched_getnetinfo()
1103 *
1104 **********************************************************************/
1105
1106void	zip_sched_getnetinfo(void *arg)
1107{
1108     register at_ifaddr_t *ifID = (at_ifaddr_t *)arg;
1109
1110	atalk_lock();
1111
1112	ifID->ifGNIScheduled = 0;
1113
1114	if (ifID->ifNumRetries >= ZIP_NETINFO_RETRIES) {
1115		/* enough packets sent.... give up! */
1116		/* we didn't get any response from the net, so
1117		 * assume there's no router around and the given
1118		 * zone name, if any, is not valid.  Change the
1119		 * zone name to "*".
1120		 */
1121		ifID->ifZoneName.len = 1;
1122		ifID->ifZoneName.str[0] = '*';
1123		ifID->ifZoneName.str[1] = '\0';
1124		/* Should NBP be notified of this "new" zone name?? */
1125		netinfo_reply_pending = 0;
1126
1127		ifID->ifRouterState = NO_ROUTER;
1128		ifID->ifARouter.s_net = 0;
1129		ifID->ifARouter.s_node = 0;
1130
1131		dPrintf(D_M_ZIP, D_L_INFO, ("zip_sched_getnetinfo: Reset Cable Range\n"));
1132
1133		ifID->ifThisCableStart = DDP_MIN_NETWORK;
1134		ifID->ifThisCableEnd = DDP_MAX_NETWORK;
1135
1136		if (ifID->ifState == LAP_ONLINE_FOR_ZIP)
1137			ZIPwakeup (ifID, 0); /* no error */
1138	} else
1139		zip_getnetinfo(ifID);
1140
1141	atalk_unlock();
1142}
1143
1144
1145/**********************************************************************
1146 * zip_type_packet()
1147 *
1148 * Remarks:
1149 *	This routine checks whether or not the packet contained in "m"
1150 *	is an (outgoing) ZIP packet.  If not, it returns 0.  If it is a
1151 *	ZIP packet, it returns the ZIP packet type (ZIP command). "m"
1152 *	points to a packet with extended DDP header.  The rest of the
1153 *	DDP data may or may not be in the first gbuf.
1154 *
1155 **********************************************************************/
1156int zip_type_packet (m)
1157     register gbuf_t	*m;
1158{
1159	register at_atp_t	*atp;
1160	register at_ddp_t	*ddp;
1161	register at_zip_t	*zip;
1162	u_char	user_bytes[4];
1163	register int	user_byte;
1164
1165	ddp = (at_ddp_t *)gbuf_rptr(m);
1166	if (ddp->dst_socket == ZIP_SOCKET) {
1167		switch (ddp->type) {
1168		case DDP_ZIP :
1169			if (gbuf_len(m) > DDP_X_HDR_SIZE)
1170				zip = (at_zip_t *)(gbuf_rptr(m)
1171					+ DDP_X_HDR_SIZE);
1172			else
1173				zip=(at_zip_t *)(gbuf_rptr(gbuf_cont(m)));
1174			return ((int)zip->command);
1175		case DDP_ATP :
1176			if (gbuf_len(m) > DDP_X_HDR_SIZE)
1177				atp = (at_atp_t *)(gbuf_rptr(m)+DDP_X_HDR_SIZE);
1178			else
1179				atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1180			/* Get the user bytes in network order */
1181			*((u_long*)user_bytes) = UAL_VALUE(atp->user_bytes);
1182			user_byte = user_bytes[0]; /* Get the zeroth byte */
1183			if ((user_byte == ZIP_GETMYZONE) ||
1184			    (user_byte == ZIP_GETZONELIST) ||
1185			    (user_byte == ZIP_GETLOCALZONES))
1186				return (user_byte);
1187			else
1188				return (0);
1189		default :
1190			return (0);
1191		}
1192	} else
1193		return (0);
1194}
1195
1196/**********************************************************************
1197 * zip_handle_getmyzone()
1198 *
1199 * Remarks:
1200 *	Routine to handle ZIP GetMyZone request locally.  It generates
1201 *	a phony response to the outgoing ATP request and sends it up.
1202 *
1203 * 07/12/94 : remark2 only called from ddp.c / ddp_output
1204 *            should only be called from the home port, but
1205 *		      when we are a router we should know the infos for all
1206 *			  anyway, so reply locally with what we have in stock...
1207 *
1208 **********************************************************************/
1209
1210int zip_handle_getmyzone(ifID, m)
1211     register at_ifaddr_t   *ifID;
1212     register gbuf_t      *m;
1213{
1214        at_atp_t            *atp;
1215        register at_ddp_t   *ddp;
1216        register at_ddp_t *r_ddp;
1217        register at_atp_t *r_atp;
1218        gbuf_t          *rm; /* reply message */
1219        register int    size;
1220        u_long  ulongtmp;
1221
1222	dPrintf(D_M_ZIP, D_L_INFO,
1223		("zip_handle_getmyzone: local reply for port=%d\n",
1224		 ifID->ifPort));
1225
1226        size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + 1 + ifID->ifZoneName.len;
1227        /* space for two headers and the zone name */
1228        if ((rm = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) {
1229		dPrintf(D_M_ZIP, D_L_WARNING,
1230			("zip_handle_getmyzone: no buffer, port=%d\n",
1231			 ifID->ifPort));
1232		return (ENOBUFS);
1233	}
1234
1235        gbuf_rinc(rm,AT_WR_OFFSET);
1236        gbuf_wset(rm,0);
1237        r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1238        r_atp = (at_atp_t *)r_ddp->data;
1239        gbuf_winc(rm,size);
1240
1241        ddp = (at_ddp_t *)gbuf_rptr(m);
1242        if (gbuf_len(m) > DDP_X_HDR_SIZE)
1243                atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1244        else
1245                atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1246
1247        /* fill up the ddp header for reply */
1248        DDPLEN_ASSIGN(r_ddp, size);
1249        r_ddp->hopcount = r_ddp->unused = 0;
1250        UAS_ASSIGN(r_ddp->checksum, 0);
1251        NET_ASSIGN(r_ddp->dst_net, ifID->ifThisNode.s_net);
1252        NET_NET(r_ddp->src_net, ddp->dst_net);
1253        r_ddp->dst_node = ifID->ifThisNode.s_node;
1254        r_ddp->src_node = ddp->dst_node;
1255        r_ddp->dst_socket = ddp->src_socket;
1256        r_ddp->src_socket = ZIP_SOCKET;
1257        r_ddp->type = DDP_ATP;
1258
1259        /* fill up the atp header */
1260        r_atp->cmd = ATP_CMD_TRESP;
1261        r_atp->xo = 0;
1262        r_atp->eom = 1;
1263        r_atp->sts = 0;
1264        r_atp->xo_relt = 0;
1265        r_atp->bitmap = 0;
1266        UAS_UAS(r_atp->tid, atp->tid);
1267        ulongtmp = 1;
1268		UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); /* no of zones */
1269
1270        /* fill up atp data part */
1271        bcopy((caddr_t) &ifID->ifZoneName, (caddr_t) r_atp->data, ifID->ifZoneName.len+1);
1272
1273        /* all set to send the packet back up */
1274
1275        timeout(send_phony_reply, (caddr_t) rm, HZ/20);
1276        return (0);
1277}
1278
1279static	void
1280send_phony_reply(arg)
1281	void	*arg;
1282{
1283	gbuf_t  *rm = (gbuf_t *)arg;
1284
1285	atalk_lock();
1286	ddp_input(rm, ifID_home);
1287	atalk_unlock();
1288
1289	return;
1290}
1291
1292
1293/*
1294 * zip_prep_query_packet:  build the actual ddp packet for the zip query
1295 */
1296
1297gbuf_t *zip_prep_query_packet(ifID, RouterNet, RouterNode)
1298     at_ifaddr_t *ifID;
1299     at_net_al	RouterNet; /* we want to send the Zip Query to that router */
1300     at_node	RouterNode;
1301{
1302
1303	register gbuf_t *m;
1304	register at_ddp_t	*ddp;
1305
1306	if ((m = gbuf_alloc (AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
1307		dPrintf(D_M_ZIP, D_L_WARNING,
1308			("zip_send_query_packet: no buffer, port=%d\n",
1309			 ifID->ifPort));
1310		return((gbuf_t *)NULL);
1311	}
1312	gbuf_rinc(m,AT_WR_OFFSET);
1313	gbuf_wset(m,0);
1314
1315	ddp = (at_ddp_t *)(gbuf_rptr(m));
1316
1317	/* Prepare the DDP header */
1318
1319	ddp->unused = ddp->hopcount = 0;
1320	UAS_ASSIGN(ddp->checksum, 0);
1321	NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
1322	ddp->src_node = ifID->ifThisNode.s_node;
1323	ddp->src_socket = ZIP_SOCKET;
1324
1325	ddp->dst_socket = ZIP_SOCKET;
1326	NET_ASSIGN(ddp->dst_net, RouterNet);
1327	ddp->dst_node = RouterNode;
1328
1329	ddp->type = DDP_ZIP;
1330
1331	return (m);
1332} /* zip_prep_query_packet */
1333
1334
1335/*
1336 * zip_send_queries: this function send queries for the routing table entries that
1337 *     need to know their zones. It scans the routing table for entries with unknown
1338 *     zones and build Query packets accordingly.
1339 *     Note: this is called on a per port basis.
1340 */
1341
1342void zip_send_queries(ifID, RouterNet, RouterNode)
1343     register at_ifaddr_t	*ifID;
1344     at_net_al	RouterNet;		/* we want to send the Zip Query to that router */
1345     at_node		RouterNode;
1346{
1347	RT_entry *Entry = &RT_table[0];
1348	register gbuf_t *m;
1349	register at_ddp_t	*ddp;
1350	int status;
1351	short Query_index, EntryNumber = 0 ;
1352	register u_char port = ifID->ifPort;
1353	char *QueryBuff, *ZoneCount;
1354	short zip_sent = FALSE;
1355
1356newPacket:
1357
1358	if (!(m = zip_prep_query_packet(ifID, RouterNet, RouterNode))) {
1359		return; /* was return (ENOBUFS); */
1360	}
1361
1362	ddp = (at_ddp_t *)(gbuf_rptr(m));
1363	QueryBuff = (char *)ddp->data;
1364
1365	*QueryBuff++ = ZIP_QUERY;
1366	ZoneCount = QueryBuff;	/* network count */
1367	*ZoneCount = 0;
1368	QueryBuff++;
1369	Query_index = 2;
1370
1371
1372	while (EntryNumber < RT_maxentry) {
1373
1374		/* scan the table, and build the packet with the right entries:
1375		 *  - entry in use and on the right Port
1376		 *  - with unknwon zones and in an active state
1377		 *	- talking to the right router
1378		 */
1379
1380		if ((Query_index) > 2*254 +2) {
1381
1382			/* we need to send the packet now, but we can't have more than 256
1383			 * requests for networks: the Netcount field is a 8bit in the zip query
1384			 * packet format as defined in Inside Atalk
1385			 */
1386
1387			dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1388				("zip_send_query: FULL query for %d nets on port#%d.(len=%d)\n",
1389				 *ZoneCount, port, Query_index));
1390			zip_sent = TRUE;
1391
1392			gbuf_winc(m,DDP_X_HDR_SIZE + Query_index);
1393			DDPLEN_ASSIGN(ddp, (DDP_X_HDR_SIZE + Query_index));
1394
1395			if ((status =
1396			     ddp_router_output(m, ifID, AT_ADDR,
1397					       RouterNet, RouterNode, 0))) {
1398				dPrintf(D_M_ZIP, D_L_ERROR,
1399					("zip_send_query: ddp_router_output returns =%d\n", status));
1400				return; /* was return (status); */
1401			}
1402
1403			goto newPacket;
1404		}
1405
1406
1407		if (((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
1408			(Entry->NetStop) && (Entry->NetPort == port) &&
1409			(!RT_ALL_ZONES_KNOWN(Entry))){
1410
1411			/* we're ready to had that to our list of stuff to send */
1412
1413			if (Entry->NetStart) { /* extended net*/
1414
1415				*QueryBuff++ = (Entry->NetStart & 0xFF00) >> 8;
1416				*QueryBuff++ = (Entry->NetStart & 0x00FF);
1417
1418			}
1419			else {
1420				*QueryBuff++ = (Entry->NetStop & 0xFF00) >> 8;
1421				*QueryBuff++ = (Entry->NetStop & 0x00FF);
1422			}
1423
1424			Query_index += 2;
1425			*ZoneCount += 1;/* bump the number of network requested */
1426
1427		}
1428
1429		Entry++;
1430		EntryNumber++;
1431
1432	}
1433
1434	dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1435	 ("zip_send_query: query for %d nets on port#%d.(len=%d)\n",
1436	 *ZoneCount, port, Query_index));
1437
1438	if (*ZoneCount) { 	/* non-full Query needs to be sent */
1439		zip_sent = TRUE;
1440		gbuf_winc(m,DDP_X_HDR_SIZE + Query_index);
1441		DDPLEN_ASSIGN(ddp, (DDP_X_HDR_SIZE + Query_index));
1442
1443		if ((status =
1444		     ddp_router_output(m, ifID, AT_ADDR,
1445				       RouterNet, RouterNode, 0))) {
1446			dPrintf(D_M_ZIP, D_L_ERROR,
1447				("zip_send_query: ddp_router_output returns =%d\n",
1448				 status));
1449			return; /* was return (status); */
1450		}
1451	}
1452	else
1453		gbuf_freem(m);
1454
1455	if (!zip_sent) /* we didn't need to send anything for that port */
1456		ifID->ifZipNeedQueries = 0;
1457} /* zip_send_queries */
1458
1459/* zip_reply_received: we recieved the reply to one of our query, update the
1460 *                     zone bitmap and stuffs with was we received.
1461 *		we receive two types of replies: non extended and extended.
1462 *	    For extended replies, the network count is the Total of zones for that net.
1463 */
1464int
1465zip_reply_received(m, ifID, reply_type)
1466     register gbuf_t	*m;
1467     register at_ifaddr_t	*ifID;
1468     int	reply_type;
1469{
1470	register at_nvestr_t	*zname;
1471	RT_entry *Entry = &RT_table[0];
1472	register at_ddp_t	*ddp;
1473	at_net_al Network;
1474	u_short payload_len, result;
1475	u_char network_count;
1476	char *PacketPtr;
1477
1478	ddp = (at_ddp_t *)gbuf_rptr(m);
1479
1480	/* access the number of nets provided in the ZIP Reply */
1481
1482	network_count  = ntohs(*(u_char *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 1));
1483
1484	PacketPtr = (char *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 2);
1485
1486	payload_len = DDPLEN_VALUE(ddp) - (DDP_X_HDR_SIZE + 2);
1487
1488	dPrintf(D_M_ZIP_LOW, D_L_INPUT, ("zip_reply_received from %d:%d type=%d netcount=%d\n",
1489			NET_VALUE(ddp->src_net), ddp->src_node, reply_type, network_count));
1490
1491
1492	while (payload_len > 0 && network_count >0) {
1493
1494		Network = ntohs(*(at_net_al *)PacketPtr);
1495		PacketPtr += 2;
1496		zname = (at_nvestr_t *)PacketPtr;
1497		if (payload_len)
1498			payload_len = payload_len -(zname->len + 3);
1499
1500		if (zname->len <= 0) { /* not valid, we got a problem here... */
1501			dPrintf(D_M_ZIP, D_L_WARNING,
1502			 ("zip_reply_received: Problem zlen=0 for net=%d from %d:%d type=%d netcnt=%d\n",
1503			 Network, NET_VALUE(ddp->src_net), ddp->src_node, reply_type, network_count));
1504			payload_len =0;
1505			continue;
1506		}
1507
1508
1509		Entry = rt_blookup(Network);
1510
1511		if (Entry != NULL) {
1512
1513			if (Entry->EntryState >= RTE_STATE_SUSPECT)  {
1514
1515				result = zt_add_zonename(zname);
1516
1517				if (result == ZT_MAXEDOUT) {
1518
1519					dPrintf(D_M_ZIP, D_L_ERROR,
1520						("zip_reply_received: ZTable full from %d:%d on zone '%s'\n",
1521						 NET_VALUE(ddp->src_net), ddp->src_node, zname->str));
1522					ErrorZIPoverflow = 1;
1523					return(1);
1524				}
1525
1526				zt_set_zmap(result, Entry->ZoneBitMap);
1527
1528				RT_SET_ZONE_KNOWN(Entry);
1529
1530			}
1531			else {
1532				dPrintf(D_M_ZIP, D_L_INPUT,
1533					("zip_reply_received: entry %d-%d not updated, cause state=%d\n",
1534					 Entry->NetStart, Entry->NetStop, Entry->EntryState));
1535			}
1536		}
1537		else {
1538			dPrintf(D_M_ZIP, D_L_WARNING,
1539				("zip_reply_received: network %d not found in RT\n", Network));
1540		}
1541
1542
1543		/* now bump the PacketPtr pointer */
1544		PacketPtr += zname->len + 1;
1545		network_count--;
1546	}
1547
1548	if ((reply_type == ZIP_REPLY) && network_count > 0) {
1549#if DEBUG
1550		if (Entry)
1551			dPrintf(D_M_ZIP, D_L_WARNING,
1552			("zip_reply_received: Problem decoding zone (after net:%d-%d)\n",
1553			Entry->NetStart, Entry->NetStop));
1554#endif
1555		ifID->ifZipNeedQueries = 1;
1556	}
1557	else {
1558		ifID->ifZipNeedQueries = 0;
1559#if DEBUG
1560		if (Entry)
1561			dPrintf(D_M_ZIP_LOW, D_L_INFO,
1562			("zip_reply_received: entry %d-%d all zones known\n",
1563			Entry->NetStart, Entry->NetStop));
1564#endif
1565	}
1566
1567	return 0;
1568}
1569
1570/*
1571 * zip_reply_to_getmyzone: replies to ZIP GetMyZone received from the Net
1572 */
1573
1574static void zip_reply_to_getmyzone (ifID, m)
1575     register at_ifaddr_t   *ifID;
1576     register gbuf_t      *m;
1577{
1578        at_atp_t            *atp;
1579        register at_ddp_t   *ddp;
1580        register at_ddp_t *r_ddp;
1581        register at_atp_t *r_atp;
1582        register gbuf_t          *rm; /* reply message */
1583        register int    size, Index, status;
1584		char *data_ptr;
1585		RT_entry *Entry;
1586        u_long  ulongtmp;
1587
1588        size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + 1 + ifID->ifZoneName.len;
1589        /* space for two headers and the zone name */
1590        if ((rm = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) {
1591		dPrintf(D_M_ZIP, D_L_WARNING,
1592			("zip_reply_to_getmyzone: no buffer, port=%d\n", ifID->ifPort));
1593                return; /* was return (ENOBUFS); */
1594		}
1595        gbuf_rinc(rm,AT_WR_OFFSET);
1596        gbuf_wset(rm,size);
1597        r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1598        r_atp = (at_atp_t *)r_ddp->data;
1599
1600        ddp = (at_ddp_t *)gbuf_rptr(m);
1601        if (gbuf_len(m) > DDP_X_HDR_SIZE)
1602                atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1603        else
1604                atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1605
1606        /* fill up the ddp header for reply */
1607        DDPLEN_ASSIGN(r_ddp, size);
1608        r_ddp->hopcount = r_ddp->unused = 0;
1609        UAS_ASSIGN(r_ddp->checksum, 0);
1610
1611        NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net);
1612        NET_NET(r_ddp->dst_net, ddp->src_net);
1613
1614        r_ddp->src_node = ifID->ifThisNode.s_node;
1615        r_ddp->dst_node = ddp->src_node;
1616
1617        r_ddp->dst_socket = ddp->src_socket;
1618        r_ddp->src_socket = ZIP_SOCKET;
1619        r_ddp->type = DDP_ATP;
1620
1621        /* fill up the atp header */
1622        r_atp->cmd = ATP_CMD_TRESP;
1623        r_atp->xo = 0;
1624        r_atp->eom = 1;
1625        r_atp->sts = 0;
1626        r_atp->xo_relt = 0;
1627        r_atp->bitmap = 0;
1628        UAS_UAS(r_atp->tid, atp->tid);
1629        ulongtmp = 1;
1630		UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); /* no of zones */
1631
1632	data_ptr = (char *)r_atp->data;
1633
1634        /*
1635	 * fill up atp data part  with the zone name if we can find it...
1636         */
1637
1638	Entry = rt_blookup(NET_VALUE(ddp->src_net));
1639	if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
1640	    RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */
1641
1642		Index = zt_ent_zindex(Entry->ZoneBitMap) -1;
1643
1644		*data_ptr = ZT_table[Index].Zone.len;
1645		bcopy((caddr_t) &ZT_table[Index].Zone.str, (caddr_t) ++data_ptr,
1646		      ZT_table[Index].Zone.len);
1647
1648		/* all set to send the packet back up */
1649		dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1650			("zip_reply_to_GMZ: ddp_router_output to %d:%d port %d\n",
1651			 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort));
1652
1653		if ((status =
1654		     ddp_router_output(rm, ifID, AT_ADDR,
1655				       NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) {
1656		  dPrintf(D_M_ZIP, D_L_ERROR,
1657			  ("zip_reply_to_GMZ: ddp_r_output returns =%d\n", status));
1658		  return; /* was return (status); */
1659		}
1660	}
1661	else
1662		gbuf_freem(rm);
1663}
1664
1665/*
1666 * zip_reply_to_getzonelist: replies to ZIP GetZoneList requested from the Net
1667 */
1668
1669int
1670zip_reply_to_getzonelist (ifID, m)
1671     register at_ifaddr_t   *ifID;
1672     register gbuf_t      *m;
1673{
1674        at_atp_t            *atp;
1675        register at_ddp_t   *ddp;
1676        register at_ddp_t *r_ddp;
1677        register at_atp_t *r_atp;
1678        register gbuf_t          *rm; /* reply message */
1679        register int    size, status;
1680		register short	Index=0, StartPoint, ZLength, PacketLen=0;
1681        u_long  ulongtmp= 0;
1682		char *Reply;
1683
1684        ddp = (at_ddp_t *)gbuf_rptr(m);
1685        if (gbuf_len(m) > DDP_X_HDR_SIZE)
1686                atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1687        else
1688                atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1689
1690
1691        /* space for two headers and the zone name */
1692
1693        if ((rm = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
1694                return (ENOBUFS);
1695		}
1696
1697        gbuf_rinc(rm,AT_WR_OFFSET);
1698        gbuf_wset(rm,0);
1699        r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1700        r_atp = (at_atp_t *)r_ddp->data;
1701
1702        /* fill up the ddp header for reply */
1703
1704        r_ddp->hopcount = r_ddp->unused = 0;
1705        UAS_ASSIGN(r_ddp->checksum, 0);
1706        NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net);
1707        NET_NET(r_ddp->dst_net, ddp->src_net);
1708        r_ddp->src_node = ifID->ifThisNode.s_node;
1709        r_ddp->dst_node = ddp->src_node;
1710        r_ddp->dst_socket = ddp->src_socket;
1711        r_ddp->src_socket = ZIP_SOCKET;
1712        r_ddp->type = DDP_ATP;
1713
1714        /* fill up the atp header */
1715
1716        r_atp->cmd = ATP_CMD_TRESP;
1717        r_atp->xo = 0;
1718        r_atp->eom = 1;
1719        r_atp->sts = 0;
1720        r_atp->xo_relt = 0;
1721        r_atp->bitmap = 0;
1722        UAS_UAS(r_atp->tid, atp->tid);
1723
1724		Reply = (char *)r_atp->data;
1725
1726			/* get the start index from the ATP request */
1727
1728		StartPoint = (UAL_VALUE_NTOH(atp->user_bytes) & 0xffff) -1;
1729
1730		/* find the next zone to send */
1731
1732		while ((Index < ZT_maxentry) && StartPoint > 0) {
1733			if (ZT_table[Index].Zone.len)
1734				StartPoint--;
1735			Index++;
1736		}
1737
1738
1739		dPrintf(D_M_ZIP_LOW, D_L_OUTPUT, ("zip_reply_to_GZL: Index=%d\n", Index));
1740        /*
1741		 * fill up atp data part  with the zone name if we can find it...
1742         */
1743
1744		while (Index < ZT_maxentry) {
1745
1746			ZLength = ZT_table[Index].Zone.len;
1747
1748			if (ZT_table[Index].ZoneCount && ZLength) {
1749
1750
1751				if (PacketLen + 8 + ZLength+1 > DDP_DATA_SIZE) /* packet full */
1752					break;
1753
1754				*Reply++ = ZLength;
1755				bcopy((caddr_t) &ZT_table[Index].Zone.str,
1756				      Reply, ZLength);
1757				Reply += ZLength;
1758				PacketLen += ZLength + 1;
1759				ulongtmp++;
1760			}
1761			Index++;
1762		}
1763
1764		if (Index >= ZT_maxentry) /* this is the end of the list */
1765
1766				ulongtmp += 0x01000000;
1767
1768
1769		UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); /* # of zones and flag*/
1770
1771        size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + PacketLen;
1772        gbuf_winc(rm,size);
1773        DDPLEN_ASSIGN(r_ddp, size);
1774
1775        /* all set to send the packet back up */
1776
1777		dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1778			("zip_r_GZL: send packet to %d:%d port %d atp_len =%d\n",
1779			NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort, PacketLen));
1780
1781
1782		if ((status= ddp_router_output(rm, ifID, AT_ADDR,
1783				 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) {
1784			dPrintf(D_M_ZIP, D_L_ERROR, ("zip_reply_to_GZL: ddp_router_output returns=%d\n",
1785				 status));
1786			return (status);
1787		}
1788        return (0);
1789
1790}
1791
1792/*
1793 * zip_reply_to_getlocalzones: replies to ZIP GetLocalZones requested from the Net
1794 */
1795
1796int zip_reply_to_getlocalzones (ifID, m)
1797     register at_ifaddr_t   *ifID;
1798     register gbuf_t      *m;
1799{
1800        at_atp_t            *atp;
1801        register at_ddp_t   *ddp;
1802        register at_ddp_t *r_ddp;
1803        register at_atp_t *r_atp;
1804        register gbuf_t          *rm; /* reply message */
1805        int    size, status;
1806		short	Index, Index_wanted, ZLength;
1807		short i,j, packet_len;
1808		short  zCount, ZoneCount, ZonesInPacket;
1809		unsigned char *zmap, last_flag = 0;
1810		RT_entry *Entry;
1811		char *Reply;
1812
1813        u_long  ulongtmp = 0;
1814
1815		Index = Index_wanted = ZLength = i = j = packet_len = zCount = ZoneCount =
1816		ZonesInPacket = 0;
1817
1818        ddp = (at_ddp_t *)gbuf_rptr(m);
1819        if (gbuf_len(m) > DDP_X_HDR_SIZE)
1820                atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1821        else
1822                atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1823
1824        /* space for two headers and the zone name */
1825
1826        if ((rm = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
1827                return (ENOBUFS);
1828		}
1829
1830        gbuf_rinc(rm,AT_WR_OFFSET);
1831        gbuf_wset(rm,0);
1832        r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1833        r_atp = (at_atp_t *)r_ddp->data;
1834
1835	Reply = (char *)r_atp->data;
1836
1837
1838	/* get the start index from the ATP request */
1839
1840	Index_wanted = (UAL_VALUE_NTOH(atp->user_bytes) & 0xffff) -1;
1841
1842	dPrintf(D_M_ZIP_LOW, D_L_INFO,
1843		("zip_r_GLZ: for station %d:%d Index_wanted = %d\n",
1844		 NET_VALUE(ddp->src_net), ddp->src_node, Index_wanted));
1845
1846	Entry = rt_blookup(NET_VALUE(ddp->src_net));
1847
1848	if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
1849		 RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */
1850
1851		ZoneCount = zt_ent_zcount(Entry) ;
1852
1853		dPrintf(D_M_ZIP_LOW, D_L_INFO,
1854			("zip_reply_GLZ: for %d:%d ZoneCount=%d\n",
1855			 NET_VALUE(ddp->src_net), ddp->src_node, ZoneCount));
1856
1857		zmap = &Entry->ZoneBitMap[0];
1858
1859		/*
1860		 * first of all, we want to find the "first next zone" in the bitmap,
1861		 * to do so, we need to scan the bitmap and add the number of valid
1862		 * zones we find until we reach the next zone to be sent in the reply
1863		 */
1864
1865		if (ZoneCount > Index_wanted) {
1866
1867			ZoneCount -= Index_wanted;
1868
1869			/* find the starting point in the bitmap according to index */
1870
1871			for (i = 0; Index_wanted >= 0 && i < ZT_BYTES; i++)
1872				if (zmap[i]) {
1873					if (Index_wanted < 8) {
1874						/* how many zones in the bitmap byte */
1875						for (j = 0, zCount =0; j < 8 ; j++)
1876							if ((zmap[i] << j) & 0x80)
1877								zCount++;
1878						if (Index_wanted < zCount) {
1879						  for (j = 0 ; Index_wanted > 0 && j < 8 ; j++)
1880						  	if ((zmap[i] << j) & 0x80)
1881							  Index_wanted--;
1882						  break;
1883						}
1884						else
1885						  Index_wanted -= zCount;
1886						}
1887					else
1888						for (j = 0 ; j < 8 ; j++)
1889							if ((zmap[i] << j) & 0x80)
1890								Index_wanted--;
1891				}
1892
1893			/*
1894			 * now, we point to the begining of our next zones in the bitmap
1895			 */
1896
1897			while (i < ZT_BYTES) {
1898
1899				if (zmap[i]) {
1900					for (; j < 8 ; j++)
1901						if ((zmap[i] << j) & 0x80) {
1902						  Index = i*8 + j;	/* get the index in ZT */
1903
1904						  ZLength = ZT_table[Index].Zone.len;
1905
1906						  if (ZT_table[Index].ZoneCount && ZLength) {
1907						    if (packet_len + ATP_HDR_SIZE + ZLength + 1 >
1908							DDP_DATA_SIZE)
1909						      goto FullPacket;
1910
1911						    *Reply++ = ZLength;
1912						    bcopy((caddr_t) &ZT_table[Index].Zone.str,
1913							  Reply, ZLength);
1914						    Reply += ZLength;
1915						    packet_len += ZLength + 1;
1916						    ZonesInPacket ++;
1917						    dPrintf(D_M_ZIP_LOW, D_L_INFO,
1918							    ("zip_reply_GLZ: add z#%d to packet (l=%d)\n",
1919							     Index, packet_len));
1920						  }
1921						  else {
1922						    dPrintf(D_M_ZIP, D_L_WARNING,
1923							    ("zip_reply_GLZ: no len for index=%d\n",
1924							     Index));
1925						  }
1926						}
1927				}
1928				i++;
1929				j = 0;
1930			}
1931		}
1932		else /* set the "last flag" bit  in the reply */
1933			last_flag = 1;
1934	}
1935	else /* set the "last flag" bit  in the reply */
1936		last_flag = 1;
1937
1938FullPacket:
1939
1940	if (ZonesInPacket == ZoneCount)
1941			last_flag = 1;
1942
1943
1944        /* fill up the ddp header for reply */
1945
1946        r_ddp->hopcount = r_ddp->unused = 0;
1947        UAS_ASSIGN(r_ddp->checksum, 0);
1948
1949        NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net);
1950        NET_NET(r_ddp->dst_net, ddp->src_net);
1951
1952        r_ddp->src_node = ifID->ifThisNode.s_node;
1953        r_ddp->dst_node = ddp->src_node;
1954
1955        r_ddp->dst_socket = ddp->src_socket;
1956        r_ddp->src_socket = ZIP_SOCKET;
1957        r_ddp->type = DDP_ATP;
1958
1959        /* fill up the atp header */
1960        r_atp->cmd = ATP_CMD_TRESP;
1961        r_atp->xo = 0;
1962        r_atp->eom = 1;
1963        r_atp->sts = 0;
1964        r_atp->xo_relt = 0;
1965        r_atp->bitmap = 0;
1966        UAS_UAS(r_atp->tid, atp->tid);
1967        ulongtmp =  ((last_flag << 24) & 0xFF000000) + ZonesInPacket; /* # of zones and flag*/
1968		UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp);
1969        size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + packet_len;
1970        gbuf_winc(rm,size);
1971        DDPLEN_ASSIGN(r_ddp, size);
1972
1973        /* all set to send the packet back up */
1974
1975	dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1976		("zip_r_GLZ: send packet to %d:%d port %d atp_len =%d\n",
1977		 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort, packet_len));
1978
1979	if ((status= ddp_router_output(rm, ifID, AT_ADDR,
1980				      NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) {
1981		dPrintf(D_M_ZIP, D_L_ERROR,
1982			("zip_reply_to_GLZ: ddp_router_output returns =%d\n",
1983			 status));
1984		return (status);
1985	}
1986        return (0);
1987} /* zip_reply_to_getlocalzones */
1988
1989int regDefaultZone(ifID)
1990     at_ifaddr_t *ifID;
1991{
1992	char data[ETHERNET_ADDR_LEN];
1993
1994	if (!ifID)
1995		return(-1);
1996
1997	zt_get_zmcast(ifID, &ifID->ifZoneName, data);
1998	if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
1999		ddp_bit_reverse((unsigned char *)data);
2000	bcopy((caddr_t)data, (caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN);
2001	(void)at_reg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr);
2002	return(0);
2003}
2004