]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/ddp_r_zip.c
xnu-517.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 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
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,
43866e37
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 *);
55e303ae
A
95static void zip_getnetinfo_funnel(void *);
96static void send_phony_reply(void *);
1c79356b
A
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 */
55e303ae
A
995static void zip_getnetinfo_funnel(arg)
996 void *arg;
1c79356b 997{
55e303ae 998 at_ifaddr_t *ifID = (at_ifaddr_t *)arg;
1c79356b
A
999 thread_funnel_set(network_flock, TRUE);
1000 zip_getnetinfo(ifID);
1001 thread_funnel_set(network_flock, FALSE);
1002}
1003
1004
1005/**********************************************************************
1006 * zip_getnetinfo()
1007 *
1008 **********************************************************************/
1009static void zip_getnetinfo (ifID)
1010 register at_ifaddr_t *ifID;
1011{
1012 register at_x_zip_t *zip;
1013 gbuf_t *m;
1014 register at_ddp_t *ddp;
1015 void zip_sched_getnetinfo();
1016 register struct atalk_addr *at_dest;
1017 register int size;
1018
1019 size = DDP_X_HDR_SIZE + ZIP_X_HDR_SIZE + ifID->ifZoneName.len + 1
1020 + sizeof(struct atalk_addr) + 1;
1021 if ((m = gbuf_alloc (AT_WR_OFFSET+size, PRI_HI)) == NULL) {
1022 /* This time, we're unable to allocate buffer to
1023 * send a packet out, so schedule to send a packet
1024 * out later, and exit.
1025 */
1026 dPrintf(D_M_ZIP, D_L_WARNING, ("zip_getnetinfo: no buffer, call later port=%d\n",
1027 ifID->ifPort));
1028 timeout (zip_getnetinfo_funnel, (caddr_t) ifID, ZIP_TIMER_INT/10);
1029 return;
1030 }
1031
1032 gbuf_rinc(m,AT_WR_OFFSET);
1033 gbuf_wset(m,0);
1034 *(u_char *)gbuf_rptr(m) = AT_ADDR;
1035 at_dest = (struct atalk_addr *)(gbuf_rptr(m) + 1);
1036 ddp = (at_ddp_t *)(gbuf_rptr(m) + sizeof(struct atalk_addr) + 1);
1037 zip = (at_x_zip_t *)ddp->data;
1038 gbuf_winc(m,size);
1039
1040 zip->command = ZIP_GETNETINFO;
1041 zip->flags = 0;
1042 NET_ASSIGN(zip->cable_range_start, 0);
1043 NET_ASSIGN(zip->cable_range_end, 0);
1044 if (ifID->ifZoneName.len) /* has to match reply exactly */
1045 bcopy((caddr_t)&ifID->ifZoneName, (caddr_t)zip->data,
1046 ifID->ifZoneName.len + 1);
1047 else
1048 zip->data[0] = 0; /* No zone name is availbale */
1049
1050 /* let the lap fields be uninitialized, 'cause it doesn't
1051 * matter.
1052 */
1053 DDPLEN_ASSIGN(ddp, size - (sizeof(struct atalk_addr) + 1));
1054 UAS_ASSIGN(ddp->checksum, 0);
1055 ddp->hopcount = ddp->unused = 0;
1056 NET_ASSIGN(ddp->dst_net, 0); /* cable-wide broadcast */
1057 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
1058 /* By this time, AARP is done */
1059
1060 ddp->dst_node = 0xff;
1061 ddp->src_node = ifID->ifThisNode.s_node;
1062 ddp->dst_socket = ZIP_SOCKET;
1063 ddp->src_socket = ZIP_SOCKET;
1064 ddp->type = DDP_ZIP;
1065
1066 at_dest->atalk_unused = 0;
1067 NET_NET(at_dest->atalk_net, ddp->dst_net);
1068 at_dest->atalk_node = ddp->dst_node;
1069
1070 dPrintf(D_M_ZIP, D_L_INPUT, ("zip_getnetinfo: called for port=%d\n",
1071 ifID->ifPort));
1072
1073 if (elap_dataput(m, ifID, 0, NULL)) {
1074 dPrintf(D_M_ZIP, D_L_ERROR,
1075 ("zip_getnetinfo: error sending zip_getnetinfo\n"));
1076 return;
1077 }
1078
1079 ifID->ifNumRetries++;
1080 netinfo_reply_pending = 1;
1081
1082 timeout (zip_sched_getnetinfo, (caddr_t) ifID, ZIP_TIMER_INT);
1083} /* zip_getnetinfo */
1084
1085
1086/**********************************************************************
1087 * zip_sched_getnetinfo()
1088 *
1089 **********************************************************************/
1090
1091void zip_sched_getnetinfo (ifID)
1092 register at_ifaddr_t *ifID;
1093{
1094 boolean_t funnel_state;
1095
1096 funnel_state = thread_funnel_set(network_flock, TRUE);
1097
1098 if (ifID->ifNumRetries >= ZIP_NETINFO_RETRIES) {
1099 /* enough packets sent.... give up! */
1100 /* we didn't get any response from the net, so
1101 * assume there's no router around and the given
1102 * zone name, if any, is not valid. Change the
1103 * zone name to "*".
1104 */
1105 ifID->ifZoneName.len = 1;
1106 ifID->ifZoneName.str[0] = '*';
1107 ifID->ifZoneName.str[1] = '\0';
1108 /* Should NBP be notified of this "new" zone name?? */
1109 netinfo_reply_pending = 0;
1110
1111 ifID->ifRouterState = NO_ROUTER;
1112 ifID->ifARouter.s_net = 0;
1113 ifID->ifARouter.s_node = 0;
1114
1115 dPrintf(D_M_ZIP, D_L_INFO, ("zip_sched_getnetinfo: Reset Cable Range\n"));
1116
1117 ifID->ifThisCableStart = DDP_MIN_NETWORK;
1118 ifID->ifThisCableEnd = DDP_MAX_NETWORK;
1119
1120 if (ifID->ifState == LAP_ONLINE_FOR_ZIP)
1121 ZIPwakeup (ifID, 0); /* no error */
1122 } else
1123 zip_getnetinfo(ifID);
1124
1125 (void) thread_funnel_set(network_flock, FALSE);
1126}
1127
1128
1129/**********************************************************************
1130 * zip_type_packet()
1131 *
1132 * Remarks:
1133 * This routine checks whether or not the packet contained in "m"
1134 * is an (outgoing) ZIP packet. If not, it returns 0. If it is a
1135 * ZIP packet, it returns the ZIP packet type (ZIP command). "m"
1136 * points to a packet with extended DDP header. The rest of the
1137 * DDP data may or may not be in the first gbuf.
1138 *
1139 **********************************************************************/
1140int zip_type_packet (m)
1141 register gbuf_t *m;
1142{
1143 register at_atp_t *atp;
1144 register at_ddp_t *ddp;
1145 register at_zip_t *zip;
1146 register u_long user_bytes;
1147 register int user_byte;
1148
1149 ddp = (at_ddp_t *)gbuf_rptr(m);
1150 if (ddp->dst_socket == ZIP_SOCKET) {
1151 switch (ddp->type) {
1152 case DDP_ZIP :
1153 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1154 zip = (at_zip_t *)(gbuf_rptr(m)
1155 + DDP_X_HDR_SIZE);
1156 else
1157 zip=(at_zip_t *)(gbuf_rptr(gbuf_cont(m)));
1158 return ((int)zip->command);
1159 case DDP_ATP :
1160 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1161 atp = (at_atp_t *)(gbuf_rptr(m)+DDP_X_HDR_SIZE);
1162 else
1163 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1164 /* Get the user bytes in network order */
1165 user_bytes = UAL_VALUE(atp->user_bytes);
1166 user_byte = user_bytes >> 24; /* Get the zeroth byte */
1167 if ((user_byte == ZIP_GETMYZONE) ||
1168 (user_byte == ZIP_GETZONELIST) ||
1169 (user_byte == ZIP_GETLOCALZONES))
1170 return (user_byte);
1171 else
1172 return (0);
1173 default :
1174 return (0);
1175 }
1176 } else
1177 return (0);
1178}
1179
1180/**********************************************************************
1181 * zip_handle_getmyzone()
1182 *
1183 * Remarks:
1184 * Routine to handle ZIP GetMyZone request locally. It generates
1185 * a phony response to the outgoing ATP request and sends it up.
1186 *
1187 * 07/12/94 : remark2 only called from ddp.c / ddp_output
1188 * should only be called from the home port, but
1189 * when we are a router we should know the infos for all
1190 * anyway, so reply locally with what we have in stock...
1191 *
1192 **********************************************************************/
1193
1194int zip_handle_getmyzone(ifID, m)
1195 register at_ifaddr_t *ifID;
1196 register gbuf_t *m;
1197{
1198 at_atp_t *atp;
1199 register at_ddp_t *ddp;
1200 register at_ddp_t *r_ddp;
1201 register at_atp_t *r_atp;
1202 gbuf_t *rm; /* reply message */
1203 register int size;
1204 u_long ulongtmp;
1205
1206 dPrintf(D_M_ZIP, D_L_INFO,
1207 ("zip_handle_getmyzone: local reply for port=%d\n",
1208 ifID->ifPort));
1209
1210 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + 1 + ifID->ifZoneName.len;
1211 /* space for two headers and the zone name */
1212 if ((rm = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) {
1213 dPrintf(D_M_ZIP, D_L_WARNING,
1214 ("zip_handle_getmyzone: no buffer, port=%d\n",
1215 ifID->ifPort));
1216 return (ENOBUFS);
1217 }
1218
1219 gbuf_rinc(rm,AT_WR_OFFSET);
1220 gbuf_wset(rm,0);
1221 r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1222 r_atp = (at_atp_t *)r_ddp->data;
1223 gbuf_winc(rm,size);
1224
1225 ddp = (at_ddp_t *)gbuf_rptr(m);
1226 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1227 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1228 else
1229 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1230
1231 /* fill up the ddp header for reply */
1232 DDPLEN_ASSIGN(r_ddp, size);
1233 r_ddp->hopcount = r_ddp->unused = 0;
1234 UAS_ASSIGN(r_ddp->checksum, 0);
1235 NET_ASSIGN(r_ddp->dst_net, ifID->ifThisNode.s_net);
1236 NET_NET(r_ddp->src_net, ddp->dst_net);
1237 r_ddp->dst_node = ifID->ifThisNode.s_node;
1238 r_ddp->src_node = ddp->dst_node;
1239 r_ddp->dst_socket = ddp->src_socket;
1240 r_ddp->src_socket = ZIP_SOCKET;
1241 r_ddp->type = DDP_ATP;
1242
1243 /* fill up the atp header */
1244 r_atp->cmd = ATP_CMD_TRESP;
1245 r_atp->xo = 0;
1246 r_atp->eom = 1;
1247 r_atp->sts = 0;
1248 r_atp->xo_relt = 0;
1249 r_atp->bitmap = 0;
1250 UAS_UAS(r_atp->tid, atp->tid);
1251 ulongtmp = 1;
1252 ulongtmp = htonl(ulongtmp);
1253 UAL_ASSIGN(r_atp->user_bytes, ulongtmp); /* no of zones */
1254
1255 /* fill up atp data part */
1256 bcopy((caddr_t) &ifID->ifZoneName, (caddr_t) r_atp->data, ifID->ifZoneName.len+1);
1257
1258 /* all set to send the packet back up */
1259
1260 timeout(send_phony_reply, (caddr_t) rm, HZ/20);
1261 return (0);
1262}
1263
1264static void
55e303ae
A
1265send_phony_reply(arg)
1266 void *arg;
1c79356b 1267{
55e303ae 1268 gbuf_t *rm = (gbuf_t *)arg;
1c79356b
A
1269 boolean_t funnel_state;
1270
1271 funnel_state = thread_funnel_set(network_flock, TRUE);
1272
1273 ddp_input(rm, ifID_home);
1274
1275 (void) thread_funnel_set(network_flock, FALSE);
1276 return;
1277}
1278
1279
1280/*
1281 * zip_prep_query_packet: build the actual ddp packet for the zip query
1282 */
1283
1284gbuf_t *zip_prep_query_packet(ifID, RouterNet, RouterNode)
1285 at_ifaddr_t *ifID;
1286 at_net_al RouterNet; /* we want to send the Zip Query to that router */
1287 at_node RouterNode;
1288{
1289
1290 register gbuf_t *m;
1291 register at_ddp_t *ddp;
1292
1293 if ((m = gbuf_alloc (AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
1294 dPrintf(D_M_ZIP, D_L_WARNING,
1295 ("zip_send_query_packet: no buffer, port=%d\n",
1296 ifID->ifPort));
1297 return((gbuf_t *)NULL);
1298 }
1299 gbuf_rinc(m,AT_WR_OFFSET);
1300 gbuf_wset(m,0);
1301
1302 ddp = (at_ddp_t *)(gbuf_rptr(m));
1303
1304 /* Prepare the DDP header */
1305
1306 ddp->unused = ddp->hopcount = 0;
1307 UAS_ASSIGN(ddp->checksum, 0);
1308 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
1309 ddp->src_node = ifID->ifThisNode.s_node;
1310 ddp->src_socket = ZIP_SOCKET;
1311
1312 ddp->dst_socket = ZIP_SOCKET;
1313 NET_ASSIGN(ddp->dst_net, RouterNet);
1314 ddp->dst_node = RouterNode;
1315
1316 ddp->type = DDP_ZIP;
1317
1318 return (m);
1319} /* zip_prep_query_packet */
1320
1321
1322/*
1323 * zip_send_queries: this function send queries for the routing table entries that
1324 * need to know their zones. It scans the routing table for entries with unknown
1325 * zones and build Query packets accordingly.
1326 * Note: this is called on a per port basis.
1327 */
1328
1329void zip_send_queries(ifID, RouterNet, RouterNode)
1330 register at_ifaddr_t *ifID;
1331 at_net_al RouterNet; /* we want to send the Zip Query to that router */
1332 at_node RouterNode;
1333{
1334 RT_entry *Entry = &RT_table[0];
1335 register gbuf_t *m;
1336 register at_ddp_t *ddp;
1337 int status;
1338 short Query_index, EntryNumber = 0 ;
1339 register u_char port = ifID->ifPort;
1340 char *QueryBuff, *ZoneCount;
1341 short zip_sent = FALSE;
1342
1343newPacket:
1344
1345 if (!(m = zip_prep_query_packet(ifID, RouterNet, RouterNode))) {
1346 return; /* was return (ENOBUFS); */
1347 }
1348
1349 ddp = (at_ddp_t *)(gbuf_rptr(m));
1350 QueryBuff = (char *)ddp->data;
1351
1352 *QueryBuff++ = ZIP_QUERY;
1353 ZoneCount = QueryBuff; /* network count */
1354 *ZoneCount = 0;
1355 QueryBuff++;
1356 Query_index = 2;
1357
1358
1359 while (EntryNumber < RT_maxentry) {
1360
1361 /* scan the table, and build the packet with the right entries:
1362 * - entry in use and on the right Port
1363 * - with unknwon zones and in an active state
1364 * - talking to the right router
1365 */
1366
1367 if ((Query_index) > 2*254 +2) {
1368
1369 /* we need to send the packet now, but we can't have more than 256
1370 * requests for networks: the Netcount field is a 8bit in the zip query
1371 * packet format as defined in Inside Atalk
1372 */
1373
1374 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1375 ("zip_send_query: FULL query for %d nets on port#%d.(len=%d)\n",
1376 *ZoneCount, port, Query_index));
1377 zip_sent = TRUE;
1378
1379 gbuf_winc(m,DDP_X_HDR_SIZE + Query_index);
1380 DDPLEN_ASSIGN(ddp, DDP_X_HDR_SIZE + Query_index);
1381
1382 if ((status =
1383 ddp_router_output(m, ifID, AT_ADDR,
1384 RouterNet, RouterNode, 0))) {
1385 dPrintf(D_M_ZIP, D_L_ERROR,
1386 ("zip_send_query: ddp_router_output returns =%d\n", status));
1387 return; /* was return (status); */
1388 }
1389
1390 goto newPacket;
1391 }
1392
1393
1394 if (((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
1395 (Entry->NetStop) && (Entry->NetPort == port) &&
1396 (!RT_ALL_ZONES_KNOWN(Entry))){
1397
1398 /* we're ready to had that to our list of stuff to send */
1399
1400 if (Entry->NetStart) { /* extended net*/
1401
1402 *QueryBuff++ = (Entry->NetStart & 0xFF00) >> 8;
1403 *QueryBuff++ = (Entry->NetStart & 0x00FF);
1404
1405 }
1406 else {
1407 *QueryBuff++ = (Entry->NetStop & 0xFF00) >> 8;
1408 *QueryBuff++ = (Entry->NetStop & 0x00FF);
1409 }
1410
1411 Query_index += 2;
1412 *ZoneCount += 1;/* bump the number of network requested */
1413
1414 }
1415
1416 Entry++;
1417 EntryNumber++;
1418
1419 }
1420
1421 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1422 ("zip_send_query: query for %d nets on port#%d.(len=%d)\n",
1423 *ZoneCount, port, Query_index));
1424
1425 if (*ZoneCount) { /* non-full Query needs to be sent */
1426 zip_sent = TRUE;
1427 gbuf_winc(m,DDP_X_HDR_SIZE + Query_index);
1428 DDPLEN_ASSIGN(ddp, DDP_X_HDR_SIZE + Query_index);
1429
1430 if ((status =
1431 ddp_router_output(m, ifID, AT_ADDR,
1432 RouterNet, RouterNode, 0))) {
1433 dPrintf(D_M_ZIP, D_L_ERROR,
1434 ("zip_send_query: ddp_router_output returns =%d\n",
1435 status));
1436 return; /* was return (status); */
1437 }
1438 }
1439 else
1440 gbuf_freem(m);
1441
1442 if (!zip_sent) /* we didn't need to send anything for that port */
1443 ifID->ifZipNeedQueries = 0;
1444} /* zip_send_queries */
1445
1446/* zip_reply_received: we recieved the reply to one of our query, update the
1447 * zone bitmap and stuffs with was we received.
1448 * we receive two types of replies: non extended and extended.
1449 * For extended replies, the network count is the Total of zones for that net.
1450 */
1451
1452zip_reply_received(m, ifID, reply_type)
1453 register gbuf_t *m;
1454 register at_ifaddr_t *ifID;
1455 int reply_type;
1456{
1457 register at_nvestr_t *zname;
1458 RT_entry *Entry = &RT_table[0];
1459 register at_ddp_t *ddp;
1460 at_net_al Network;
1461 u_short payload_len, result;
1462 u_char network_count;
1463 char *PacketPtr;
1464
1465 ddp = (at_ddp_t *)gbuf_rptr(m);
1466
1467 /* access the number of nets provided in the ZIP Reply */
1468
1469 network_count = *(u_char *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 1);
1470
1471 PacketPtr = (char *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 2);
1472
1473 payload_len = DDPLEN_VALUE(ddp) - (DDP_X_HDR_SIZE + 2);
1474
1475 dPrintf(D_M_ZIP_LOW, D_L_INPUT, ("zip_reply_received from %d:%d type=%d netcount=%d\n",
1476 NET_VALUE(ddp->src_net), ddp->src_node, reply_type, network_count));
1477
1478
1479 while (payload_len > 0 && network_count >0) {
1480
1481 Network = *(at_net_al *)PacketPtr;
1482 PacketPtr += 2;
1483 zname = (at_nvestr_t *)PacketPtr;
1484 if (payload_len)
1485 payload_len = payload_len -(zname->len + 3);
1486
1487 if (zname->len <= 0) { /* not valid, we got a problem here... */
1488 dPrintf(D_M_ZIP, D_L_WARNING,
1489 ("zip_reply_received: Problem zlen=0 for net=%d from %d:%d type=%d netcnt=%d\n",
1490 Network, NET_VALUE(ddp->src_net), ddp->src_node, reply_type, network_count));
1491 payload_len =0;
1492 continue;
1493 }
1494
1495
1496 Entry = rt_blookup(Network);
1497
1498 if (Entry != NULL) {
1499
1500 if (Entry->EntryState >= RTE_STATE_SUSPECT) {
1501
1502 result = zt_add_zonename(zname);
1503
1504 if (result == ZT_MAXEDOUT) {
1505
1506 dPrintf(D_M_ZIP, D_L_ERROR,
1507 ("zip_reply_received: ZTable full from %d:%d on zone '%s'\n",
1508 NET_VALUE(ddp->src_net), ddp->src_node, zname->str));
1509 ErrorZIPoverflow = 1;
1510 return(1);
1511 }
1512
1513 zt_set_zmap(result, Entry->ZoneBitMap);
1514
1515 RT_SET_ZONE_KNOWN(Entry);
1516
1517 }
1518 else {
1519 dPrintf(D_M_ZIP, D_L_INPUT,
1520 ("zip_reply_received: entry %d-%d not updated, cause state=%d\n",
1521 Entry->NetStart, Entry->NetStop, Entry->EntryState));
1522 }
1523 }
1524 else {
1525 dPrintf(D_M_ZIP, D_L_WARNING,
1526 ("zip_reply_received: network %d not found in RT\n", Network));
1527 }
1528
1529
1530 /* now bump the PacketPtr pointer */
1531 PacketPtr += zname->len + 1;
1532 network_count--;
1533 }
1534
1535 if ((reply_type == ZIP_REPLY) && network_count > 0) {
1536 if (Entry)
1537 dPrintf(D_M_ZIP, D_L_WARNING,
1538 ("zip_reply_received: Problem decoding zone (after net:%d-%d)\n",
1539 Entry->NetStart, Entry->NetStop));
1540 ifID->ifZipNeedQueries = 1;
1541 }
1542 else {
1543 ifID->ifZipNeedQueries = 0;
1544 if (Entry)
1545 dPrintf(D_M_ZIP_LOW, D_L_INFO,
1546 ("zip_reply_received: entry %d-%d all zones known\n",
1547 Entry->NetStart, Entry->NetStop));
1548 }
1549}
1550
1551/*
1552 * zip_reply_to_getmyzone: replies to ZIP GetMyZone received from the Net
1553 */
1554
1555static void zip_reply_to_getmyzone (ifID, m)
1556 register at_ifaddr_t *ifID;
1557 register gbuf_t *m;
1558{
1559 at_atp_t *atp;
1560 register at_ddp_t *ddp;
1561 register at_ddp_t *r_ddp;
1562 register at_atp_t *r_atp;
1563 register gbuf_t *rm; /* reply message */
1564 register int size, Index, status;
1565 char *data_ptr;
1566 RT_entry *Entry;
1567 u_long ulongtmp;
1568
1569 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + 1 + ifID->ifZoneName.len;
1570 /* space for two headers and the zone name */
1571 if ((rm = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) {
1572 dPrintf(D_M_ZIP, D_L_WARNING,
1573 ("zip_reply_to_getmyzone: no buffer, port=%d\n", ifID->ifPort));
1574 return; /* was return (ENOBUFS); */
1575 }
1576 gbuf_rinc(rm,AT_WR_OFFSET);
1577 gbuf_wset(rm,size);
1578 r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1579 r_atp = (at_atp_t *)r_ddp->data;
1580
1581 ddp = (at_ddp_t *)gbuf_rptr(m);
1582 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1583 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1584 else
1585 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1586
1587 /* fill up the ddp header for reply */
1588 DDPLEN_ASSIGN(r_ddp, size);
1589 r_ddp->hopcount = r_ddp->unused = 0;
1590 UAS_ASSIGN(r_ddp->checksum, 0);
1591
1592 NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net);
1593 NET_NET(r_ddp->dst_net, ddp->src_net);
1594
1595 r_ddp->src_node = ifID->ifThisNode.s_node;
1596 r_ddp->dst_node = ddp->src_node;
1597
1598 r_ddp->dst_socket = ddp->src_socket;
1599 r_ddp->src_socket = ZIP_SOCKET;
1600 r_ddp->type = DDP_ATP;
1601
1602 /* fill up the atp header */
1603 r_atp->cmd = ATP_CMD_TRESP;
1604 r_atp->xo = 0;
1605 r_atp->eom = 1;
1606 r_atp->sts = 0;
1607 r_atp->xo_relt = 0;
1608 r_atp->bitmap = 0;
1609 UAS_UAS(r_atp->tid, atp->tid);
1610 ulongtmp = 1;
1611 ulongtmp = htonl(ulongtmp);
1612 UAL_ASSIGN(r_atp->user_bytes, ulongtmp); /* no of zones */
1613
1614 data_ptr = (char *)r_atp->data;
1615
1616 /*
1617 * fill up atp data part with the zone name if we can find it...
1618 */
1619
1620 Entry = rt_blookup(NET_VALUE(ddp->src_net));
1621 if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
1622 RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */
1623
1624 Index = zt_ent_zindex(Entry->ZoneBitMap) -1;
1625
1626 *data_ptr = ZT_table[Index].Zone.len;
1627 bcopy((caddr_t) &ZT_table[Index].Zone.str, (caddr_t) ++data_ptr,
1628 ZT_table[Index].Zone.len);
1629
1630 /* all set to send the packet back up */
1631 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1632 ("zip_reply_to_GMZ: ddp_router_output to %d:%d port %d\n",
1633 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort));
1634
1635 if ((status =
1636 ddp_router_output(rm, ifID, AT_ADDR,
1637 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) {
1638 dPrintf(D_M_ZIP, D_L_ERROR,
1639 ("zip_reply_to_GMZ: ddp_r_output returns =%d\n", status));
1640 return; /* was return (status); */
1641 }
1642 }
1643 else
1644 gbuf_freem(rm);
1645}
1646
1647/*
1648 * zip_reply_to_getzonelist: replies to ZIP GetZoneList requested from the Net
1649 */
1650
1651zip_reply_to_getzonelist (ifID, m)
1652 register at_ifaddr_t *ifID;
1653 register gbuf_t *m;
1654{
1655 at_atp_t *atp;
1656 register at_ddp_t *ddp;
1657 register at_ddp_t *r_ddp;
1658 register at_atp_t *r_atp;
1659 register gbuf_t *rm; /* reply message */
1660 register int size, status;
1661 register short Index=0, StartPoint, ZLength, PacketLen=0;
1662 u_long ulongtmp= 0;
1663 char *Reply;
1664
1665 ddp = (at_ddp_t *)gbuf_rptr(m);
1666 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1667 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1668 else
1669 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1670
1671
1672 /* space for two headers and the zone name */
1673
1674 if ((rm = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
1675 return (ENOBUFS);
1676 }
1677
1678 gbuf_rinc(rm,AT_WR_OFFSET);
1679 gbuf_wset(rm,0);
1680 r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1681 r_atp = (at_atp_t *)r_ddp->data;
1682
1683 /* fill up the ddp header for reply */
1684
1685 r_ddp->hopcount = r_ddp->unused = 0;
1686 UAS_ASSIGN(r_ddp->checksum, 0);
1687 NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net);
1688 NET_NET(r_ddp->dst_net, ddp->src_net);
1689 r_ddp->src_node = ifID->ifThisNode.s_node;
1690 r_ddp->dst_node = ddp->src_node;
1691 r_ddp->dst_socket = ddp->src_socket;
1692 r_ddp->src_socket = ZIP_SOCKET;
1693 r_ddp->type = DDP_ATP;
1694
1695 /* fill up the atp header */
1696
1697 r_atp->cmd = ATP_CMD_TRESP;
1698 r_atp->xo = 0;
1699 r_atp->eom = 1;
1700 r_atp->sts = 0;
1701 r_atp->xo_relt = 0;
1702 r_atp->bitmap = 0;
1703 UAS_UAS(r_atp->tid, atp->tid);
1704
1705 Reply = (char *)r_atp->data;
1706
1707 /* get the start index from the ATP request */
1708
1709 StartPoint = (UAL_VALUE(atp->user_bytes) & 0xffff) -1;
1710
1711 /* find the next zone to send */
1712
1713 while ((Index < ZT_maxentry) && StartPoint > 0) {
1714 if (ZT_table[Index].Zone.len)
1715 StartPoint--;
1716 Index++;
1717 }
1718
1719
1720 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT, ("zip_reply_to_GZL: Index=%d\n", Index));
1721 /*
1722 * fill up atp data part with the zone name if we can find it...
1723 */
1724
1725 while (Index < ZT_maxentry) {
1726
1727 ZLength = ZT_table[Index].Zone.len;
1728
1729 if (ZT_table[Index].ZoneCount && ZLength) {
1730
1731
1732 if (PacketLen + 8 + ZLength+1 > DDP_DATA_SIZE) /* packet full */
1733 break;
1734
1735 *Reply++ = ZLength;
1736 bcopy((caddr_t) &ZT_table[Index].Zone.str,
1737 Reply, ZLength);
1738 Reply += ZLength;
1739 PacketLen += ZLength + 1;
1740 ulongtmp++;
1741 }
1742 Index++;
1743 }
1744
1745 if (Index >= ZT_maxentry) /* this is the end of the list */
1746
1747 ulongtmp += 0x01000000;
1748
1749
1750 UAL_ASSIGN(r_atp->user_bytes, ulongtmp); /* # of zones and flag*/
1751
1752 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + PacketLen;
1753 gbuf_winc(rm,size);
1754 DDPLEN_ASSIGN(r_ddp, size);
1755
1756 /* all set to send the packet back up */
1757
1758 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1759 ("zip_r_GZL: send packet to %d:%d port %d atp_len =%d\n",
1760 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort, PacketLen));
1761
1762
1763 if (status= ddp_router_output(rm, ifID, AT_ADDR,
1764 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0)) {
1765 dPrintf(D_M_ZIP, D_L_ERROR, ("zip_reply_to_GZL: ddp_router_output returns=%d\n",
1766 status));
1767 return (status);
1768 }
1769 return (0);
1770
1771}
1772
1773/*
1774 * zip_reply_to_getlocalzones: replies to ZIP GetLocalZones requested from the Net
1775 */
1776
1777int zip_reply_to_getlocalzones (ifID, m)
1778 register at_ifaddr_t *ifID;
1779 register gbuf_t *m;
1780{
1781 at_atp_t *atp;
1782 register at_ddp_t *ddp;
1783 register at_ddp_t *r_ddp;
1784 register at_atp_t *r_atp;
1785 register gbuf_t *rm; /* reply message */
1786 int size, status;
1787 short Index, Index_wanted, ZLength;
1788 short i,j, packet_len;
1789 short zCount, ZoneCount, ZonesInPacket;
1790 char *zmap, last_flag = 0;
1791 RT_entry *Entry;
1792 char *Reply;
1793
1794 u_long ulongtmp = 0;
1795
1796 Index = Index_wanted = ZLength = i = j = packet_len = zCount = ZoneCount =
1797 ZonesInPacket = 0;
1798
1799 ddp = (at_ddp_t *)gbuf_rptr(m);
1800 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1801 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1802 else
1803 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1804
1805 /* space for two headers and the zone name */
1806
1807 if ((rm = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
1808 return (ENOBUFS);
1809 }
1810
1811 gbuf_rinc(rm,AT_WR_OFFSET);
1812 gbuf_wset(rm,0);
1813 r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1814 r_atp = (at_atp_t *)r_ddp->data;
1815
1816 Reply = (char *)r_atp->data;
1817
1818
1819 /* get the start index from the ATP request */
1820
1821 Index_wanted = (UAL_VALUE(atp->user_bytes) & 0xffff) -1;
1822
1823 dPrintf(D_M_ZIP_LOW, D_L_INFO,
1824 ("zip_r_GLZ: for station %d:%d Index_wanted = %d\n",
1825 NET_VALUE(ddp->src_net), ddp->src_node, Index_wanted));
1826
1827 Entry = rt_blookup(NET_VALUE(ddp->src_net));
1828
1829 if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
1830 RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */
1831
1832 ZoneCount = zt_ent_zcount(Entry) ;
1833
1834 dPrintf(D_M_ZIP_LOW, D_L_INFO,
1835 ("zip_reply_GLZ: for %d:%d ZoneCount=%d\n",
1836 NET_VALUE(ddp->src_net), ddp->src_node, ZoneCount));
1837
1838 zmap = &Entry->ZoneBitMap[0];
1839
1840 /*
1841 * first of all, we want to find the "first next zone" in the bitmap,
1842 * to do so, we need to scan the bitmap and add the number of valid
1843 * zones we find until we reach the next zone to be sent in the reply
1844 */
1845
1846 if (ZoneCount > Index_wanted) {
1847
1848 ZoneCount -= Index_wanted;
1849
1850 /* find the starting point in the bitmap according to index */
1851
1852 for (i = 0; Index_wanted >= 0 && i < ZT_BYTES; i++)
1853 if (zmap[i]) {
1854 if (Index_wanted < 8) {
1855 /* how many zones in the bitmap byte */
1856 for (j = 0, zCount =0; j < 8 ; j++)
1857 if ((zmap[i] << j) & 0x80)
1858 zCount++;
1859 if (Index_wanted < zCount) {
1860 for (j = 0 ; Index_wanted > 0 && j < 8 ; j++)
1861 if ((zmap[i] << j) & 0x80)
1862 Index_wanted--;
1863 break;
1864 }
1865 else
1866 Index_wanted -= zCount;
1867 }
1868 else
1869 for (j = 0 ; j < 8 ; j++)
1870 if ((zmap[i] << j) & 0x80)
1871 Index_wanted--;
1872 }
1873
1874 /*
1875 * now, we point to the begining of our next zones in the bitmap
1876 */
1877
1878 while (i < ZT_BYTES) {
1879
1880 if (zmap[i]) {
1881 for (; j < 8 ; j++)
1882 if ((zmap[i] << j) & 0x80) {
1883 Index = i*8 + j; /* get the index in ZT */
1884
1885 ZLength = ZT_table[Index].Zone.len;
1886
1887 if (ZT_table[Index].ZoneCount && ZLength) {
1888 if (packet_len + ATP_HDR_SIZE + ZLength + 1 >
1889 DDP_DATA_SIZE)
1890 goto FullPacket;
1891
1892 *Reply++ = ZLength;
1893 bcopy((caddr_t) &ZT_table[Index].Zone.str,
1894 Reply, ZLength);
1895 Reply += ZLength;
1896 packet_len += ZLength + 1;
1897 ZonesInPacket ++;
1898 dPrintf(D_M_ZIP_LOW, D_L_INFO,
1899 ("zip_reply_GLZ: add z#%d to packet (l=%d)\n",
1900 Index, packet_len));
1901 }
1902 else {
1903 dPrintf(D_M_ZIP, D_L_WARNING,
1904 ("zip_reply_GLZ: no len for index=%d\n",
1905 Index));
1906 }
1907 }
1908 }
1909 i++;
1910 j = 0;
1911 }
1912 }
1913 else /* set the "last flag" bit in the reply */
1914 last_flag = 1;
1915 }
1916 else /* set the "last flag" bit in the reply */
1917 last_flag = 1;
1918
1919FullPacket:
1920
1921 if (ZonesInPacket == ZoneCount)
1922 last_flag = 1;
1923
1924
1925 /* fill up the ddp header for reply */
1926
1927 r_ddp->hopcount = r_ddp->unused = 0;
1928 UAS_ASSIGN(r_ddp->checksum, 0);
1929
1930 NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net);
1931 NET_NET(r_ddp->dst_net, ddp->src_net);
1932
1933 r_ddp->src_node = ifID->ifThisNode.s_node;
1934 r_ddp->dst_node = ddp->src_node;
1935
1936 r_ddp->dst_socket = ddp->src_socket;
1937 r_ddp->src_socket = ZIP_SOCKET;
1938 r_ddp->type = DDP_ATP;
1939
1940 /* fill up the atp header */
1941 r_atp->cmd = ATP_CMD_TRESP;
1942 r_atp->xo = 0;
1943 r_atp->eom = 1;
1944 r_atp->sts = 0;
1945 r_atp->xo_relt = 0;
1946 r_atp->bitmap = 0;
1947 UAS_UAS(r_atp->tid, atp->tid);
1948 ulongtmp = ((last_flag << 24) & 0xFF000000) + ZonesInPacket; /* # of zones and flag*/
1949 UAL_ASSIGN(r_atp->user_bytes, ulongtmp);
1950 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + packet_len;
1951 gbuf_winc(rm,size);
1952 DDPLEN_ASSIGN(r_ddp, size);
1953
1954 /* all set to send the packet back up */
1955
1956 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1957 ("zip_r_GLZ: send packet to %d:%d port %d atp_len =%d\n",
1958 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort, packet_len));
1959
1960 if (status= ddp_router_output(rm, ifID, AT_ADDR,
1961 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0)) {
1962 dPrintf(D_M_ZIP, D_L_ERROR,
1963 ("zip_reply_to_GLZ: ddp_router_output returns =%d\n",
1964 status));
1965 return (status);
1966 }
1967 return (0);
1968} /* zip_reply_to_getlocalzones */
1969
1970int regDefaultZone(ifID)
1971 at_ifaddr_t *ifID;
1972{
1973 int i;
1974 char data[ETHERNET_ADDR_LEN];
1975
1976 if (!ifID)
1977 return(-1);
1978
1979 zt_get_zmcast(ifID, &ifID->ifZoneName, data);
1980 if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
1981 ddp_bit_reverse(data);
1982 bcopy((caddr_t)data, (caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN);
1983 (void)at_reg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr);
1984 return(0);
1985}