]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 1988-2007 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 A |
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. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
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> | |
2d21ac55 | 65 | #include <netat/at_pcb.h> |
1c79356b A |
66 | #include <netat/at_var.h> |
67 | #include <netat/ddp.h> | |
68 | #include <netat/nbp.h> | |
69 | #include <netat/zip.h> | |
1c79356b A |
70 | #include <netat/atp.h> |
71 | #include <netat/routing_tables.h> | |
2d21ac55 | 72 | #include <netat/rtmp.h> |
1c79356b A |
73 | #include <netat/debug.h> |
74 | ||
9bccf70c A |
75 | #include <sys/kern_event.h> |
76 | ||
1c79356b A |
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 *); | |
91447636 | 93 | static void zip_getnetinfo_locked(void *); |
55e303ae | 94 | static void send_phony_reply(void *); |
1c79356b | 95 | |
2d21ac55 A |
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 | ||
1c79356b A |
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; | |
2d21ac55 | 120 | u_short znumber, len, packet_length = 0, size, status; |
1c79356b A |
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 | ||
2d21ac55 | 165 | if ((znumber = zt_find_zname(zname))) { |
1c79356b A |
166 | |
167 | if (ZT_ISIN_ZMAP((znumber), Entry->ZoneBitMap)) { | |
168 | ||
169 | GNIReply[1] = 0; /* Zone Valid */ | |
170 | ||
2d21ac55 | 171 | if ((len = zt_get_zmcast(ifID, zname, &GNIReply[8+zname->len]))) |
1c79356b A |
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 | ||
2d21ac55 | 205 | if ((len = zt_get_zmcast(ifID, &ZT_table[Index].Zone, &GNIReply[8+zname->len]))) |
1c79356b A |
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 | ||
2d21ac55 | 378 | DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE)); |
1c79356b A |
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) { | |
2d21ac55 | 419 | DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE)); |
1c79356b A |
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; | |
2d21ac55 | 444 | register at_ddp_t *ddp = NULL, *ddp_received; |
1c79356b A |
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); | |
0c530ab8 | 455 | NetAsked = (u_short *)(ddp_received->data + 2); |
1c79356b A |
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++) { | |
0c530ab8 | 493 | Entry = rt_blookup(ntohs(*NetAsked)); |
1c79356b A |
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 | ||
2d21ac55 | 509 | DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE)); |
1c79356b A |
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 | ||
0c530ab8 | 556 | zip_send_ext_reply_to_query(mreceived, ifID, Entry, ntohs(*NetAsked)); |
1c79356b A |
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) { | |
2d21ac55 | 567 | DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE)); |
1c79356b A |
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; | |
0c530ab8 | 594 | u_char user_bytes[4]; |
1c79356b A |
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; | |
1c79356b A |
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 | { | |
1c79356b A |
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 | ||
9bccf70c A |
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 | ||
1c79356b A |
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; | |
91447636 | 755 | ifID->ifGNIScheduled = 1; |
1c79356b A |
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 | ||
0c530ab8 A |
775 | *((u_long*)user_bytes) = UAL_VALUE(atp->user_bytes); |
776 | user_byte = user_bytes[0]; /* Get the zeroth byte */ | |
1c79356b A |
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; | |
1c79356b A |
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; | |
1c79356b A |
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? *** */ | |
9bccf70c A |
882 | if (!zonename_equal((at_nvestr_t *)netinfo->data, &ifID->ifZoneName)) { |
883 | dPrintf(D_M_ZIP, D_L_INFO, ("zip_netinfo_reply, !zonename_equal!!!")); | |
1c79356b | 884 | return; |
9bccf70c | 885 | } |
1c79356b A |
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 */ | |
91447636 | 893 | ifID->ifGNIScheduled = 0; |
1c79356b A |
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 | } | |
9bccf70c A |
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 | } | |
1c79356b A |
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 : | |
91447636 A |
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 | } | |
1c79356b A |
987 | break; |
988 | case ZIP_NO_ROUTER : | |
989 | ifID->ifZoneName.len = 1; | |
990 | ifID->ifZoneName.str[0] = '*'; | |
991 | ifID->ifZoneName.str[1] = '\0'; | |
9bccf70c A |
992 | |
993 | /* Send event with zone info. */ | |
994 | atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName)); | |
995 | ||
1c79356b A |
996 | break; |
997 | default : | |
998 | break; | |
999 | } | |
1000 | return (0); | |
1001 | } | |
1002 | ||
91447636 | 1003 | /* locked version of zip_getnetinfo */ |
2d21ac55 A |
1004 | static void |
1005 | zip_getnetinfo_locked(void *arg) | |
1c79356b | 1006 | { |
91447636 A |
1007 | at_ifaddr_t *ifID; |
1008 | ||
1009 | atalk_lock(); | |
2d21ac55 | 1010 | if (arg != NULL) { // make sure it hasn't been closed |
91447636 A |
1011 | ifID = (at_ifaddr_t *)arg; |
1012 | ifID->ifGNIScheduled = 0; | |
1013 | zip_getnetinfo(ifID); | |
1014 | } | |
1015 | atalk_unlock(); | |
1c79356b A |
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; | |
1c79356b A |
1029 | register struct atalk_addr *at_dest; |
1030 | register int size; | |
91447636 | 1031 | |
1c79356b A |
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)); | |
91447636 A |
1042 | ifID->ifGNIScheduled = 1; |
1043 | timeout (zip_getnetinfo_locked, (caddr_t) ifID, ZIP_TIMER_INT/10); | |
1c79356b A |
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 | */ | |
2d21ac55 | 1068 | DDPLEN_ASSIGN(ddp, (size - (sizeof(struct atalk_addr) + 1))); |
1c79356b A |
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; | |
91447636 | 1096 | ifID->ifGNIScheduled = 1; |
1c79356b A |
1097 | timeout (zip_sched_getnetinfo, (caddr_t) ifID, ZIP_TIMER_INT); |
1098 | } /* zip_getnetinfo */ | |
1099 | ||
1100 | ||
1101 | /********************************************************************** | |
1102 | * zip_sched_getnetinfo() | |
1103 | * | |
1104 | **********************************************************************/ | |
1105 | ||
2d21ac55 | 1106 | void zip_sched_getnetinfo(void *arg) |
1c79356b | 1107 | { |
2d21ac55 | 1108 | register at_ifaddr_t *ifID = (at_ifaddr_t *)arg; |
1c79356b | 1109 | |
91447636 A |
1110 | atalk_lock(); |
1111 | ||
1112 | ifID->ifGNIScheduled = 0; | |
1c79356b A |
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 | ||
91447636 | 1141 | atalk_unlock(); |
1c79356b A |
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; | |
0c530ab8 | 1162 | u_char user_bytes[4]; |
1c79356b A |
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 */ | |
0c530ab8 A |
1181 | *((u_long*)user_bytes) = UAL_VALUE(atp->user_bytes); |
1182 | user_byte = user_bytes[0]; /* Get the zeroth byte */ | |
1c79356b A |
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; | |
0c530ab8 | 1268 | UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); /* no of zones */ |
1c79356b A |
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 | |
55e303ae A |
1280 | send_phony_reply(arg) |
1281 | void *arg; | |
1c79356b | 1282 | { |
55e303ae | 1283 | gbuf_t *rm = (gbuf_t *)arg; |
1c79356b | 1284 | |
91447636 | 1285 | atalk_lock(); |
1c79356b | 1286 | ddp_input(rm, ifID_home); |
91447636 | 1287 | atalk_unlock(); |
1c79356b | 1288 | |
1c79356b A |
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); | |
2d21ac55 | 1393 | DDPLEN_ASSIGN(ddp, (DDP_X_HDR_SIZE + Query_index)); |
1c79356b A |
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); | |
2d21ac55 | 1441 | DDPLEN_ASSIGN(ddp, (DDP_X_HDR_SIZE + Query_index)); |
1c79356b A |
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 | */ | |
2d21ac55 | 1464 | int |
1c79356b A |
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 | ||
0c530ab8 | 1482 | network_count = ntohs(*(u_char *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 1)); |
1c79356b A |
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 | ||
0c530ab8 | 1494 | Network = ntohs(*(at_net_al *)PacketPtr); |
1c79356b A |
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) { | |
2d21ac55 | 1549 | #if DEBUG |
1c79356b A |
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)); | |
2d21ac55 | 1554 | #endif |
1c79356b A |
1555 | ifID->ifZipNeedQueries = 1; |
1556 | } | |
1557 | else { | |
1558 | ifID->ifZipNeedQueries = 0; | |
2d21ac55 | 1559 | #if DEBUG |
1c79356b A |
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)); | |
2d21ac55 | 1564 | #endif |
1c79356b | 1565 | } |
2d21ac55 A |
1566 | |
1567 | return 0; | |
1c79356b A |
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; | |
0c530ab8 | 1630 | UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); /* no of zones */ |
1c79356b A |
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 | ||
2d21ac55 | 1669 | int |
1c79356b A |
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 | ||
0c530ab8 | 1728 | StartPoint = (UAL_VALUE_NTOH(atp->user_bytes) & 0xffff) -1; |
1c79356b A |
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 | ||
0c530ab8 | 1769 | UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); /* # of zones and flag*/ |
1c79356b A |
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 | ||
2d21ac55 A |
1782 | if ((status= ddp_router_output(rm, ifID, AT_ADDR, |
1783 | NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) { | |
1c79356b A |
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; | |
2d21ac55 | 1809 | unsigned char *zmap, last_flag = 0; |
1c79356b A |
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 | ||
0c530ab8 | 1840 | Index_wanted = (UAL_VALUE_NTOH(atp->user_bytes) & 0xffff) -1; |
1c79356b A |
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*/ | |
0c530ab8 | 1968 | UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); |
1c79356b A |
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 | ||
2d21ac55 A |
1979 | if ((status= ddp_router_output(rm, ifID, AT_ADDR, |
1980 | NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) { | |
1c79356b A |
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 | { | |
1c79356b A |
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)) | |
2d21ac55 | 1999 | ddp_bit_reverse((unsigned char *)data); |
1c79356b A |
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 | } |