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