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