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