]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/ddp_r_zip.c
xnu-517.12.7.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 *);
55e303ae
A
92static void zip_getnetinfo_funnel(void *);
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;
745 timeout(zip_sched_getnetinfo, (caddr_t) ifID,
746 2*ZIP_TIMER_INT);
747
748 gbuf_freem(m);
749 break;
750 default :
751 routing_needed(m, ifID, TRUE);
752 break;
753 }
754 }
755 else if (ddp->type == DDP_ATP &&
756 RT_LOOKUP_OKAY(ifID, ddp)) {
757 if (gbuf_len(m) > DDP_X_HDR_SIZE)
758 atp = (at_atp_t *)(gbuf_rptr(m)+DDP_X_HDR_SIZE);
759 else
760 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
761
762 /* Get the user bytes in network order */
763
764 user_bytes = UAL_VALUE(atp->user_bytes);
765 user_byte = user_bytes >> 24; /* Get the zeroth byte */
766
767 dPrintf(D_M_ZIP, D_L_INPUT,
768 ("zip_input: received a ZIP_ATP command=%d\n", user_byte));
769
770 switch (user_byte) {
771 case ZIP_GETMYZONE:
772 zip_reply_to_getmyzone(ifID, m);
773 gbuf_freem(m);
774 break;
775
776 case ZIP_GETZONELIST:
777 zip_reply_to_getzonelist(ifID, m);
778 gbuf_freem(m);
779 break;
780
781 case ZIP_GETLOCALZONES:
782 zip_reply_to_getlocalzones(ifID, m);
783 gbuf_freem(m);
784 break;
785
786 default:
787 dPrintf(D_M_ZIP, D_L_WARNING,
788 ("zip_input: received unknown ZIP_ATP command=%d\n", user_byte));
789 routing_needed(m, ifID, TRUE);
790 break;
791 }
792 } else {
793 gbuf_freem(m);
794 }
795 return;
796} /* zip_router_input */
797
798/***********************************************************************
799 * zonename_equal()
800 *
801 * Remarks :
802 *
803 **********************************************************************/
804int zonename_equal (zone1, zone2)
805 register at_nvestr_t *zone1, *zone2;
806{
807 register char c1, c2;
808 char upshift8();
809 register int i;
810
811 if (zone1->len != zone2->len)
812 return(0);
813
814 for (i=0; i< (int) zone1->len; i++) {
815 c1 = zone1->str[i];
816 c2 = zone2->str[i];
817 if (c1 >= 'a' && c1 <= 'z')
818 c1 += 'A' - 'a';
819 if (c2 >= 'a' && c2 <= 'z')
820 c2 += 'A' - 'a';
821 if (c1 & 0x80)
822 c1 = upshift8(c1);
823 if (c2 & 0x80)
824 c2 = upshift8(c2);
825 if (c1 != c2)
826 return(0);
827 }
828 return(1);
829}
830
831
832char upshift8 (ch)
833 register char ch;
834{
835 register int i;
836
837 static unsigned char lower_case[] =
838 {0x8a, 0x8c, 0x8d, 0x8e, 0x96, 0x9a, 0x9f, 0xbe,
839 0xbf, 0xcf, 0x9b, 0x8b, 0x88, 0};
840 static unsigned char upper_case[] =
841 {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xae,
842 0xaf, 0xce, 0xcd, 0xcc, 0xcb, 0};
843
844 for (i=0; lower_case[i]; i++)
845 if (ch == lower_case[i])
846 return (upper_case[i]);
847
848 return(ch);
849}
850
851
852/***********************************************************************
853 * zip_netinfo_reply ()
854 *
855 * Remarks :
856 *
857 **********************************************************************/
858static void zip_netinfo_reply (netinfo, ifID)
859 register at_x_zip_t *netinfo;
860 register at_ifaddr_t *ifID;
861{
862 u_char mcast_len;
863 void zip_sched_getnetinfo(); /* forward reference */
864 register at_net_al this_net;
865 char *default_zone;
866 register u_char zone_name_len;
867
868 /* There may be multiple zones on the cable.... we need to
869 * worry about whether or not this packet is addressed
870 * to us.
871 */
872 /* *** Do we really need to check this? *** */
9bccf70c
A
873 if (!zonename_equal((at_nvestr_t *)netinfo->data, &ifID->ifZoneName)) {
874 dPrintf(D_M_ZIP, D_L_INFO, ("zip_netinfo_reply, !zonename_equal!!!"));
1c79356b 875 return;
9bccf70c 876 }
1c79356b
A
877
878 ifID->ifThisCableStart = NET_VALUE(netinfo->cable_range_start);
879 ifID->ifThisCableEnd = NET_VALUE(netinfo->cable_range_end);
880 dPrintf(D_M_ZIP, D_L_OUTPUT, ("Zip_netinfo_reply: Set cable to %d-%d\n",
881 ifID->ifThisCableStart, ifID->ifThisCableEnd));
882
883 /* The packet is in response to our request */
884 untimeout (zip_sched_getnetinfo, (caddr_t) ifID);
885 netinfo_reply_pending = 0;
886 zone_name_len = netinfo->data[0];
887 mcast_len = netinfo->data[zone_name_len + 1];
888
889 if (netinfo->flags & ZIP_ZONENAME_INVALID) {
890 /* copy out the default zone name from packet */
891 default_zone = (char *)&netinfo->data[zone_name_len+1+mcast_len+1];
892 bcopy((caddr_t)default_zone, (caddr_t)&ifID->ifZoneName,
893 *default_zone + 1);
894 }
895
896 /* add the new zone to the list of local zones */
897 if (!MULTIPORT_MODE && !DEFAULT_ZONE(&ifID->ifZoneName))
898 (void)setLocalZones(&ifID->ifZoneName, (ifID->ifZoneName.len+1));
899
900 /* get the multicast address out of the GetNetInfo reply, if there is one */
901 if (!(netinfo->flags & ZIP_USE_BROADCAST)) {
902 /* If ZIP_USE_BROADCAST is set, we will use the cable
903 broadcast address as the multicast address, however
904 the cable multicast address has already been registered.
905 */
906 /* This packet contains a multicast address, so
907 * send to elap to register it.
908 */
909 if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
910 ddp_bit_reverse(&netinfo->data[zone_name_len + 2]);
911
912 bcopy((caddr_t)&netinfo->data[zone_name_len + 2],
913 (caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN);
914 (void)at_reg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr);
915 }
916
917 this_net = ifID->ifThisNode.s_net;
918 if ((this_net >= ifID->ifThisCableStart) &&
919 (this_net <= ifID->ifThisCableEnd)) {
920 /* ThisNet is in the range of valid network numbers
921 * for the cable. Do nothing.
922 */
923 } else {
924 /* ThisNet is not in the range of valid network
925 * numbers for the cable. This may be either because
926 * the chosen number was from start-up range, or
927 * because the user has a misconception of where the
928 * machine is!! Since ThisCableRange is set up, next
929 * time aarp is invoked, it would select address in
930 * the right range.
931 */
932
933 /* to reset initial_net and initial_node to zero, so
934 * that aarp is forced to choose new values
935 */
936 ifID->initial_addr.s_net = 0;
937 ifID->initial_addr.s_node = 0;
938
939 /* Wake up elap_online sleeping on this interface. */
940 ZIPwakeup(ifID, ZIP_RE_AARP);
941 return;
942 }
9bccf70c
A
943
944 if (!ifID->startup_inprogress) {
945 /* Send event with zone info. This covers case where we get zone info
946 after startup. During startup this event is sent from ZIPwakeup. */
947 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName));
948 }
1c79356b
A
949
950 ZIPwakeup(ifID, 0); /* no error */
951 return;
952} /* zip_netinfo_reply */
953
954
955/**********************************************************************
956 * zip_control()
957 *
958 **********************************************************************/
959int zip_control (ifID, control)
960 register at_ifaddr_t *ifID;
961 int control;
962{
963 dPrintf(D_M_ZIP, D_L_INFO, ("zip_control called port=%d control=%d\n",
964 ifID->ifPort, control));
965 switch (control) {
966 case ZIP_ONLINE :
967 case ZIP_LATE_ROUTER :
968 ifID->ifNumRetries = 0;
969 /* Get the desired zone name from elap and put it in
970 * ifID for zip_getnetinfo() to use.
971 */
972 if (ifID->startup_zone.len)
973 ifID->ifZoneName = ifID->startup_zone;
974 zip_getnetinfo(ifID);
975 break;
976 case ZIP_NO_ROUTER :
977 ifID->ifZoneName.len = 1;
978 ifID->ifZoneName.str[0] = '*';
979 ifID->ifZoneName.str[1] = '\0';
9bccf70c
A
980
981 /* Send event with zone info. */
982 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName));
983
1c79356b
A
984 break;
985 default :
986 break;
987 }
988 return (0);
989}
990
991/* funnel version of zip_getnetinfo */
55e303ae
A
992static void zip_getnetinfo_funnel(arg)
993 void *arg;
1c79356b 994{
55e303ae 995 at_ifaddr_t *ifID = (at_ifaddr_t *)arg;
1c79356b
A
996 thread_funnel_set(network_flock, TRUE);
997 zip_getnetinfo(ifID);
998 thread_funnel_set(network_flock, FALSE);
999}
1000
1001
1002/**********************************************************************
1003 * zip_getnetinfo()
1004 *
1005 **********************************************************************/
1006static void zip_getnetinfo (ifID)
1007 register at_ifaddr_t *ifID;
1008{
1009 register at_x_zip_t *zip;
1010 gbuf_t *m;
1011 register at_ddp_t *ddp;
1012 void zip_sched_getnetinfo();
1013 register struct atalk_addr *at_dest;
1014 register int size;
1015
1016 size = DDP_X_HDR_SIZE + ZIP_X_HDR_SIZE + ifID->ifZoneName.len + 1
1017 + sizeof(struct atalk_addr) + 1;
1018 if ((m = gbuf_alloc (AT_WR_OFFSET+size, PRI_HI)) == NULL) {
1019 /* This time, we're unable to allocate buffer to
1020 * send a packet out, so schedule to send a packet
1021 * out later, and exit.
1022 */
1023 dPrintf(D_M_ZIP, D_L_WARNING, ("zip_getnetinfo: no buffer, call later port=%d\n",
1024 ifID->ifPort));
1025 timeout (zip_getnetinfo_funnel, (caddr_t) ifID, ZIP_TIMER_INT/10);
1026 return;
1027 }
1028
1029 gbuf_rinc(m,AT_WR_OFFSET);
1030 gbuf_wset(m,0);
1031 *(u_char *)gbuf_rptr(m) = AT_ADDR;
1032 at_dest = (struct atalk_addr *)(gbuf_rptr(m) + 1);
1033 ddp = (at_ddp_t *)(gbuf_rptr(m) + sizeof(struct atalk_addr) + 1);
1034 zip = (at_x_zip_t *)ddp->data;
1035 gbuf_winc(m,size);
1036
1037 zip->command = ZIP_GETNETINFO;
1038 zip->flags = 0;
1039 NET_ASSIGN(zip->cable_range_start, 0);
1040 NET_ASSIGN(zip->cable_range_end, 0);
1041 if (ifID->ifZoneName.len) /* has to match reply exactly */
1042 bcopy((caddr_t)&ifID->ifZoneName, (caddr_t)zip->data,
1043 ifID->ifZoneName.len + 1);
1044 else
1045 zip->data[0] = 0; /* No zone name is availbale */
1046
1047 /* let the lap fields be uninitialized, 'cause it doesn't
1048 * matter.
1049 */
1050 DDPLEN_ASSIGN(ddp, size - (sizeof(struct atalk_addr) + 1));
1051 UAS_ASSIGN(ddp->checksum, 0);
1052 ddp->hopcount = ddp->unused = 0;
1053 NET_ASSIGN(ddp->dst_net, 0); /* cable-wide broadcast */
1054 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
1055 /* By this time, AARP is done */
1056
1057 ddp->dst_node = 0xff;
1058 ddp->src_node = ifID->ifThisNode.s_node;
1059 ddp->dst_socket = ZIP_SOCKET;
1060 ddp->src_socket = ZIP_SOCKET;
1061 ddp->type = DDP_ZIP;
1062
1063 at_dest->atalk_unused = 0;
1064 NET_NET(at_dest->atalk_net, ddp->dst_net);
1065 at_dest->atalk_node = ddp->dst_node;
1066
1067 dPrintf(D_M_ZIP, D_L_INPUT, ("zip_getnetinfo: called for port=%d\n",
1068 ifID->ifPort));
1069
1070 if (elap_dataput(m, ifID, 0, NULL)) {
1071 dPrintf(D_M_ZIP, D_L_ERROR,
1072 ("zip_getnetinfo: error sending zip_getnetinfo\n"));
1073 return;
1074 }
1075
1076 ifID->ifNumRetries++;
1077 netinfo_reply_pending = 1;
1078
1079 timeout (zip_sched_getnetinfo, (caddr_t) ifID, ZIP_TIMER_INT);
1080} /* zip_getnetinfo */
1081
1082
1083/**********************************************************************
1084 * zip_sched_getnetinfo()
1085 *
1086 **********************************************************************/
1087
1088void zip_sched_getnetinfo (ifID)
1089 register at_ifaddr_t *ifID;
1090{
1091 boolean_t funnel_state;
1092
1093 funnel_state = thread_funnel_set(network_flock, TRUE);
1094
1095 if (ifID->ifNumRetries >= ZIP_NETINFO_RETRIES) {
1096 /* enough packets sent.... give up! */
1097 /* we didn't get any response from the net, so
1098 * assume there's no router around and the given
1099 * zone name, if any, is not valid. Change the
1100 * zone name to "*".
1101 */
1102 ifID->ifZoneName.len = 1;
1103 ifID->ifZoneName.str[0] = '*';
1104 ifID->ifZoneName.str[1] = '\0';
1105 /* Should NBP be notified of this "new" zone name?? */
1106 netinfo_reply_pending = 0;
1107
1108 ifID->ifRouterState = NO_ROUTER;
1109 ifID->ifARouter.s_net = 0;
1110 ifID->ifARouter.s_node = 0;
1111
1112 dPrintf(D_M_ZIP, D_L_INFO, ("zip_sched_getnetinfo: Reset Cable Range\n"));
1113
1114 ifID->ifThisCableStart = DDP_MIN_NETWORK;
1115 ifID->ifThisCableEnd = DDP_MAX_NETWORK;
1116
1117 if (ifID->ifState == LAP_ONLINE_FOR_ZIP)
1118 ZIPwakeup (ifID, 0); /* no error */
1119 } else
1120 zip_getnetinfo(ifID);
1121
1122 (void) thread_funnel_set(network_flock, FALSE);
1123}
1124
1125
1126/**********************************************************************
1127 * zip_type_packet()
1128 *
1129 * Remarks:
1130 * This routine checks whether or not the packet contained in "m"
1131 * is an (outgoing) ZIP packet. If not, it returns 0. If it is a
1132 * ZIP packet, it returns the ZIP packet type (ZIP command). "m"
1133 * points to a packet with extended DDP header. The rest of the
1134 * DDP data may or may not be in the first gbuf.
1135 *
1136 **********************************************************************/
1137int zip_type_packet (m)
1138 register gbuf_t *m;
1139{
1140 register at_atp_t *atp;
1141 register at_ddp_t *ddp;
1142 register at_zip_t *zip;
1143 register u_long user_bytes;
1144 register int user_byte;
1145
1146 ddp = (at_ddp_t *)gbuf_rptr(m);
1147 if (ddp->dst_socket == ZIP_SOCKET) {
1148 switch (ddp->type) {
1149 case DDP_ZIP :
1150 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1151 zip = (at_zip_t *)(gbuf_rptr(m)
1152 + DDP_X_HDR_SIZE);
1153 else
1154 zip=(at_zip_t *)(gbuf_rptr(gbuf_cont(m)));
1155 return ((int)zip->command);
1156 case DDP_ATP :
1157 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1158 atp = (at_atp_t *)(gbuf_rptr(m)+DDP_X_HDR_SIZE);
1159 else
1160 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1161 /* Get the user bytes in network order */
1162 user_bytes = UAL_VALUE(atp->user_bytes);
1163 user_byte = user_bytes >> 24; /* Get the zeroth byte */
1164 if ((user_byte == ZIP_GETMYZONE) ||
1165 (user_byte == ZIP_GETZONELIST) ||
1166 (user_byte == ZIP_GETLOCALZONES))
1167 return (user_byte);
1168 else
1169 return (0);
1170 default :
1171 return (0);
1172 }
1173 } else
1174 return (0);
1175}
1176
1177/**********************************************************************
1178 * zip_handle_getmyzone()
1179 *
1180 * Remarks:
1181 * Routine to handle ZIP GetMyZone request locally. It generates
1182 * a phony response to the outgoing ATP request and sends it up.
1183 *
1184 * 07/12/94 : remark2 only called from ddp.c / ddp_output
1185 * should only be called from the home port, but
1186 * when we are a router we should know the infos for all
1187 * anyway, so reply locally with what we have in stock...
1188 *
1189 **********************************************************************/
1190
1191int zip_handle_getmyzone(ifID, m)
1192 register at_ifaddr_t *ifID;
1193 register gbuf_t *m;
1194{
1195 at_atp_t *atp;
1196 register at_ddp_t *ddp;
1197 register at_ddp_t *r_ddp;
1198 register at_atp_t *r_atp;
1199 gbuf_t *rm; /* reply message */
1200 register int size;
1201 u_long ulongtmp;
1202
1203 dPrintf(D_M_ZIP, D_L_INFO,
1204 ("zip_handle_getmyzone: local reply for port=%d\n",
1205 ifID->ifPort));
1206
1207 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + 1 + ifID->ifZoneName.len;
1208 /* space for two headers and the zone name */
1209 if ((rm = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) {
1210 dPrintf(D_M_ZIP, D_L_WARNING,
1211 ("zip_handle_getmyzone: no buffer, port=%d\n",
1212 ifID->ifPort));
1213 return (ENOBUFS);
1214 }
1215
1216 gbuf_rinc(rm,AT_WR_OFFSET);
1217 gbuf_wset(rm,0);
1218 r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1219 r_atp = (at_atp_t *)r_ddp->data;
1220 gbuf_winc(rm,size);
1221
1222 ddp = (at_ddp_t *)gbuf_rptr(m);
1223 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1224 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1225 else
1226 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1227
1228 /* fill up the ddp header for reply */
1229 DDPLEN_ASSIGN(r_ddp, size);
1230 r_ddp->hopcount = r_ddp->unused = 0;
1231 UAS_ASSIGN(r_ddp->checksum, 0);
1232 NET_ASSIGN(r_ddp->dst_net, ifID->ifThisNode.s_net);
1233 NET_NET(r_ddp->src_net, ddp->dst_net);
1234 r_ddp->dst_node = ifID->ifThisNode.s_node;
1235 r_ddp->src_node = ddp->dst_node;
1236 r_ddp->dst_socket = ddp->src_socket;
1237 r_ddp->src_socket = ZIP_SOCKET;
1238 r_ddp->type = DDP_ATP;
1239
1240 /* fill up the atp header */
1241 r_atp->cmd = ATP_CMD_TRESP;
1242 r_atp->xo = 0;
1243 r_atp->eom = 1;
1244 r_atp->sts = 0;
1245 r_atp->xo_relt = 0;
1246 r_atp->bitmap = 0;
1247 UAS_UAS(r_atp->tid, atp->tid);
1248 ulongtmp = 1;
1249 ulongtmp = htonl(ulongtmp);
1250 UAL_ASSIGN(r_atp->user_bytes, ulongtmp); /* no of zones */
1251
1252 /* fill up atp data part */
1253 bcopy((caddr_t) &ifID->ifZoneName, (caddr_t) r_atp->data, ifID->ifZoneName.len+1);
1254
1255 /* all set to send the packet back up */
1256
1257 timeout(send_phony_reply, (caddr_t) rm, HZ/20);
1258 return (0);
1259}
1260
1261static void
55e303ae
A
1262send_phony_reply(arg)
1263 void *arg;
1c79356b 1264{
55e303ae 1265 gbuf_t *rm = (gbuf_t *)arg;
1c79356b
A
1266 boolean_t funnel_state;
1267
1268 funnel_state = thread_funnel_set(network_flock, TRUE);
1269
1270 ddp_input(rm, ifID_home);
1271
1272 (void) thread_funnel_set(network_flock, FALSE);
1273 return;
1274}
1275
1276
1277/*
1278 * zip_prep_query_packet: build the actual ddp packet for the zip query
1279 */
1280
1281gbuf_t *zip_prep_query_packet(ifID, RouterNet, RouterNode)
1282 at_ifaddr_t *ifID;
1283 at_net_al RouterNet; /* we want to send the Zip Query to that router */
1284 at_node RouterNode;
1285{
1286
1287 register gbuf_t *m;
1288 register at_ddp_t *ddp;
1289
1290 if ((m = gbuf_alloc (AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
1291 dPrintf(D_M_ZIP, D_L_WARNING,
1292 ("zip_send_query_packet: no buffer, port=%d\n",
1293 ifID->ifPort));
1294 return((gbuf_t *)NULL);
1295 }
1296 gbuf_rinc(m,AT_WR_OFFSET);
1297 gbuf_wset(m,0);
1298
1299 ddp = (at_ddp_t *)(gbuf_rptr(m));
1300
1301 /* Prepare the DDP header */
1302
1303 ddp->unused = ddp->hopcount = 0;
1304 UAS_ASSIGN(ddp->checksum, 0);
1305 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
1306 ddp->src_node = ifID->ifThisNode.s_node;
1307 ddp->src_socket = ZIP_SOCKET;
1308
1309 ddp->dst_socket = ZIP_SOCKET;
1310 NET_ASSIGN(ddp->dst_net, RouterNet);
1311 ddp->dst_node = RouterNode;
1312
1313 ddp->type = DDP_ZIP;
1314
1315 return (m);
1316} /* zip_prep_query_packet */
1317
1318
1319/*
1320 * zip_send_queries: this function send queries for the routing table entries that
1321 * need to know their zones. It scans the routing table for entries with unknown
1322 * zones and build Query packets accordingly.
1323 * Note: this is called on a per port basis.
1324 */
1325
1326void zip_send_queries(ifID, RouterNet, RouterNode)
1327 register at_ifaddr_t *ifID;
1328 at_net_al RouterNet; /* we want to send the Zip Query to that router */
1329 at_node RouterNode;
1330{
1331 RT_entry *Entry = &RT_table[0];
1332 register gbuf_t *m;
1333 register at_ddp_t *ddp;
1334 int status;
1335 short Query_index, EntryNumber = 0 ;
1336 register u_char port = ifID->ifPort;
1337 char *QueryBuff, *ZoneCount;
1338 short zip_sent = FALSE;
1339
1340newPacket:
1341
1342 if (!(m = zip_prep_query_packet(ifID, RouterNet, RouterNode))) {
1343 return; /* was return (ENOBUFS); */
1344 }
1345
1346 ddp = (at_ddp_t *)(gbuf_rptr(m));
1347 QueryBuff = (char *)ddp->data;
1348
1349 *QueryBuff++ = ZIP_QUERY;
1350 ZoneCount = QueryBuff; /* network count */
1351 *ZoneCount = 0;
1352 QueryBuff++;
1353 Query_index = 2;
1354
1355
1356 while (EntryNumber < RT_maxentry) {
1357
1358 /* scan the table, and build the packet with the right entries:
1359 * - entry in use and on the right Port
1360 * - with unknwon zones and in an active state
1361 * - talking to the right router
1362 */
1363
1364 if ((Query_index) > 2*254 +2) {
1365
1366 /* we need to send the packet now, but we can't have more than 256
1367 * requests for networks: the Netcount field is a 8bit in the zip query
1368 * packet format as defined in Inside Atalk
1369 */
1370
1371 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1372 ("zip_send_query: FULL query for %d nets on port#%d.(len=%d)\n",
1373 *ZoneCount, port, Query_index));
1374 zip_sent = TRUE;
1375
1376 gbuf_winc(m,DDP_X_HDR_SIZE + Query_index);
1377 DDPLEN_ASSIGN(ddp, DDP_X_HDR_SIZE + Query_index);
1378
1379 if ((status =
1380 ddp_router_output(m, ifID, AT_ADDR,
1381 RouterNet, RouterNode, 0))) {
1382 dPrintf(D_M_ZIP, D_L_ERROR,
1383 ("zip_send_query: ddp_router_output returns =%d\n", status));
1384 return; /* was return (status); */
1385 }
1386
1387 goto newPacket;
1388 }
1389
1390
1391 if (((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
1392 (Entry->NetStop) && (Entry->NetPort == port) &&
1393 (!RT_ALL_ZONES_KNOWN(Entry))){
1394
1395 /* we're ready to had that to our list of stuff to send */
1396
1397 if (Entry->NetStart) { /* extended net*/
1398
1399 *QueryBuff++ = (Entry->NetStart & 0xFF00) >> 8;
1400 *QueryBuff++ = (Entry->NetStart & 0x00FF);
1401
1402 }
1403 else {
1404 *QueryBuff++ = (Entry->NetStop & 0xFF00) >> 8;
1405 *QueryBuff++ = (Entry->NetStop & 0x00FF);
1406 }
1407
1408 Query_index += 2;
1409 *ZoneCount += 1;/* bump the number of network requested */
1410
1411 }
1412
1413 Entry++;
1414 EntryNumber++;
1415
1416 }
1417
1418 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1419 ("zip_send_query: query for %d nets on port#%d.(len=%d)\n",
1420 *ZoneCount, port, Query_index));
1421
1422 if (*ZoneCount) { /* non-full Query needs to be sent */
1423 zip_sent = TRUE;
1424 gbuf_winc(m,DDP_X_HDR_SIZE + Query_index);
1425 DDPLEN_ASSIGN(ddp, DDP_X_HDR_SIZE + Query_index);
1426
1427 if ((status =
1428 ddp_router_output(m, ifID, AT_ADDR,
1429 RouterNet, RouterNode, 0))) {
1430 dPrintf(D_M_ZIP, D_L_ERROR,
1431 ("zip_send_query: ddp_router_output returns =%d\n",
1432 status));
1433 return; /* was return (status); */
1434 }
1435 }
1436 else
1437 gbuf_freem(m);
1438
1439 if (!zip_sent) /* we didn't need to send anything for that port */
1440 ifID->ifZipNeedQueries = 0;
1441} /* zip_send_queries */
1442
1443/* zip_reply_received: we recieved the reply to one of our query, update the
1444 * zone bitmap and stuffs with was we received.
1445 * we receive two types of replies: non extended and extended.
1446 * For extended replies, the network count is the Total of zones for that net.
1447 */
1448
1449zip_reply_received(m, ifID, reply_type)
1450 register gbuf_t *m;
1451 register at_ifaddr_t *ifID;
1452 int reply_type;
1453{
1454 register at_nvestr_t *zname;
1455 RT_entry *Entry = &RT_table[0];
1456 register at_ddp_t *ddp;
1457 at_net_al Network;
1458 u_short payload_len, result;
1459 u_char network_count;
1460 char *PacketPtr;
1461
1462 ddp = (at_ddp_t *)gbuf_rptr(m);
1463
1464 /* access the number of nets provided in the ZIP Reply */
1465
1466 network_count = *(u_char *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 1);
1467
1468 PacketPtr = (char *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 2);
1469
1470 payload_len = DDPLEN_VALUE(ddp) - (DDP_X_HDR_SIZE + 2);
1471
1472 dPrintf(D_M_ZIP_LOW, D_L_INPUT, ("zip_reply_received from %d:%d type=%d netcount=%d\n",
1473 NET_VALUE(ddp->src_net), ddp->src_node, reply_type, network_count));
1474
1475
1476 while (payload_len > 0 && network_count >0) {
1477
1478 Network = *(at_net_al *)PacketPtr;
1479 PacketPtr += 2;
1480 zname = (at_nvestr_t *)PacketPtr;
1481 if (payload_len)
1482 payload_len = payload_len -(zname->len + 3);
1483
1484 if (zname->len <= 0) { /* not valid, we got a problem here... */
1485 dPrintf(D_M_ZIP, D_L_WARNING,
1486 ("zip_reply_received: Problem zlen=0 for net=%d from %d:%d type=%d netcnt=%d\n",
1487 Network, NET_VALUE(ddp->src_net), ddp->src_node, reply_type, network_count));
1488 payload_len =0;
1489 continue;
1490 }
1491
1492
1493 Entry = rt_blookup(Network);
1494
1495 if (Entry != NULL) {
1496
1497 if (Entry->EntryState >= RTE_STATE_SUSPECT) {
1498
1499 result = zt_add_zonename(zname);
1500
1501 if (result == ZT_MAXEDOUT) {
1502
1503 dPrintf(D_M_ZIP, D_L_ERROR,
1504 ("zip_reply_received: ZTable full from %d:%d on zone '%s'\n",
1505 NET_VALUE(ddp->src_net), ddp->src_node, zname->str));
1506 ErrorZIPoverflow = 1;
1507 return(1);
1508 }
1509
1510 zt_set_zmap(result, Entry->ZoneBitMap);
1511
1512 RT_SET_ZONE_KNOWN(Entry);
1513
1514 }
1515 else {
1516 dPrintf(D_M_ZIP, D_L_INPUT,
1517 ("zip_reply_received: entry %d-%d not updated, cause state=%d\n",
1518 Entry->NetStart, Entry->NetStop, Entry->EntryState));
1519 }
1520 }
1521 else {
1522 dPrintf(D_M_ZIP, D_L_WARNING,
1523 ("zip_reply_received: network %d not found in RT\n", Network));
1524 }
1525
1526
1527 /* now bump the PacketPtr pointer */
1528 PacketPtr += zname->len + 1;
1529 network_count--;
1530 }
1531
1532 if ((reply_type == ZIP_REPLY) && network_count > 0) {
1533 if (Entry)
1534 dPrintf(D_M_ZIP, D_L_WARNING,
1535 ("zip_reply_received: Problem decoding zone (after net:%d-%d)\n",
1536 Entry->NetStart, Entry->NetStop));
1537 ifID->ifZipNeedQueries = 1;
1538 }
1539 else {
1540 ifID->ifZipNeedQueries = 0;
1541 if (Entry)
1542 dPrintf(D_M_ZIP_LOW, D_L_INFO,
1543 ("zip_reply_received: entry %d-%d all zones known\n",
1544 Entry->NetStart, Entry->NetStop));
1545 }
1546}
1547
1548/*
1549 * zip_reply_to_getmyzone: replies to ZIP GetMyZone received from the Net
1550 */
1551
1552static void zip_reply_to_getmyzone (ifID, m)
1553 register at_ifaddr_t *ifID;
1554 register gbuf_t *m;
1555{
1556 at_atp_t *atp;
1557 register at_ddp_t *ddp;
1558 register at_ddp_t *r_ddp;
1559 register at_atp_t *r_atp;
1560 register gbuf_t *rm; /* reply message */
1561 register int size, Index, status;
1562 char *data_ptr;
1563 RT_entry *Entry;
1564 u_long ulongtmp;
1565
1566 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + 1 + ifID->ifZoneName.len;
1567 /* space for two headers and the zone name */
1568 if ((rm = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) {
1569 dPrintf(D_M_ZIP, D_L_WARNING,
1570 ("zip_reply_to_getmyzone: no buffer, port=%d\n", ifID->ifPort));
1571 return; /* was return (ENOBUFS); */
1572 }
1573 gbuf_rinc(rm,AT_WR_OFFSET);
1574 gbuf_wset(rm,size);
1575 r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1576 r_atp = (at_atp_t *)r_ddp->data;
1577
1578 ddp = (at_ddp_t *)gbuf_rptr(m);
1579 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1580 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1581 else
1582 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1583
1584 /* fill up the ddp header for reply */
1585 DDPLEN_ASSIGN(r_ddp, size);
1586 r_ddp->hopcount = r_ddp->unused = 0;
1587 UAS_ASSIGN(r_ddp->checksum, 0);
1588
1589 NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net);
1590 NET_NET(r_ddp->dst_net, ddp->src_net);
1591
1592 r_ddp->src_node = ifID->ifThisNode.s_node;
1593 r_ddp->dst_node = ddp->src_node;
1594
1595 r_ddp->dst_socket = ddp->src_socket;
1596 r_ddp->src_socket = ZIP_SOCKET;
1597 r_ddp->type = DDP_ATP;
1598
1599 /* fill up the atp header */
1600 r_atp->cmd = ATP_CMD_TRESP;
1601 r_atp->xo = 0;
1602 r_atp->eom = 1;
1603 r_atp->sts = 0;
1604 r_atp->xo_relt = 0;
1605 r_atp->bitmap = 0;
1606 UAS_UAS(r_atp->tid, atp->tid);
1607 ulongtmp = 1;
1608 ulongtmp = htonl(ulongtmp);
1609 UAL_ASSIGN(r_atp->user_bytes, ulongtmp); /* no of zones */
1610
1611 data_ptr = (char *)r_atp->data;
1612
1613 /*
1614 * fill up atp data part with the zone name if we can find it...
1615 */
1616
1617 Entry = rt_blookup(NET_VALUE(ddp->src_net));
1618 if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
1619 RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */
1620
1621 Index = zt_ent_zindex(Entry->ZoneBitMap) -1;
1622
1623 *data_ptr = ZT_table[Index].Zone.len;
1624 bcopy((caddr_t) &ZT_table[Index].Zone.str, (caddr_t) ++data_ptr,
1625 ZT_table[Index].Zone.len);
1626
1627 /* all set to send the packet back up */
1628 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1629 ("zip_reply_to_GMZ: ddp_router_output to %d:%d port %d\n",
1630 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort));
1631
1632 if ((status =
1633 ddp_router_output(rm, ifID, AT_ADDR,
1634 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) {
1635 dPrintf(D_M_ZIP, D_L_ERROR,
1636 ("zip_reply_to_GMZ: ddp_r_output returns =%d\n", status));
1637 return; /* was return (status); */
1638 }
1639 }
1640 else
1641 gbuf_freem(rm);
1642}
1643
1644/*
1645 * zip_reply_to_getzonelist: replies to ZIP GetZoneList requested from the Net
1646 */
1647
1648zip_reply_to_getzonelist (ifID, m)
1649 register at_ifaddr_t *ifID;
1650 register gbuf_t *m;
1651{
1652 at_atp_t *atp;
1653 register at_ddp_t *ddp;
1654 register at_ddp_t *r_ddp;
1655 register at_atp_t *r_atp;
1656 register gbuf_t *rm; /* reply message */
1657 register int size, status;
1658 register short Index=0, StartPoint, ZLength, PacketLen=0;
1659 u_long ulongtmp= 0;
1660 char *Reply;
1661
1662 ddp = (at_ddp_t *)gbuf_rptr(m);
1663 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1664 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1665 else
1666 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1667
1668
1669 /* space for two headers and the zone name */
1670
1671 if ((rm = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
1672 return (ENOBUFS);
1673 }
1674
1675 gbuf_rinc(rm,AT_WR_OFFSET);
1676 gbuf_wset(rm,0);
1677 r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1678 r_atp = (at_atp_t *)r_ddp->data;
1679
1680 /* fill up the ddp header for reply */
1681
1682 r_ddp->hopcount = r_ddp->unused = 0;
1683 UAS_ASSIGN(r_ddp->checksum, 0);
1684 NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net);
1685 NET_NET(r_ddp->dst_net, ddp->src_net);
1686 r_ddp->src_node = ifID->ifThisNode.s_node;
1687 r_ddp->dst_node = ddp->src_node;
1688 r_ddp->dst_socket = ddp->src_socket;
1689 r_ddp->src_socket = ZIP_SOCKET;
1690 r_ddp->type = DDP_ATP;
1691
1692 /* fill up the atp header */
1693
1694 r_atp->cmd = ATP_CMD_TRESP;
1695 r_atp->xo = 0;
1696 r_atp->eom = 1;
1697 r_atp->sts = 0;
1698 r_atp->xo_relt = 0;
1699 r_atp->bitmap = 0;
1700 UAS_UAS(r_atp->tid, atp->tid);
1701
1702 Reply = (char *)r_atp->data;
1703
1704 /* get the start index from the ATP request */
1705
1706 StartPoint = (UAL_VALUE(atp->user_bytes) & 0xffff) -1;
1707
1708 /* find the next zone to send */
1709
1710 while ((Index < ZT_maxentry) && StartPoint > 0) {
1711 if (ZT_table[Index].Zone.len)
1712 StartPoint--;
1713 Index++;
1714 }
1715
1716
1717 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT, ("zip_reply_to_GZL: Index=%d\n", Index));
1718 /*
1719 * fill up atp data part with the zone name if we can find it...
1720 */
1721
1722 while (Index < ZT_maxentry) {
1723
1724 ZLength = ZT_table[Index].Zone.len;
1725
1726 if (ZT_table[Index].ZoneCount && ZLength) {
1727
1728
1729 if (PacketLen + 8 + ZLength+1 > DDP_DATA_SIZE) /* packet full */
1730 break;
1731
1732 *Reply++ = ZLength;
1733 bcopy((caddr_t) &ZT_table[Index].Zone.str,
1734 Reply, ZLength);
1735 Reply += ZLength;
1736 PacketLen += ZLength + 1;
1737 ulongtmp++;
1738 }
1739 Index++;
1740 }
1741
1742 if (Index >= ZT_maxentry) /* this is the end of the list */
1743
1744 ulongtmp += 0x01000000;
1745
1746
1747 UAL_ASSIGN(r_atp->user_bytes, ulongtmp); /* # of zones and flag*/
1748
1749 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + PacketLen;
1750 gbuf_winc(rm,size);
1751 DDPLEN_ASSIGN(r_ddp, size);
1752
1753 /* all set to send the packet back up */
1754
1755 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1756 ("zip_r_GZL: send packet to %d:%d port %d atp_len =%d\n",
1757 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort, PacketLen));
1758
1759
1760 if (status= ddp_router_output(rm, ifID, AT_ADDR,
1761 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0)) {
1762 dPrintf(D_M_ZIP, D_L_ERROR, ("zip_reply_to_GZL: ddp_router_output returns=%d\n",
1763 status));
1764 return (status);
1765 }
1766 return (0);
1767
1768}
1769
1770/*
1771 * zip_reply_to_getlocalzones: replies to ZIP GetLocalZones requested from the Net
1772 */
1773
1774int zip_reply_to_getlocalzones (ifID, m)
1775 register at_ifaddr_t *ifID;
1776 register gbuf_t *m;
1777{
1778 at_atp_t *atp;
1779 register at_ddp_t *ddp;
1780 register at_ddp_t *r_ddp;
1781 register at_atp_t *r_atp;
1782 register gbuf_t *rm; /* reply message */
1783 int size, status;
1784 short Index, Index_wanted, ZLength;
1785 short i,j, packet_len;
1786 short zCount, ZoneCount, ZonesInPacket;
1787 char *zmap, last_flag = 0;
1788 RT_entry *Entry;
1789 char *Reply;
1790
1791 u_long ulongtmp = 0;
1792
1793 Index = Index_wanted = ZLength = i = j = packet_len = zCount = ZoneCount =
1794 ZonesInPacket = 0;
1795
1796 ddp = (at_ddp_t *)gbuf_rptr(m);
1797 if (gbuf_len(m) > DDP_X_HDR_SIZE)
1798 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE);
1799 else
1800 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m)));
1801
1802 /* space for two headers and the zone name */
1803
1804 if ((rm = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) {
1805 return (ENOBUFS);
1806 }
1807
1808 gbuf_rinc(rm,AT_WR_OFFSET);
1809 gbuf_wset(rm,0);
1810 r_ddp = (at_ddp_t *)(gbuf_rptr(rm));
1811 r_atp = (at_atp_t *)r_ddp->data;
1812
1813 Reply = (char *)r_atp->data;
1814
1815
1816 /* get the start index from the ATP request */
1817
1818 Index_wanted = (UAL_VALUE(atp->user_bytes) & 0xffff) -1;
1819
1820 dPrintf(D_M_ZIP_LOW, D_L_INFO,
1821 ("zip_r_GLZ: for station %d:%d Index_wanted = %d\n",
1822 NET_VALUE(ddp->src_net), ddp->src_node, Index_wanted));
1823
1824 Entry = rt_blookup(NET_VALUE(ddp->src_net));
1825
1826 if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
1827 RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */
1828
1829 ZoneCount = zt_ent_zcount(Entry) ;
1830
1831 dPrintf(D_M_ZIP_LOW, D_L_INFO,
1832 ("zip_reply_GLZ: for %d:%d ZoneCount=%d\n",
1833 NET_VALUE(ddp->src_net), ddp->src_node, ZoneCount));
1834
1835 zmap = &Entry->ZoneBitMap[0];
1836
1837 /*
1838 * first of all, we want to find the "first next zone" in the bitmap,
1839 * to do so, we need to scan the bitmap and add the number of valid
1840 * zones we find until we reach the next zone to be sent in the reply
1841 */
1842
1843 if (ZoneCount > Index_wanted) {
1844
1845 ZoneCount -= Index_wanted;
1846
1847 /* find the starting point in the bitmap according to index */
1848
1849 for (i = 0; Index_wanted >= 0 && i < ZT_BYTES; i++)
1850 if (zmap[i]) {
1851 if (Index_wanted < 8) {
1852 /* how many zones in the bitmap byte */
1853 for (j = 0, zCount =0; j < 8 ; j++)
1854 if ((zmap[i] << j) & 0x80)
1855 zCount++;
1856 if (Index_wanted < zCount) {
1857 for (j = 0 ; Index_wanted > 0 && j < 8 ; j++)
1858 if ((zmap[i] << j) & 0x80)
1859 Index_wanted--;
1860 break;
1861 }
1862 else
1863 Index_wanted -= zCount;
1864 }
1865 else
1866 for (j = 0 ; j < 8 ; j++)
1867 if ((zmap[i] << j) & 0x80)
1868 Index_wanted--;
1869 }
1870
1871 /*
1872 * now, we point to the begining of our next zones in the bitmap
1873 */
1874
1875 while (i < ZT_BYTES) {
1876
1877 if (zmap[i]) {
1878 for (; j < 8 ; j++)
1879 if ((zmap[i] << j) & 0x80) {
1880 Index = i*8 + j; /* get the index in ZT */
1881
1882 ZLength = ZT_table[Index].Zone.len;
1883
1884 if (ZT_table[Index].ZoneCount && ZLength) {
1885 if (packet_len + ATP_HDR_SIZE + ZLength + 1 >
1886 DDP_DATA_SIZE)
1887 goto FullPacket;
1888
1889 *Reply++ = ZLength;
1890 bcopy((caddr_t) &ZT_table[Index].Zone.str,
1891 Reply, ZLength);
1892 Reply += ZLength;
1893 packet_len += ZLength + 1;
1894 ZonesInPacket ++;
1895 dPrintf(D_M_ZIP_LOW, D_L_INFO,
1896 ("zip_reply_GLZ: add z#%d to packet (l=%d)\n",
1897 Index, packet_len));
1898 }
1899 else {
1900 dPrintf(D_M_ZIP, D_L_WARNING,
1901 ("zip_reply_GLZ: no len for index=%d\n",
1902 Index));
1903 }
1904 }
1905 }
1906 i++;
1907 j = 0;
1908 }
1909 }
1910 else /* set the "last flag" bit in the reply */
1911 last_flag = 1;
1912 }
1913 else /* set the "last flag" bit in the reply */
1914 last_flag = 1;
1915
1916FullPacket:
1917
1918 if (ZonesInPacket == ZoneCount)
1919 last_flag = 1;
1920
1921
1922 /* fill up the ddp header for reply */
1923
1924 r_ddp->hopcount = r_ddp->unused = 0;
1925 UAS_ASSIGN(r_ddp->checksum, 0);
1926
1927 NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net);
1928 NET_NET(r_ddp->dst_net, ddp->src_net);
1929
1930 r_ddp->src_node = ifID->ifThisNode.s_node;
1931 r_ddp->dst_node = ddp->src_node;
1932
1933 r_ddp->dst_socket = ddp->src_socket;
1934 r_ddp->src_socket = ZIP_SOCKET;
1935 r_ddp->type = DDP_ATP;
1936
1937 /* fill up the atp header */
1938 r_atp->cmd = ATP_CMD_TRESP;
1939 r_atp->xo = 0;
1940 r_atp->eom = 1;
1941 r_atp->sts = 0;
1942 r_atp->xo_relt = 0;
1943 r_atp->bitmap = 0;
1944 UAS_UAS(r_atp->tid, atp->tid);
1945 ulongtmp = ((last_flag << 24) & 0xFF000000) + ZonesInPacket; /* # of zones and flag*/
1946 UAL_ASSIGN(r_atp->user_bytes, ulongtmp);
1947 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + packet_len;
1948 gbuf_winc(rm,size);
1949 DDPLEN_ASSIGN(r_ddp, size);
1950
1951 /* all set to send the packet back up */
1952
1953 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT,
1954 ("zip_r_GLZ: send packet to %d:%d port %d atp_len =%d\n",
1955 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort, packet_len));
1956
1957 if (status= ddp_router_output(rm, ifID, AT_ADDR,
1958 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0)) {
1959 dPrintf(D_M_ZIP, D_L_ERROR,
1960 ("zip_reply_to_GLZ: ddp_router_output returns =%d\n",
1961 status));
1962 return (status);
1963 }
1964 return (0);
1965} /* zip_reply_to_getlocalzones */
1966
1967int regDefaultZone(ifID)
1968 at_ifaddr_t *ifID;
1969{
1970 int i;
1971 char data[ETHERNET_ADDR_LEN];
1972
1973 if (!ifID)
1974 return(-1);
1975
1976 zt_get_zmcast(ifID, &ifID->ifZoneName, data);
1977 if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type))
1978 ddp_bit_reverse(data);
1979 bcopy((caddr_t)data, (caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN);
1980 (void)at_reg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr);
1981 return(0);
1982}