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