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