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