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