2 * Copyright (c) 1988-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * 0.01 05/12/94 Laurent Dumont Creation
31 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
35 * Router ZIP protocol functions:
37 * This file contains Routing specifics to handle ZIP requests and responses
38 * sent and received by a router node.
40 * The entry point for the zip input in ddp is valid only when we're
41 * running in router mode.
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>
52 #include <sys/filedesc.h>
53 #include <sys/fcntl.h>
55 #include <sys/ioctl.h>
56 #include <sys/malloc.h>
57 #include <sys/socket.h>
58 #include <sys/socketvar.h>
61 #include <net/if_types.h>
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>
75 #include <sys/kern_event.h>
78 extern at_ifaddr_t
*ifID_table
[], *ifID_home
;
79 extern short ErrorZIPoverflow
;
81 /**********************************************************************
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.
88 **********************************************************************/
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 *);
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
);
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
*);
108 * zip_send_getnetinfo_reply: we received a GetNetInfo packet, we need to reply
109 * with the right information for the port.
111 static void zip_send_getnetinfo_reply(m
, ifID
)
113 register at_ifaddr_t
*ifID
;
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
;
124 ddp
= (at_ddp_t
*)gbuf_rptr(m
);
126 /* access the Zone Name info part of the GetNetInfo Request */
128 zname
= (at_nvestr_t
*)(gbuf_rptr(m
) + DDP_X_HDR_SIZE
+ 6);
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
)));
139 ZoneNameProvided
= TRUE
;
141 GNIReply
[0] = ZIP_NETINFO_REPLY
;
142 GNIReply
[1] = ZIP_ZONENAME_INVALID
;
144 /* check if we are the originator is in the cable range for this interface */
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
;
150 Entry
= rt_blookup(CableStop
);
152 if (Entry
!= NULL
&& RT_ALL_ZONES_KNOWN(Entry
)) { /* this net is well known... */
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);
159 /* copy the zone name found in the request */
161 GNIReply
[6] = zname
->len
;
162 bcopy(&zname
->str
, &GNIReply
[7], zname
->len
);
165 if ((znumber
= zt_find_zname(zname
))) {
167 if (ZT_ISIN_ZMAP((znumber
), Entry
->ZoneBitMap
)) {
169 GNIReply
[1] = 0; /* Zone Valid */
171 if ((len
= zt_get_zmcast(ifID
, zname
, &GNIReply
[8+zname
->len
])))
172 GNIReply
[7+zname
->len
] = len
;
174 GNIReply
[1] |= ZIP_USE_BROADCAST
;
175 GNIReply
[7+zname
->len
] = 0; /* multicast address length */
177 packet_length
= 8 + zname
->len
+ len
;
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"));
188 if (zt_ent_zcount(Entry
) == 1)
189 GNIReply
[1] |= ZIP_ONE_ZONE
;
191 if (GNIReply
[1] & ZIP_ZONENAME_INVALID
) {
193 short Index
= ifID
->ifDefZone
;
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
));
205 if ((len
= zt_get_zmcast(ifID
, &ZT_table
[Index
].Zone
, &GNIReply
[8+zname
->len
])))
206 GNIReply
[7+zname
->len
] = len
;
208 GNIReply
[1] |= ZIP_USE_BROADCAST
;
209 GNIReply
[7+zname
->len
] = 0; /* multicast address length */
212 packet_length
= 7 + zname
->len
+ len
;
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
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
;
226 * we're finally ready to send out the GetNetInfo Reply
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); */
236 gbuf_rinc(m_sent
,AT_WR_OFFSET
);
237 gbuf_wset(m_sent
,size
);
238 ddp_sent
= (at_ddp_t
*)(gbuf_rptr(m_sent
));
240 /* Prepare the DDP header */
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
;
250 if (RequestIsBroadcasted
) { /* if this was a broadcast, must respond from that */
252 NET_ASSIGN(ddp_sent
->dst_net
, 0);
253 ddp_sent
->dst_node
= 0xFF;
257 NET_NET(ddp_sent
->dst_net
, ddp
->src_net
);
258 ddp_sent
->dst_node
= ddp
->src_node
;
260 ddp_sent
->type
= DDP_ZIP
;
262 bcopy(&GNIReply
, &ddp_sent
->data
, packet_length
);
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
));
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); */
275 } /* zip_send_getnetinfo_reply */
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.
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
;
287 register gbuf_t
*m_sent
;
288 register at_ddp_t
*ddp
, *src_ddp
;
290 /* access the source Net and Node informations */
292 src_ddp
= (at_ddp_t
*)gbuf_rptr(m
);
294 if ((m_sent
= gbuf_alloc (AT_WR_OFFSET
+1024, PRI_HI
)) == NULL
) {
295 return((gbuf_t
*)NULL
);
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
));
301 /* Prepare the DDP header */
303 ddp
->unused
= ddp
->hopcount
= 0;
304 UAS_ASSIGN(ddp
->checksum
, 0);
306 NET_ASSIGN(ddp
->src_net
, ifID
->ifThisNode
.s_net
);
307 ddp
->src_node
= ifID
->ifThisNode
.s_node
;
308 ddp
->src_socket
= ZIP_SOCKET
;
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
;
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.
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 */
332 register at_ddp_t
*ddp
;
333 short i
, j
, reply_length
, Index
, zone_count
, status
;
335 char *ReplyBuff
, *ZonesInPacket
;
337 zone_count
= zt_ent_zcount(Entry
);
338 zmap
= Entry
->ZoneBitMap
;
344 if (!(m
= prep_ZIP_reply_packet (mreceived
, ifID
))) {
345 return; /* was return(ENOBUFS); */
348 ddp
= (at_ddp_t
*)(gbuf_rptr(m
));
349 ReplyBuff
= (char *)(ddp
->data
);
352 *ReplyBuff
++ = 8; /* ZIP function = 8 [extended reply] */
354 ZonesInPacket
= ReplyBuff
;
357 reply_length
= 2; /* 1st byte is ZIP reply code, 2nd is network count */
360 /* For all zones, we check if they belong to the map for that Network */
362 for (; i
>= 0; i
--) {
364 /* find the zones defined in this entry bitmap */
368 if (zmap
[i
] << j
& 0x80) { /* bingo */
370 Index
= i
*8 + j
; /* zone index in zone table */
372 if (reply_length
+ 3 + ZT_table
[Index
].Zone
.len
> DDP_DATA_SIZE
) {
374 /* we need to send the packet before, this won't fit... */
376 zone_count
-= *ZonesInPacket
;
378 DDPLEN_ASSIGN(ddp
, (reply_length
+ DDP_X_HDR_SIZE
));
379 gbuf_winc(m
,reply_length
);
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",
386 return; /* was return (status); */
392 /* this should fit in this packet, build the NetNumber, ZoneLen,
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
;
402 bcopy(&ZT_table
[Index
].Zone
.str
, ReplyBuff
,
403 ZT_table
[Index
].Zone
.len
);
405 ReplyBuff
+= ZT_table
[Index
].Zone
.len
;
406 reply_length
+= ZT_table
[Index
].Zone
.len
+3;
411 j
= 0; /* reset the bit count */
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
419 DDPLEN_ASSIGN(ddp
, (reply_length
+ DDP_X_HDR_SIZE
));
420 gbuf_winc(m
,reply_length
);
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); */
429 else /* free the buffer not used */
432 } /* zip_send_ext_reply_to_query */
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.
439 static void zip_send_reply_to_query(mreceived
, ifID
)
440 register gbuf_t
*mreceived
;
441 register at_ifaddr_t
*ifID
;
444 register at_ddp_t
*ddp
= NULL
, *ddp_received
;
446 short i
, reply_length
, Index
, status
;
447 u_char network_count
;
449 char *ReplyBuff
, *ZonesInPacket
;
451 ddp_received
= (at_ddp_t
*)gbuf_rptr(mreceived
);
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);
457 /* check the validity of the Query packet */
459 if (DDPLEN_VALUE(ddp_received
) !=
460 (2 + network_count
* 2 + DDP_X_HDR_SIZE
)) {
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); */
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.
479 if (!(m
= prep_ZIP_reply_packet (mreceived
, ifID
))) {
480 return; /* was return(ENOBUFS); */
483 ddp
= (at_ddp_t
*)(gbuf_rptr(m
));
484 ReplyBuff
= (char *)(ddp
->data
);
486 *ReplyBuff
++ = 2; /* ZIP function = 2 [Non extended reply] */
487 ZonesInPacket
= ReplyBuff
;
490 reply_length
= 2; /* 1st byte is ZIP reply code, 2nd is network count */
492 for (i
= 0 ; i
< network_count
; i
++, NetAsked
++) {
493 Entry
= rt_blookup(ntohs(*NetAsked
));
495 if (Entry
!= NULL
&& ((Entry
->EntryState
& 0x0F) >= RTE_STATE_SUSPECT
) &&
496 RT_ALL_ZONES_KNOWN(Entry
)) { /* this net is well known... */
498 if (Entry
->NetStart
== 0) { /* asking for a NON EXTENDED network */
500 if ( (Index
= zt_ent_zindex(Entry
->ZoneBitMap
)) == 0)
505 if (reply_length
+ 3 + ZT_table
[Index
].Zone
.len
> DDP_DATA_SIZE
) {
507 /* we need to send the packet before, this won't fit... */
509 DDPLEN_ASSIGN(ddp
, (reply_length
+ DDP_X_HDR_SIZE
));
510 gbuf_winc(m
,reply_length
);
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",
519 return; /* was return (status); */
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
531 /* this should fit in this packet, build the NetNumber, ZoneLen,
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
);
543 ReplyBuff
+= ZT_table
[Index
].Zone
.len
;
545 reply_length
+= ZT_table
[Index
].Zone
.len
+ 3;
552 else { /* extended network, check for multiple zone name attached
553 * and build a separate packet for each extended network requested
556 zip_send_ext_reply_to_query(mreceived
, ifID
, Entry
, ntohs(*NetAsked
));
562 /* If we have a non extended packet (code 2) with some stuff in it,
563 * we need to send it now
566 if ( reply_length
> 2) {
567 DDPLEN_ASSIGN(ddp
, (reply_length
+ DDP_X_HDR_SIZE
));
568 gbuf_winc(m
,reply_length
);
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); */
578 else /* free the buffer not used */
580 } /* zip_send_reply_to_query */
582 /***********************************************************************
585 **********************************************************************/
587 void zip_router_input (m
, ifID
)
589 register at_ifaddr_t
*ifID
;
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
;
597 /* variables for ZipNotify processing */
598 register char old_zone_len
;
599 register char new_zone_len
;
600 register char *old_zone
;
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
608 dPrintf(D_M_ZIP
, D_L_WARNING
, ("zip_router_input: not an M_DATA message\n"));
614 dPrintf(D_M_ZIP
, D_L_WARNING
, ("zip_router_input: BAD ifID\n"));
620 * The ZIP listener receives two types of requests:
622 * ATP requests: GetZoneList, GetLocalZone, or GetMyZone
623 * ZIP requests: Netinfo, Query, Reply, takedown, bringup
626 ddp
= (at_ddp_t
*)gbuf_rptr(m
);
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",
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
));
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
));
645 zip_send_reply_to_query(m
, ifID
);
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"));
656 zip_reply_received(m
, ifID
, zip
->command
);
661 /* we received a Zip Takedown packet */
662 dPrintf(D_M_ZIP
, D_L_WARNING
, ("zip_input: Received a Zip takedown!!!\n"));
667 /* we received a Zip BringUp packet */
668 dPrintf(D_M_ZIP
, D_L_WARNING
, ("zip_input: Received a Zip BringUp!!!\n"));
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
);
687 case ZIP_NETINFO_REPLY
:
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!
695 ((NET_VALUE(ddp
->src_net
) != ifID
->ifThisNode
.s_net
) ||
696 (ddp
->src_node
!= ifID
->ifThisNode
.s_node
)) && netinfo_reply_pending
)
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
);
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
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
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
;
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
);
734 /* change the zone name - copy both the length and the string */
735 bcopy((caddr_t
)new_zone
, (caddr_t
)&ifID
->ifZoneName
,
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);
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));
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.
753 ifID
->ifNumRetries
= ZIP_NETINFO_RETRIES
;
754 netinfo_reply_pending
= 1;
755 ifID
->ifGNIScheduled
= 1;
756 timeout(zip_sched_getnetinfo
, (caddr_t
) ifID
,
762 routing_needed(m
, ifID
, TRUE
);
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
);
771 atp
= (at_atp_t
*)(gbuf_rptr(gbuf_cont(m
)));
773 /* Get the user bytes in network order */
775 *((u_long
*)user_bytes
) = UAL_VALUE(atp
->user_bytes
);
776 user_byte
= user_bytes
[0]; /* Get the zeroth byte */
778 dPrintf(D_M_ZIP
, D_L_INPUT
,
779 ("zip_input: received a ZIP_ATP command=%d\n", user_byte
));
783 zip_reply_to_getmyzone(ifID
, m
);
787 case ZIP_GETZONELIST
:
788 zip_reply_to_getzonelist(ifID
, m
);
792 case ZIP_GETLOCALZONES
:
793 zip_reply_to_getlocalzones(ifID
, m
);
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
);
807 } /* zip_router_input */
809 /***********************************************************************
814 **********************************************************************/
815 int zonename_equal (zone1
, zone2
)
816 register at_nvestr_t
*zone1
, *zone2
;
818 register char c1
, c2
;
821 if (zone1
->len
!= zone2
->len
)
824 for (i
=0; i
< (int) zone1
->len
; i
++) {
827 if (c1
>= 'a' && c1
<= 'z')
829 if (c2
>= 'a' && c2
<= 'z')
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};
854 for (i
=0; lower_case
[i
]; i
++)
855 if (ch
== lower_case
[i
])
856 return (upper_case
[i
]);
862 /***********************************************************************
863 * zip_netinfo_reply ()
867 **********************************************************************/
868 static void zip_netinfo_reply (netinfo
, ifID
)
869 register at_x_zip_t
*netinfo
;
870 register at_ifaddr_t
*ifID
;
873 register at_net_al this_net
;
875 register u_char zone_name_len
;
877 /* There may be multiple zones on the cable.... we need to
878 * worry about whether or not this packet is addressed
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!!!"));
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
));
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];
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
,
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));
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.
916 /* This packet contains a multicast address, so
917 * send to elap to register it.
919 if (FDDI_OR_TOKENRING(ifID
->aa_ifp
->if_type
))
920 ddp_bit_reverse(&netinfo
->data
[zone_name_len
+ 2]);
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
);
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.
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
943 /* to reset initial_net and initial_node to zero, so
944 * that aarp is forced to choose new values
946 ifID
->initial_addr
.s_net
= 0;
947 ifID
->initial_addr
.s_node
= 0;
949 /* Wake up elap_online sleeping on this interface. */
950 ZIPwakeup(ifID
, ZIP_RE_AARP
);
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
));
960 ZIPwakeup(ifID
, 0); /* no error */
962 } /* zip_netinfo_reply */
965 /**********************************************************************
968 **********************************************************************/
969 int zip_control (ifID
, control
)
970 register at_ifaddr_t
*ifID
;
973 dPrintf(D_M_ZIP
, D_L_INFO
, ("zip_control called port=%d control=%d\n",
974 ifID
->ifPort
, control
));
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.
983 if (ifID
->startup_zone
.len
)
984 ifID
->ifZoneName
= ifID
->startup_zone
;
985 zip_getnetinfo(ifID
);
989 ifID
->ifZoneName
.len
= 1;
990 ifID
->ifZoneName
.str
[0] = '*';
991 ifID
->ifZoneName
.str
[1] = '\0';
993 /* Send event with zone info. */
994 atalk_post_msg(ifID
->aa_ifp
, KEV_ATALK_ZONEUPDATED
, 0, &(ifID
->ifZoneName
));
1003 /* locked version of zip_getnetinfo */
1005 zip_getnetinfo_locked(void *arg
)
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
);
1019 /**********************************************************************
1022 **********************************************************************/
1023 static void zip_getnetinfo (ifID
)
1024 register at_ifaddr_t
*ifID
;
1026 register at_x_zip_t
*zip
;
1028 register at_ddp_t
*ddp
;
1029 register struct atalk_addr
*at_dest
;
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.
1040 dPrintf(D_M_ZIP
, D_L_WARNING
, ("zip_getnetinfo: no buffer, call later port=%d\n",
1042 ifID
->ifGNIScheduled
= 1;
1043 timeout (zip_getnetinfo_locked
, (caddr_t
) ifID
, ZIP_TIMER_INT
/10);
1047 gbuf_rinc(m
,AT_WR_OFFSET
);
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
;
1055 zip
->command
= ZIP_GETNETINFO
;
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);
1063 zip
->data
[0] = 0; /* No zone name is availbale */
1065 /* let the lap fields be uninitialized, 'cause it doesn't
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 */
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
;
1081 at_dest
->atalk_unused
= 0;
1082 NET_NET(at_dest
->atalk_net
, ddp
->dst_net
);
1083 at_dest
->atalk_node
= ddp
->dst_node
;
1085 dPrintf(D_M_ZIP
, D_L_INPUT
, ("zip_getnetinfo: called for port=%d\n",
1088 if (elap_dataput(m
, ifID
, 0, NULL
)) {
1089 dPrintf(D_M_ZIP
, D_L_ERROR
,
1090 ("zip_getnetinfo: error sending zip_getnetinfo\n"));
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 */
1101 /**********************************************************************
1102 * zip_sched_getnetinfo()
1104 **********************************************************************/
1106 void zip_sched_getnetinfo(void *arg
)
1108 register at_ifaddr_t
*ifID
= (at_ifaddr_t
*)arg
;
1112 ifID
->ifGNIScheduled
= 0;
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
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;
1127 ifID
->ifRouterState
= NO_ROUTER
;
1128 ifID
->ifARouter
.s_net
= 0;
1129 ifID
->ifARouter
.s_node
= 0;
1131 dPrintf(D_M_ZIP
, D_L_INFO
, ("zip_sched_getnetinfo: Reset Cable Range\n"));
1133 ifID
->ifThisCableStart
= DDP_MIN_NETWORK
;
1134 ifID
->ifThisCableEnd
= DDP_MAX_NETWORK
;
1136 if (ifID
->ifState
== LAP_ONLINE_FOR_ZIP
)
1137 ZIPwakeup (ifID
, 0); /* no error */
1139 zip_getnetinfo(ifID
);
1145 /**********************************************************************
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.
1155 **********************************************************************/
1156 int zip_type_packet (m
)
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
;
1165 ddp
= (at_ddp_t
*)gbuf_rptr(m
);
1166 if (ddp
->dst_socket
== ZIP_SOCKET
) {
1167 switch (ddp
->type
) {
1169 if (gbuf_len(m
) > DDP_X_HDR_SIZE
)
1170 zip
= (at_zip_t
*)(gbuf_rptr(m
)
1173 zip
=(at_zip_t
*)(gbuf_rptr(gbuf_cont(m
)));
1174 return ((int)zip
->command
);
1176 if (gbuf_len(m
) > DDP_X_HDR_SIZE
)
1177 atp
= (at_atp_t
*)(gbuf_rptr(m
)+DDP_X_HDR_SIZE
);
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
))
1196 /**********************************************************************
1197 * zip_handle_getmyzone()
1200 * Routine to handle ZIP GetMyZone request locally. It generates
1201 * a phony response to the outgoing ATP request and sends it up.
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...
1208 **********************************************************************/
1210 int zip_handle_getmyzone(ifID
, m
)
1211 register at_ifaddr_t
*ifID
;
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 */
1222 dPrintf(D_M_ZIP
, D_L_INFO
,
1223 ("zip_handle_getmyzone: local reply for port=%d\n",
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",
1235 gbuf_rinc(rm
,AT_WR_OFFSET
);
1237 r_ddp
= (at_ddp_t
*)(gbuf_rptr(rm
));
1238 r_atp
= (at_atp_t
*)r_ddp
->data
;
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
);
1245 atp
= (at_atp_t
*)(gbuf_rptr(gbuf_cont(m
)));
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
;
1259 /* fill up the atp header */
1260 r_atp
->cmd
= ATP_CMD_TRESP
;
1266 UAS_UAS(r_atp
->tid
, atp
->tid
);
1268 UAL_ASSIGN_HTON(r_atp
->user_bytes
, ulongtmp
); /* no of zones */
1270 /* fill up atp data part */
1271 bcopy((caddr_t
) &ifID
->ifZoneName
, (caddr_t
) r_atp
->data
, ifID
->ifZoneName
.len
+1);
1273 /* all set to send the packet back up */
1275 timeout(send_phony_reply
, (caddr_t
) rm
, HZ
/20);
1280 send_phony_reply(arg
)
1283 gbuf_t
*rm
= (gbuf_t
*)arg
;
1286 ddp_input(rm
, ifID_home
);
1294 * zip_prep_query_packet: build the actual ddp packet for the zip query
1297 gbuf_t
*zip_prep_query_packet(ifID
, RouterNet
, RouterNode
)
1299 at_net_al RouterNet
; /* we want to send the Zip Query to that router */
1304 register at_ddp_t
*ddp
;
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",
1310 return((gbuf_t
*)NULL
);
1312 gbuf_rinc(m
,AT_WR_OFFSET
);
1315 ddp
= (at_ddp_t
*)(gbuf_rptr(m
));
1317 /* Prepare the DDP header */
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
;
1325 ddp
->dst_socket
= ZIP_SOCKET
;
1326 NET_ASSIGN(ddp
->dst_net
, RouterNet
);
1327 ddp
->dst_node
= RouterNode
;
1329 ddp
->type
= DDP_ZIP
;
1332 } /* zip_prep_query_packet */
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.
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 */
1347 RT_entry
*Entry
= &RT_table
[0];
1349 register at_ddp_t
*ddp
;
1351 short Query_index
, EntryNumber
= 0 ;
1352 register u_char port
= ifID
->ifPort
;
1353 char *QueryBuff
, *ZoneCount
;
1354 short zip_sent
= FALSE
;
1358 if (!(m
= zip_prep_query_packet(ifID
, RouterNet
, RouterNode
))) {
1359 return; /* was return (ENOBUFS); */
1362 ddp
= (at_ddp_t
*)(gbuf_rptr(m
));
1363 QueryBuff
= (char *)ddp
->data
;
1365 *QueryBuff
++ = ZIP_QUERY
;
1366 ZoneCount
= QueryBuff
; /* network count */
1372 while (EntryNumber
< RT_maxentry
) {
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
1380 if ((Query_index
) > 2*254 +2) {
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
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
));
1392 gbuf_winc(m
,DDP_X_HDR_SIZE
+ Query_index
);
1393 DDPLEN_ASSIGN(ddp
, (DDP_X_HDR_SIZE
+ Query_index
));
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); */
1407 if (((Entry
->EntryState
& 0x0F) >= RTE_STATE_SUSPECT
) &&
1408 (Entry
->NetStop
) && (Entry
->NetPort
== port
) &&
1409 (!RT_ALL_ZONES_KNOWN(Entry
))){
1411 /* we're ready to had that to our list of stuff to send */
1413 if (Entry
->NetStart
) { /* extended net*/
1415 *QueryBuff
++ = (Entry
->NetStart
& 0xFF00) >> 8;
1416 *QueryBuff
++ = (Entry
->NetStart
& 0x00FF);
1420 *QueryBuff
++ = (Entry
->NetStop
& 0xFF00) >> 8;
1421 *QueryBuff
++ = (Entry
->NetStop
& 0x00FF);
1425 *ZoneCount
+= 1;/* bump the number of network requested */
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
));
1438 if (*ZoneCount
) { /* non-full Query needs to be sent */
1440 gbuf_winc(m
,DDP_X_HDR_SIZE
+ Query_index
);
1441 DDPLEN_ASSIGN(ddp
, (DDP_X_HDR_SIZE
+ Query_index
));
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",
1449 return; /* was return (status); */
1455 if (!zip_sent
) /* we didn't need to send anything for that port */
1456 ifID
->ifZipNeedQueries
= 0;
1457 } /* zip_send_queries */
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.
1465 zip_reply_received(m
, ifID
, reply_type
)
1467 register at_ifaddr_t
*ifID
;
1470 register at_nvestr_t
*zname
;
1471 RT_entry
*Entry
= &RT_table
[0];
1472 register at_ddp_t
*ddp
;
1474 u_short payload_len
, result
;
1475 u_char network_count
;
1478 ddp
= (at_ddp_t
*)gbuf_rptr(m
);
1480 /* access the number of nets provided in the ZIP Reply */
1482 network_count
= ntohs(*(u_char
*)(gbuf_rptr(m
) + DDP_X_HDR_SIZE
+ 1));
1484 PacketPtr
= (char *)(gbuf_rptr(m
) + DDP_X_HDR_SIZE
+ 2);
1486 payload_len
= DDPLEN_VALUE(ddp
) - (DDP_X_HDR_SIZE
+ 2);
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
));
1492 while (payload_len
> 0 && network_count
>0) {
1494 Network
= ntohs(*(at_net_al
*)PacketPtr
);
1496 zname
= (at_nvestr_t
*)PacketPtr
;
1498 payload_len
= payload_len
-(zname
->len
+ 3);
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
));
1509 Entry
= rt_blookup(Network
);
1511 if (Entry
!= NULL
) {
1513 if (Entry
->EntryState
>= RTE_STATE_SUSPECT
) {
1515 result
= zt_add_zonename(zname
);
1517 if (result
== ZT_MAXEDOUT
) {
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;
1526 zt_set_zmap(result
, Entry
->ZoneBitMap
);
1528 RT_SET_ZONE_KNOWN(Entry
);
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
));
1538 dPrintf(D_M_ZIP
, D_L_WARNING
,
1539 ("zip_reply_received: network %d not found in RT\n", Network
));
1543 /* now bump the PacketPtr pointer */
1544 PacketPtr
+= zname
->len
+ 1;
1548 if ((reply_type
== ZIP_REPLY
) && network_count
> 0) {
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
));
1555 ifID
->ifZipNeedQueries
= 1;
1558 ifID
->ifZipNeedQueries
= 0;
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
));
1571 * zip_reply_to_getmyzone: replies to ZIP GetMyZone received from the Net
1574 static void zip_reply_to_getmyzone (ifID
, m
)
1575 register at_ifaddr_t
*ifID
;
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
;
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); */
1595 gbuf_rinc(rm
,AT_WR_OFFSET
);
1597 r_ddp
= (at_ddp_t
*)(gbuf_rptr(rm
));
1598 r_atp
= (at_atp_t
*)r_ddp
->data
;
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
);
1604 atp
= (at_atp_t
*)(gbuf_rptr(gbuf_cont(m
)));
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);
1611 NET_ASSIGN(r_ddp
->src_net
, ifID
->ifThisNode
.s_net
);
1612 NET_NET(r_ddp
->dst_net
, ddp
->src_net
);
1614 r_ddp
->src_node
= ifID
->ifThisNode
.s_node
;
1615 r_ddp
->dst_node
= ddp
->src_node
;
1617 r_ddp
->dst_socket
= ddp
->src_socket
;
1618 r_ddp
->src_socket
= ZIP_SOCKET
;
1619 r_ddp
->type
= DDP_ATP
;
1621 /* fill up the atp header */
1622 r_atp
->cmd
= ATP_CMD_TRESP
;
1628 UAS_UAS(r_atp
->tid
, atp
->tid
);
1630 UAL_ASSIGN_HTON(r_atp
->user_bytes
, ulongtmp
); /* no of zones */
1632 data_ptr
= (char *)r_atp
->data
;
1635 * fill up atp data part with the zone name if we can find it...
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... */
1642 Index
= zt_ent_zindex(Entry
->ZoneBitMap
) -1;
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
);
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
));
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); */
1666 * zip_reply_to_getzonelist: replies to ZIP GetZoneList requested from the Net
1670 zip_reply_to_getzonelist (ifID
, m
)
1671 register at_ifaddr_t
*ifID
;
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;
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
);
1688 atp
= (at_atp_t
*)(gbuf_rptr(gbuf_cont(m
)));
1691 /* space for two headers and the zone name */
1693 if ((rm
= gbuf_alloc(AT_WR_OFFSET
+1024, PRI_HI
)) == NULL
) {
1697 gbuf_rinc(rm
,AT_WR_OFFSET
);
1699 r_ddp
= (at_ddp_t
*)(gbuf_rptr(rm
));
1700 r_atp
= (at_atp_t
*)r_ddp
->data
;
1702 /* fill up the ddp header for reply */
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
;
1714 /* fill up the atp header */
1716 r_atp
->cmd
= ATP_CMD_TRESP
;
1722 UAS_UAS(r_atp
->tid
, atp
->tid
);
1724 Reply
= (char *)r_atp
->data
;
1726 /* get the start index from the ATP request */
1728 StartPoint
= (UAL_VALUE_NTOH(atp
->user_bytes
) & 0xffff) -1;
1730 /* find the next zone to send */
1732 while ((Index
< ZT_maxentry
) && StartPoint
> 0) {
1733 if (ZT_table
[Index
].Zone
.len
)
1739 dPrintf(D_M_ZIP_LOW
, D_L_OUTPUT
, ("zip_reply_to_GZL: Index=%d\n", Index
));
1741 * fill up atp data part with the zone name if we can find it...
1744 while (Index
< ZT_maxentry
) {
1746 ZLength
= ZT_table
[Index
].Zone
.len
;
1748 if (ZT_table
[Index
].ZoneCount
&& ZLength
) {
1751 if (PacketLen
+ 8 + ZLength
+1 > DDP_DATA_SIZE
) /* packet full */
1755 bcopy((caddr_t
) &ZT_table
[Index
].Zone
.str
,
1758 PacketLen
+= ZLength
+ 1;
1764 if (Index
>= ZT_maxentry
) /* this is the end of the list */
1766 ulongtmp
+= 0x01000000;
1769 UAL_ASSIGN_HTON(r_atp
->user_bytes
, ulongtmp
); /* # of zones and flag*/
1771 size
= DDP_X_HDR_SIZE
+ ATP_HDR_SIZE
+ PacketLen
;
1773 DDPLEN_ASSIGN(r_ddp
, size
);
1775 /* all set to send the packet back up */
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
));
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",
1793 * zip_reply_to_getlocalzones: replies to ZIP GetLocalZones requested from the Net
1796 int zip_reply_to_getlocalzones (ifID
, m
)
1797 register at_ifaddr_t
*ifID
;
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 */
1806 short Index
, Index_wanted
, ZLength
;
1807 short i
,j
, packet_len
;
1808 short zCount
, ZoneCount
, ZonesInPacket
;
1809 unsigned char *zmap
, last_flag
= 0;
1813 u_long ulongtmp
= 0;
1815 Index
= Index_wanted
= ZLength
= i
= j
= packet_len
= zCount
= ZoneCount
=
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
);
1822 atp
= (at_atp_t
*)(gbuf_rptr(gbuf_cont(m
)));
1824 /* space for two headers and the zone name */
1826 if ((rm
= gbuf_alloc(AT_WR_OFFSET
+1024, PRI_HI
)) == NULL
) {
1830 gbuf_rinc(rm
,AT_WR_OFFSET
);
1832 r_ddp
= (at_ddp_t
*)(gbuf_rptr(rm
));
1833 r_atp
= (at_atp_t
*)r_ddp
->data
;
1835 Reply
= (char *)r_atp
->data
;
1838 /* get the start index from the ATP request */
1840 Index_wanted
= (UAL_VALUE_NTOH(atp
->user_bytes
) & 0xffff) -1;
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
));
1846 Entry
= rt_blookup(NET_VALUE(ddp
->src_net
));
1848 if (Entry
!= NULL
&& ((Entry
->EntryState
& 0x0F) >= RTE_STATE_SUSPECT
) &&
1849 RT_ALL_ZONES_KNOWN(Entry
)) { /* this net is well known... */
1851 ZoneCount
= zt_ent_zcount(Entry
) ;
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
));
1857 zmap
= &Entry
->ZoneBitMap
[0];
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
1865 if (ZoneCount
> Index_wanted
) {
1867 ZoneCount
-= Index_wanted
;
1869 /* find the starting point in the bitmap according to index */
1871 for (i
= 0; Index_wanted
>= 0 && i
< ZT_BYTES
; 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)
1878 if (Index_wanted
< zCount
) {
1879 for (j
= 0 ; Index_wanted
> 0 && j
< 8 ; j
++)
1880 if ((zmap
[i
] << j
) & 0x80)
1885 Index_wanted
-= zCount
;
1888 for (j
= 0 ; j
< 8 ; j
++)
1889 if ((zmap
[i
] << j
) & 0x80)
1894 * now, we point to the begining of our next zones in the bitmap
1897 while (i
< ZT_BYTES
) {
1901 if ((zmap
[i
] << j
) & 0x80) {
1902 Index
= i
*8 + j
; /* get the index in ZT */
1904 ZLength
= ZT_table
[Index
].Zone
.len
;
1906 if (ZT_table
[Index
].ZoneCount
&& ZLength
) {
1907 if (packet_len
+ ATP_HDR_SIZE
+ ZLength
+ 1 >
1912 bcopy((caddr_t
) &ZT_table
[Index
].Zone
.str
,
1915 packet_len
+= ZLength
+ 1;
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
));
1922 dPrintf(D_M_ZIP
, D_L_WARNING
,
1923 ("zip_reply_GLZ: no len for index=%d\n",
1932 else /* set the "last flag" bit in the reply */
1935 else /* set the "last flag" bit in the reply */
1940 if (ZonesInPacket
== ZoneCount
)
1944 /* fill up the ddp header for reply */
1946 r_ddp
->hopcount
= r_ddp
->unused
= 0;
1947 UAS_ASSIGN(r_ddp
->checksum
, 0);
1949 NET_ASSIGN(r_ddp
->src_net
, ifID
->ifThisNode
.s_net
);
1950 NET_NET(r_ddp
->dst_net
, ddp
->src_net
);
1952 r_ddp
->src_node
= ifID
->ifThisNode
.s_node
;
1953 r_ddp
->dst_node
= ddp
->src_node
;
1955 r_ddp
->dst_socket
= ddp
->src_socket
;
1956 r_ddp
->src_socket
= ZIP_SOCKET
;
1957 r_ddp
->type
= DDP_ATP
;
1959 /* fill up the atp header */
1960 r_atp
->cmd
= ATP_CMD_TRESP
;
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
;
1971 DDPLEN_ASSIGN(r_ddp
, size
);
1973 /* all set to send the packet back up */
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
));
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",
1987 } /* zip_reply_to_getlocalzones */
1989 int regDefaultZone(ifID
)
1992 char data
[ETHERNET_ADDR_LEN
];
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
);