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