]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/aurp_zi.c
xnu-344.21.73.tar.gz
[apple/xnu.git] / bsd / netat / aurp_zi.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * Copyright (c) 1996 Apple Computer, Inc.
27 *
28 * Created April 8, 1996 by Tuyen Nguyen
29 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
30 *
31 * File: zi.c
32 */
33#include <sys/errno.h>
34#include <sys/types.h>
35#include <sys/param.h>
36#include <machine/spl.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/proc.h>
40#include <sys/filedesc.h>
41#include <sys/fcntl.h>
42#include <sys/mbuf.h>
43#include <sys/socket.h>
44#include <sys/socketvar.h>
45#include <net/if.h>
46#include <kern/assert.h>
47
48#include <netat/sysglue.h>
49#include <netat/appletalk.h>
50#include <netat/at_var.h>
51#include <netat/routing_tables.h>
52#include <netat/at_pcb.h>
53#include <netat/aurp.h>
54#include <netat/debug.h>
55
56static int AURPgetzi(int, unsigned char *, short *, gbuf_t *, int);
57static void AURPsetzi(unsigned char, gbuf_t *, short, short);
58
59/* */
60void AURPsndZReq(state)
61 aurp_state_t *state;
62{
63 gbuf_t *m;
64 int msize;
65 aurp_hdr_t *hdrp;
66 short *net, nets_cnt, net_sent=0, entry_num=0;
67 RT_entry *entry = RT_table;
68
69 if (!state->get_zi || (state->rcv_state == AURPSTATE_Unconnected))
70 return;
71
72l_more:
73 msize = sizeof(aurp_hdr_t);
74 if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) {
75 dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndZReq: node=%d, out of mblk\n",
76 state->rem_node));
77 return;
78 }
79 gbuf_wset(m,msize);
80
81 /* construct the ZI request packet */
82 hdrp = (aurp_hdr_t *)gbuf_rptr(m);
83 hdrp->connection_id = state->rcv_connection_id;
84 hdrp->sequence_number = 0;
85 hdrp->command_code = AURPCMD_ZReq;
86 hdrp->flags = 0;
87 *(short *)(hdrp+1) = AURPSUBCODE_ZoneInfo1;
88 gbuf_winc(m,sizeof(short));
89
90 net = (short *)gbuf_wptr(m);
91 nets_cnt = 0;
92
93 while (entry_num < RT_maxentry) {
94 /*
95 * scan the router table, and build the ZI request packet
96 * with the right entries, i.e.,
97 * - entry in use and not of the net_port
98 * - with no zones and in an active state
99 * - talking to the right router
100 */
101 if ( (entry->NetPort == net_port) && entry->NetStop &&
102 ((entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) &&
103 (!RT_ALL_ZONES_KNOWN(entry)) ) {
104 *net++ = (entry->NetStart) ? entry->NetStart : entry->NetStop;
105 nets_cnt++;
106 }
107
108 if (nets_cnt >= 640) {
109 /* query only 640 networks per packet */
110 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndZReq: node=%d\n",
111 state->rem_node));
112 gbuf_winc(m,(nets_cnt * sizeof(short)));
113 AURPsend(m, AUD_AURP, state->rem_node);
114 net_sent = 1;
115 goto l_more;
116 }
117
118 entry_num++;
119 entry++;
120 }
121
122 if (nets_cnt) {
123 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndZReq: node=%d\n",
124 state->rem_node));
125 gbuf_winc(m,(nets_cnt * sizeof(short)));
126 AURPsend(m, AUD_AURP, state->rem_node);
127 net_sent = 1;
128 } else
129 gbuf_freeb(m);
130
131 if (!net_sent)
132 state->get_zi = 0;
133}
134
135/* */
136void AURPsndZRsp(state, dat_m, flag)
137 aurp_state_t *state;
138 gbuf_t *dat_m;
139 int flag;
140{
141 short len;
142 int msize, next_entry = 0;
143 gbuf_t *m;
144 aurp_hdr_t *hdrp;
145
146 if ((state->snd_state == AURPSTATE_Unconnected) || (dat_m == 0))
147 return;
148 msize = sizeof(aurp_hdr_t);
149
150 do {
151 if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) {
152 dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndZRsp: node=%d, out of mblk\n",
153 state->rem_node));
154 return;
155 }
156 gbuf_wset(m,msize);
157
158 /* construct the ZI response packet */
159 hdrp = (aurp_hdr_t *)gbuf_rptr(m);
160 hdrp->connection_id = state->snd_connection_id;
161 hdrp->sequence_number = 0;
162 hdrp->command_code = AURPCMD_ZRsp;
163 hdrp->flags = 0;
164
165 /* get zone info of the local networks */
166 next_entry = AURPgetzi(next_entry, gbuf_wptr(m), &len, dat_m, flag);
167 gbuf_winc(m,len);
168
169 /* send the packet */
170 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndZRsp: len=%d\n", len));
171 AURPsend(m, AUD_AURP, state->rem_node);
172
173 } while (next_entry);
174
175 gbuf_freem(dat_m);
176}
177
178/* */
179void AURPsndGZN(state, dat_m)
180 aurp_state_t *state;
181 gbuf_t *dat_m;
182{
183 short zname_len;
184 int msize;
185 gbuf_t *m;
186 aurp_hdr_t *hdrp;
187
188 if (state->snd_state == AURPSTATE_Unconnected)
189 return;
190
191 msize = sizeof(aurp_hdr_t);
192 if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) {
193 dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndGZN: node=%d, out of mblk\n",
194 state->rem_node));
195 return;
196 }
197 gbuf_wset(m,msize);
198
199 /* construct the GZN response packet */
200 hdrp = (aurp_hdr_t *)gbuf_rptr(m);
201 hdrp->connection_id = state->snd_connection_id;
202 hdrp->sequence_number = 0;
203 hdrp->command_code = AURPCMD_ZRsp;
204 hdrp->flags = 0;
205 *(short *)(gbuf_wptr(m)) = AURPSUBCODE_GetZoneNets;
206 gbuf_winc(m,sizeof(short));
207 zname_len = gbuf_len(dat_m);
208 bcopy(gbuf_rptr(dat_m), gbuf_wptr(m), zname_len);
209 gbuf_winc(m,zname_len);
210 *(short *)(gbuf_wptr(m)) = -1; /* number of tuples - proto not supported */
211 gbuf_winc(m,sizeof(short));
212
213 /* send the packet */
214 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndGZN: count=%d\n", -1));
215 AURPsend(m, AUD_AURP, state->rem_node);
216}
217
218/* */
219void AURPsndGDZL(state, dat_m)
220 aurp_state_t *state;
221 gbuf_t *dat_m;
222{
223 int msize;
224 gbuf_t *m;
225 aurp_hdr_t *hdrp;
226
227 if (state->snd_state == AURPSTATE_Unconnected)
228 return;
229
230 msize = sizeof(aurp_hdr_t);
231 if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) {
232 dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndGDZL: node=%d, out of mblk\n",
233 state->rem_node));
234 return;
235 }
236 gbuf_wset(m,msize);
237
238 /* construct the GDZL response packet */
239 hdrp = (aurp_hdr_t *)gbuf_rptr(m);
240 hdrp->connection_id = state->snd_connection_id;
241 hdrp->sequence_number = 0;
242 hdrp->command_code = AURPCMD_ZRsp;
243 hdrp->flags = 0;
244 *(short *)(gbuf_wptr(m)) = AURPSUBCODE_GetDomainZoneList;
245 gbuf_winc(m,sizeof(short));
246 *(short *)(gbuf_wptr(m)) = -1; /* start index - proto not supported */
247 gbuf_winc(m,sizeof(short));
248
249 /* send the packet */
250 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndGDZL: index=%d\n", -1));
251 AURPsend(m, AUD_AURP, state->rem_node);
252}
253
254/* */
255void AURPrcvZReq(state, m)
256 aurp_state_t *state;
257 gbuf_t *m;
258{
259 short sub_code;
260 aurp_hdr_t *hdrp = (aurp_hdr_t *)gbuf_rptr(m);
261
262 /* make sure we're in a valid state to accept it */
263 if (state->snd_state == AURPSTATE_Unconnected) {
264 dPrintf(D_M_AURP, D_L_WARNING, ("AURPrcvZReq: unexpected response\n"));
265 gbuf_freem(m);
266 return;
267 }
268
269 /* check for the correct connection id */
270 if (hdrp->connection_id != state->snd_connection_id) {
271 dPrintf(D_M_AURP, D_L_WARNING,
272 ("AURPrcvZReq: invalid connection id, r=%d, m=%d\n",
273 hdrp->connection_id, state->snd_connection_id));
274 gbuf_freem(m);
275 return;
276 }
277
278 gbuf_rinc(m,sizeof(*hdrp));
279 sub_code = *(short *)gbuf_rptr(m);
280 gbuf_rinc(m,sizeof(short));
281
282 dPrintf(D_M_AURP, D_L_INFO, ("AURPrcvZReq: len=%ld\n", gbuf_len(m)));
283
284 switch (sub_code) {
285 case AURPSUBCODE_ZoneInfo1:
286 AURPsndZRsp(state, m, 0);
287 return;
288
289 case AURPSUBCODE_GetZoneNets:
290 AURPsndGZN(state, m);
291 break;
292
293 case AURPSUBCODE_GetDomainZoneList:
294 AURPsndGDZL(state, m);
295 break;
296 }
297
298 gbuf_freem(m);
299}
300
301/* */
302void AURPrcvZRsp(state, m)
303 aurp_state_t *state;
304 gbuf_t *m;
305{
306 short sub_code, tuples_cnt;
307 aurp_hdr_t *hdrp = (aurp_hdr_t *)gbuf_rptr(m);
308
309 /* make sure we're in a valid state to accept it */
310 if (state->rcv_state == AURPSTATE_Unconnected) {
311 dPrintf(D_M_AURP, D_L_WARNING, ("AURPrcvZRsp: unexpected response\n"));
312 gbuf_freem(m);
313 return;
314 }
315
316 /* check for the correct connection id */
317 if (hdrp->connection_id != state->rcv_connection_id) {
318 dPrintf(D_M_AURP, D_L_WARNING,
319 ("AURPrcvZRsp: invalid connection id, r=%d, m=%d\n",
320 hdrp->connection_id, state->rcv_connection_id));
321 gbuf_freem(m);
322 return;
323 }
324
325 gbuf_rinc(m,sizeof(*hdrp));
326 sub_code = *(short *)gbuf_rptr(m);
327 gbuf_rinc(m,sizeof(short));
328
329 dPrintf(D_M_AURP, D_L_INFO, ("AURPrcvZRsp: len=%ld\n", gbuf_len(m)));
330
331 switch (sub_code) {
332 case AURPSUBCODE_ZoneInfo1:
333 case AURPSUBCODE_ZoneInfo2:
334 tuples_cnt = *(short *)gbuf_rptr(m);
335 gbuf_rinc(m,sizeof(short));
336 AURPsetzi(state->rem_node, m, sub_code, tuples_cnt);
337 break;
338
339 case AURPSUBCODE_GetZoneNets:
340 break;
341
342 case AURPSUBCODE_GetDomainZoneList:
343 break;
344 }
345
346 gbuf_freem(m);
347}
348
349/* */
350static int
351AURPgetzi(next_entry, buf, len, dat_m, flag)
352 int next_entry;
353 unsigned char *buf;
354 short *len;
355 gbuf_t *dat_m;
356 int flag;
357{
358 static int i_sav=ZT_BYTES-1, j_sav=0, idx_sav=-1;
359 unsigned char ev, zname_len, *zmap, *zname_base, *zname_sav, *tuples_ptr;
360 unsigned short net_num, *net, zname_offset;
361 short *sub_codep, *tuples_cntp, tuples_cnt, dat_len;
362 int i, j, idx, nets_cnt;
363 RT_entry *entry;
364
365 /*
366 * XXX CHS June-98: The compiler complains that some of these
367 * XXX variables may be used before they're set. I don't think
368 * XXX that's actually the case, but to check, I'll assign them
369 * XXX with some test value, and add asserts to check them at
370 * XXX run-time. The asserts won't be compiled in for production.
371 */
372 zname_sav = tuples_ptr = (unsigned char *) 0xdeadbeef; /* XXX */
373 net = (unsigned short *) 0xdeadbeef; /* XXX */
374 net_num = 0xdead; /* XXX */
375 nets_cnt = 0xfeedface; /* XXX */
376
377 sub_codep = (short *)buf;
378 buf += sizeof(short);
379 tuples_cntp = (short *)buf;
380 buf += sizeof(short);
381 *len = sizeof(short) + sizeof(short);
382 zname_base = buf + sizeof(short);
383 dat_len = 0;
384
385 /* set the subcode in the ZI response packet */
386 *sub_codep = next_entry ? AURPSUBCODE_ZoneInfo2 : AURPSUBCODE_ZoneInfo1;
387
388 switch (flag) {
389 case 0: /* zone info in response to ZI request */
390 net = (unsigned short *)gbuf_rptr(dat_m);
391 nets_cnt = (gbuf_len(dat_m))/2;
392 break;
393 case 1: /* zone info in response to Ack of RI response */
394 tuples_ptr = gbuf_rptr(dat_m);
395 nets_cnt = (gbuf_len(dat_m))/3;
396 next_entry = 0;
397 break;
398 case 2: /* zone info in response to Ack of RI update */
399 tuples_ptr = gbuf_rptr(dat_m);
400 nets_cnt = (gbuf_len(dat_m))/4;
401 next_entry = 0;
402 break;
403 }
404
405 /*
406 * for each network, find all the zones that it belongs to
407 */
408 assert(nets_cnt != 0xfeedface); /* XXX */
409 for (tuples_cnt=0; next_entry < nets_cnt; next_entry++) {
410 switch(flag) {
411 case 0:
412 assert(net != 0xdeadbeef); /* XXX */
413 net_num = net[next_entry];
414 break;
415 case 1:
416 assert(tuples_ptr != 0xdeadbeef); /* XXX */
417 net_num = *(unsigned short *)tuples_ptr;
418 tuples_ptr += 3;
419 gbuf_rinc(dat_m,3);
420 if (tuples_ptr[-1] & 0x80) {
421 tuples_ptr += 3;
422 gbuf_rinc(dat_m,3);
423 next_entry++;
424 }
425 break;
426 case 2:
427 if (gbuf_len(dat_m) <= 0) {
428 next_entry = nets_cnt;
429 goto l_done;
430 }
431 assert(tuples_ptr != 0xdeadbeef); /* XXX */
432 ev = *tuples_ptr++;
433 net_num = *(unsigned short *)tuples_ptr;
434 tuples_ptr += 3;
435 gbuf_rinc(dat_m,4);
436 if (tuples_ptr[-1] & 0x80) {
437 tuples_ptr += 2;
438 gbuf_rinc(dat_m,2);
439 }
440 if (ev != AURPEV_NetAdded)
441 continue;
442 break;
443 }
444
445 /*
446 * find the RT entry associated with the network
447 */
448 assert(net_num != 0xdead); /* XXX */
449 if ((entry = rt_blookup(net_num)) == 0) {
450 dPrintf(D_M_AURP, D_L_WARNING, ("AURPgetzi: invalid net, %d\n",
451 net_num));
452 continue;
453 }
454 if ( ((entry->EntryState & 0x0F) < RTE_STATE_SUSPECT) ||
455 !RT_ALL_ZONES_KNOWN(entry) ||
456 (entry->AURPFlag & AURP_NetHiden) ) {
457 dPrintf(D_M_AURP_LOW, D_L_INFO, ("AURPgetzi: zombie net, net=%d\n",
458 net_num));
459 continue;
460 }
461
462 if (entry->NetStart == 0) {
463 if ((idx = zt_ent_zindex(entry->ZoneBitMap)) == 0)
464 continue;
465 idx--; /* index in the zone table */
466 zname_len = ZT_table[idx].Zone.len;
467 if (zname_len) {
468 assert(net_num != 0xdead); /* XXX */
469 *(unsigned short *)buf = net_num;
470 buf += sizeof(short);
471 if (idx == idx_sav) {
472 /* use the optimized format */
473 assert(zname_sav != 0xdeadbeef); /* XXX */
474 zname_offset = zname_sav - zname_base;
475 *(unsigned short *)buf = (0x8000 | zname_offset);
476 buf += sizeof(short);
477 dat_len += 4;
478 } else {
479 /* use the long format */
480 zname_sav = buf;
481 *buf++ = zname_len;
482 bcopy(ZT_table[idx].Zone.str, buf, zname_len);
483 buf += zname_len;
484 dat_len += (3 + zname_len);
485 }
486 tuples_cnt++;
487 idx_sav = idx;
488 }
489
490 } else {
491 zmap = entry->ZoneBitMap;
492 for (i=i_sav; i >=0; i--) {
493 if (!zmap[i])
494 continue;
495
496 for (j=j_sav; j < 8; j++) {
497 if (!((zmap[i] << j) & 0x80))
498 continue;
499
500 idx = i*8 + j; /* index in the zone table */
501 zname_len = ZT_table[idx].Zone.len;
502 if (zname_len) {
503 if ((dat_len+3+zname_len) > AURP_MaxPktSize) {
504 i_sav = i;
505 j_sav = j;
506 goto l_done;
507 }
508
509 assert(net_num != 0xdead); /* XXX */
510 *(unsigned short *)buf = net_num;
511 buf += sizeof(short);
512 if (idx == idx_sav) {
513 /* use the optimized format */
514 assert(zname_sav != 0xdeadbeef);/*XXX*/
515 zname_offset = zname_sav - zname_base;
516 *(unsigned short *)buf = (0x8000 | zname_offset);
517 buf += sizeof(short);
518 dat_len += 4;
519 } else {
520 /* use the long format */
521 zname_sav = buf;
522 *buf++ = zname_len;
523 bcopy(ZT_table[idx].Zone.str, buf, zname_len);
524 buf += zname_len;
525 dat_len += (3 + zname_len);
526 }
527 tuples_cnt++;
528 idx_sav = idx;
529 }
530 }
531 }
532 }
533 if ((dat_len+3+32) > AURP_MaxPktSize) {
534 next_entry++;
535 break;
536 }
537 }
538 i_sav = ZT_BYTES-1;
539 j_sav = 0;
540
541l_done:
542 *len += dat_len;
543 if (next_entry == nets_cnt)
544 next_entry = 0;
545
546 /* set the subcode in the ZI response packet */
547 if (next_entry)
548 *sub_codep = AURPSUBCODE_ZoneInfo2;
549
550 /* set the tuples count in the ZI response packet */
551 *tuples_cntp = tuples_cnt;
552
553 idx_sav = -1;
554 return next_entry;
555}
556
557/* */
558static void
559AURPsetzi(node, m, sub_code, tuples_cnt)
560 unsigned char node;
561 gbuf_t *m;
562 short sub_code;
563 short tuples_cnt;
564{
565 int rc, tuple_fmt;
566 unsigned short net_num, zname_offset;
567 unsigned char *buf = gbuf_rptr(m), *zname_base;
568 RT_entry *entry;
569 at_nvestr_t *zname;
570
571 /* compute the base of the zone names of the optimized tuples */
572 zname_base = buf + sizeof(short);
573
574 /* process all tuples */
575 while (tuples_cnt-- > 0) {
576 net_num = *(unsigned short *)buf;
577 buf += sizeof(short);
578 if (*buf & 0x80) {
579 /* optimized-format tuple */
580 zname_offset = (*(unsigned short *)buf) & 0x7fff;
581 buf += sizeof(short);
582 zname = (at_nvestr_t *)(zname_base + zname_offset);
583 tuple_fmt = 0;
584 dPrintf(D_M_AURP_LOW, D_L_INFO,
585 ("AURPsetzi: optimized fmt, net=%d. zlen=%d, zoffset=%d\n ",
586 net_num, zname->len, zname_offset));
587 } else {
588 /* long-format tuple */
589 zname = (at_nvestr_t *)buf;
590 tuple_fmt = 1;
591 dPrintf(D_M_AURP_LOW, D_L_INFO,
592 ("AURPsetzi: long fmt, net=%d, zlen=%d\n ",
593 net_num, zname->len));
594 }
595
596 /*
597 * find the RT entry associated with the specified network
598 */
599 if ((entry = rt_blookup(net_num)) == 0) {
600 dPrintf(D_M_AURP, D_L_WARNING,
601 ("AURPsetzi: invalid net, net=%d\n", net_num));
602 } else { /* entry found */
603 if (entry->EntryState >= RTE_STATE_SUSPECT) {
604 if ((rc = zt_add_zonename(zname)) == ZT_MAXEDOUT) {
605 dPrintf(D_M_AURP, D_L_WARNING,
606 ("AURPsetzi: ZT_table full\n"));
607 } else {
608 zt_set_zmap(rc, entry->ZoneBitMap);
609 RT_SET_ZONE_KNOWN(entry);
610 }
611 }
612 }
613 if (tuple_fmt)
614 buf += zname->len+1;
615 }
616}