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