xref: /csrg-svn/sys/netccitt/pk_input.c (revision 45297)
1 /*
2  * Copyright (c) University of British Columbia, 1984
3  * Copyright (c) 1990 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Laboratory for Computation Vision and the Computer Science Department
8  * of the University of British Columbia.
9  *
10  * %sccs.include.redist.c%
11  *
12  *	@(#)pk_input.c	7.6 (Berkeley) 10/04/90
13  */
14 
15 #include "param.h"
16 #include "systm.h"
17 #include "mbuf.h"
18 #include "socket.h"
19 #include "protosw.h"
20 #include "socketvar.h"
21 #include "errno.h"
22 
23 #include "../net/if.h"
24 
25 #include "x25.h"
26 #include "pk.h"
27 #include "pk_var.h"
28 
29 /*
30  *  This procedure is called by the link level whenever the link
31  *  becomes operational, is reset, or when the link goes down.
32  */
33 
34 pk_ctlinput (code, xcp)
35 register struct x25config *xcp;
36 {
37 
38 	register struct pkcb *pkp;
39 
40 	for (pkp = pkcbhead; pkp; pkp = pkp -> pk_next)
41 		if (pkp -> pk_xcp == xcp)
42 			break;
43 
44 	if (pkp == 0)
45 		return (EINVAL);
46 
47 	switch (code) {
48 	case PRC_LINKUP:
49 		if (pkp -> pk_state == DTE_WAITING)
50 			pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION);
51 		break;
52 
53 	case PRC_LINKDOWN:
54 		pk_restart (pkp, -1);	/* Clear all active circuits */
55 		pkp -> pk_state = DTE_WAITING;
56 		break;
57 
58 	case PRC_LINKRESET:
59 		pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION);
60 		break;
61 
62 	}
63 	return (0);
64 }
65 struct ifqueue pkintrq;
66 /*
67  * This routine is called if there are semi-smart devices that do HDLC
68  * in hardware and want to queue the packet and call level 3 directly
69  */
70 pkintr ()
71 {
72 	register struct mbuf *m;
73 	register struct ifaddr *ifa;
74 	register struct ifnet *ifp;
75 	register int s;
76 
77 	for (;;) {
78 		s = splimp ();
79 		IF_DEQUEUE (&pkintrq, m);
80 		splx (s);
81 		if (m == 0)
82 			break;
83 		if (m->m_len < PKHEADERLN) {
84 			printf ("pkintr: packet too short (len=%d)\n",
85 				m->m_len);
86 			m_freem (m);
87 			continue;
88 		}
89 		if ((m->m_flags & M_PKTHDR) == 0)
90 			panic("pkintr");
91 		ifp = m->m_pkthdr.rcvif;
92 		/*
93 		 * look up the appropriate control block
94 		 */
95 		for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
96 			if (ifa->ifa_addr->sa_family == AF_CCITT)
97 				break;
98 		if (ifa == 0)
99 			continue;
100 		pk_input(m, ((struct x25_ifaddr *)ifa)->ia_xcp);
101 	}
102 }
103 struct mbuf *pk_bad_packet;
104 /*
105  *  X.25 PACKET INPUT
106  *
107  *  This procedure is called by a link level procedure whenever
108  *  an information frame is received. It decodes the packet and
109  *  demultiplexes based on the logical channel number.
110  *
111  */
112 
113 pk_input (m, xcp)
114 register struct mbuf *m;
115 struct x25config *xcp;
116 {
117 	register struct x25_packet *xp;
118 	register struct pklcd *lcp;
119 	register struct socket *so = 0;
120 	register struct pkcb *pkp;
121 	int  ptype, lcn, lcdstate = LISTEN;
122 	static struct x25config *lastxcp;
123 	static struct pkcb *lastpkp;
124 
125 	if (xcp == lastxcp)
126 		pkp = lastpkp;
127 	else {
128 		for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
129 			if (pkp == 0) {
130 				pk_message (0, xcp, "pk_input: unknown network");
131 				m_freem (m);
132 				return;
133 			}
134 			if (pkp -> pk_xcp == xcp)
135 				break;
136 		}
137 		lastxcp = xcp;
138 		lastpkp = pkp;
139 	}
140 
141 	xp = mtod (m, struct x25_packet *);
142 	ptype = pk_decode (xp);
143 	lcn = xp -> logical_channel_number;
144 	lcp = pkp -> pk_chan[lcn];
145 
146 	/*
147 	 *  If the DTE is in Restart  state, then it will ignore data,
148 	 *  interrupt, call setup and clearing, flow control and reset
149 	 *  packets.
150 	 */
151 	if (lcn < 0 || lcn > pkp -> pk_maxlcn) {
152 		pk_message (lcn, pkp -> pk_xcp, "illegal lcn");
153 		m_freem (m);
154 		return;
155 	}
156 
157 	pk_trace (pkp -> pk_xcp, xp, "P-In");
158 
159 	if (pkp -> pk_state != DTE_READY && ptype != RESTART && ptype != RESTART_CONF) {
160 		m_freem (m);
161 		return;
162 	}
163 	if (lcp) {
164 		so = lcp -> lcd_so;
165 		lcdstate = lcp -> lcd_state;
166 	} else {
167 		if (ptype == CLEAR) {	/* idle line probe (Datapac specific) */
168 			/* send response on lcd 0's output queue */
169 			lcp -> lcd_template = pk_template (lcn, X25_CLEAR_CONFIRM);
170 			pk_output (lcp);
171 			m_freem (m);
172 			return;
173 		}
174 		if (ptype != CALL)
175 			ptype = INVALID_PACKET;
176 	}
177 
178 	if (lcn == 0 && ptype != RESTART && ptype != RESTART_CONF) {
179 		pk_message (0, pkp -> pk_xcp, "illegal ptype (%d, %s) on lcn 0",
180 			ptype, pk_name[ptype / MAXSTATES]);
181 		if (pk_bad_packet)
182 			m_freem (pk_bad_packet);
183 		pk_bad_packet = m;
184 		return;
185 	}
186 
187 	switch (ptype + lcdstate) {
188 	/*
189 	 *  Incoming Call packet received.
190 	 */
191 	case CALL + LISTEN:
192 		incoming_call (pkp, xp, m -> m_len);
193 		break;
194 
195 	/*
196 	 *  Call collision: Just throw this "incoming call" away since
197 	 *  the DCE will ignore it anyway.
198 	 */
199 	case CALL + SENT_CALL:
200 		pk_message ((int)xp -> logical_channel_number, pkp -> pk_xcp,
201 			"incoming call collision");
202 		break;
203 
204 	/*
205 	 *  Call confirmation packet received. This usually means our
206 	 *  previous connect request is now complete.
207 	 */
208 	case CALL_ACCEPTED + SENT_CALL:
209 		call_accepted (lcp, xp, m -> m_len);
210 		break;
211 
212 	/*
213 	 *  This condition can only happen if the previous state was
214 	 *  SENT_CALL. Just ignore the packet, eventually a clear
215 	 *  confirmation should arrive.
216 	 */
217 	case CALL_ACCEPTED + SENT_CLEAR:
218 		break;
219 
220 	/*
221 	 *  Clear packet received. This requires a complete tear down
222 	 *  of the virtual circuit.  Free buffers and control blocks.
223 	 *  and send a clear confirmation.
224 	 */
225 	case CLEAR + READY:
226 	case CLEAR + RECEIVED_CALL:
227 	case CLEAR + SENT_CALL:
228 	case CLEAR + DATA_TRANSFER:
229 		lcp -> lcd_state = RECEIVED_CLEAR;
230 		lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CLEAR_CONFIRM);
231 		pk_output (lcp);
232 		pk_clearcause (pkp, xp);
233 		pk_close (lcp);
234 		break;
235 
236 	/*
237 	 *  Clear collision: Treat this clear packet as a confirmation.
238 	 */
239 	case CLEAR + SENT_CLEAR:
240 		pk_close (lcp);
241 		break;
242 
243 	/*
244 	 *  Clear confirmation received. This usually means the virtual
245 	 *  circuit is now completely removed.
246 	 */
247 	case CLEAR_CONF + SENT_CLEAR:
248 		pk_close (lcp);
249 		break;
250 
251 	/*
252 	 *  A clear confirmation on an unassigned logical channel - just
253 	 *  ignore it. Note: All other packets on an unassigned channel
254 	 *  results in a clear.
255 	 */
256 	case CLEAR_CONF + READY:
257 		break;
258 
259 	/*
260 	 *  Data packet received. Pass on to next level. Move the Q and M
261 	 *  bits into the data portion for the next level.
262 	 */
263 	case DATA + DATA_TRANSFER:
264 		if (lcp -> lcd_reset_condition) {
265 			ptype = DELETE_PACKET;
266 			break;
267 		}
268 
269 		/*
270 		 *  Process the P(S) flow control information in this Data packet.
271 		 *  Check that the packets arrive in the correct sequence and that
272 		 *  they are within the "lcd_input_window". Input window rotation is
273 		 *  initiated by the receive interface.
274 		 */
275 
276 		if (PS(xp) != ((lcp -> lcd_rsn + 1) % MODULUS) ||
277 			PS(xp) == ((lcp -> lcd_input_window + lcp->lcd_windowsize) % MODULUS)) {
278 			m_freem (m);
279 			pk_procerror (RESET, lcp, "p(s) flow control error");
280 			break;
281 		}
282 		lcp -> lcd_rsn = PS(xp);
283 
284 		if (pk_ack (lcp, PR(xp)) != PACKET_OK) {
285 			m_freem (m);
286 			break;
287 		}
288 		if (so == 0)
289 			break;
290 		m -> m_data += PKHEADERLN;
291 		m -> m_len -= PKHEADERLN;
292 		if (lcp -> lcd_flags & X25_MQBIT) {
293 			octet *t;
294 
295 			m -> m_data -= 1;
296 			m -> m_len += 1;
297 			t = mtod (m, octet *);
298 			*t = 0x00;
299 			if (xp -> q_bit)
300 				*t |= 0x80;
301 			if (MBIT(xp))
302 				*t |= 0x40;
303 		}
304 
305 		/*
306 		 * Discard Q-BIT packets if the application
307 		 * doesn't want to be informed of M and Q bit status
308 		 */
309 		if (xp -> q_bit && (lcp -> lcd_flags & X25_MQBIT) == 0) {
310 			m_freem (m);
311 			lcp -> lcd_rxcnt++;
312 			/*
313 			 * NB.  This is dangerous: sending a RR here can
314 			 * cause sequence number errors if a previous data
315 			 * packet has not yet been passed up to the application
316 			 * (RR's are normally generated via PRU_RCVD).
317 			 */
318 			lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RR);
319 			pk_output (lcp);
320 		} else {
321 #ifdef BSD4_3
322 			sbappendrecord (&so -> so_rcv, m);
323 #else
324 			sbappend (&so -> so_rcv, m);
325 #endif
326 			sorwakeup (so);
327 		}
328 		break;
329 
330 	/*
331 	 *  Interrupt packet received.
332 	 */
333 	case INTERRUPT + DATA_TRANSFER:
334 		if (lcp -> lcd_reset_condition)
335 			break;
336 		lcp -> lcd_intrdata = xp -> packet_data;
337 		lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT_CONFIRM);
338 		pk_output (lcp);
339 		MCHTYPE(m, MT_OOBDATA);
340 		if (so)
341 			sohasoutofband (so);
342 		break;
343 
344 	/*
345 	 *  Interrupt confirmation packet received.
346 	 */
347 	case INTERRUPT_CONF + DATA_TRANSFER:
348 		if (lcp -> lcd_reset_condition)
349 			break;
350 		if (lcp -> lcd_intrconf_pending == TRUE)
351 			lcp -> lcd_intrconf_pending = FALSE;
352 		else
353 			pk_procerror (RESET, lcp, "unexpected packet");
354 		MCHTYPE(m, MT_CONTROL);
355 		break;
356 
357 	/*
358 	 *  Receiver ready received. Rotate the output window and output
359 	 *  any data packets waiting transmission.
360 	 */
361 	case RR + DATA_TRANSFER:
362 		if (lcp -> lcd_reset_condition ||
363 		    pk_ack (lcp, PR(xp)) != PACKET_OK) {
364 			ptype = DELETE_PACKET;
365 			break;
366 		}
367 		if (lcp -> lcd_rnr_condition == TRUE)
368 			lcp -> lcd_rnr_condition = FALSE;
369 		pk_output (lcp);
370 		MCHTYPE(m, MT_CONTROL);
371 		break;
372 
373 	/*
374 	 *  Receiver Not Ready received. Packets up to the P(R) can be
375 	 *  be sent. Condition is cleared with a RR.
376 	 */
377 	case RNR + DATA_TRANSFER:
378 		if (lcp -> lcd_reset_condition ||
379 		    pk_ack (lcp, PR(xp)) != PACKET_OK) {
380 			ptype = DELETE_PACKET;
381 			break;
382 		}
383 		lcp -> lcd_rnr_condition = TRUE;
384 		MCHTYPE(m, MT_CONTROL);
385 		break;
386 
387 	/*
388 	 *  Reset packet received. Set state to FLOW_OPEN.  The Input and
389 	 *  Output window edges ar set to zero. Both the send and receive
390 	 *  numbers are reset. A confirmation is returned.
391 	 */
392 	case RESET + DATA_TRANSFER:
393 		if (lcp -> lcd_reset_condition)
394 			/* Reset collision. Just ignore packet. */
395 			break;
396 
397 		pk_resetcause (pkp, xp);
398 		lcp -> lcd_window_condition = lcp -> lcd_rnr_condition =
399 			lcp -> lcd_intrconf_pending = FALSE;
400 		lcp -> lcd_output_window = lcp -> lcd_input_window =
401 			lcp -> lcd_last_transmitted_pr = 0;
402 		lcp -> lcd_ssn = 0;
403 		lcp -> lcd_rsn = MODULUS - 1;
404 
405 		lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET_CONFIRM);
406 		pk_output (lcp);
407 
408 		MCHTYPE(m, MT_CONTROL);
409 		if (so == 0)
410 			break;
411 		sbflush (&so -> so_snd);
412 		sbflush (&so -> so_rcv);
413 		wakeup ((caddr_t) & so -> so_timeo);
414 		sorwakeup (so);
415 		sowwakeup (so);
416 		break;
417 
418 	/*
419 	 *  Reset confirmation received.
420 	 */
421 	case RESET_CONF + DATA_TRANSFER:
422 		if (lcp -> lcd_reset_condition) {
423 			lcp -> lcd_reset_condition = FALSE;
424 			pk_output (lcp);
425 		}
426 		else
427 			pk_procerror (RESET, lcp, "unexpected packet");
428 		MCHTYPE(m, MT_CONTROL);
429 		break;
430 
431 	case DATA + SENT_CLEAR:
432 		ptype = DELETE_PACKET;
433 	case RR + SENT_CLEAR:
434 	case RNR + SENT_CLEAR:
435 	case INTERRUPT + SENT_CLEAR:
436 	case INTERRUPT_CONF + SENT_CLEAR:
437 	case RESET + SENT_CLEAR:
438 	case RESET_CONF + SENT_CLEAR:
439 		/* Just ignore p if we have sent a CLEAR already.
440 		   */
441 		break;
442 
443 	/*
444 	 *  Restart sets all the permanent virtual circuits to the "Data
445 	 *  Transfer" stae and  all the switched virtual circuits to the
446 	 *  "Ready" state.
447 	 */
448 	case RESTART + READY:
449 		switch (pkp -> pk_state) {
450 		case DTE_SENT_RESTART:
451 			/* Restart collision. */
452 			pkp -> pk_state = DTE_READY;
453 			pk_message (0, pkp -> pk_xcp,
454 				"Packet level operational");
455 			break;
456 
457 		default:
458 			pk_restart (pkp, -1);
459 			pk_restartcause (pkp, xp);
460 			pkp -> pk_chan[0] -> lcd_template = pk_template (0,
461 				X25_RESTART_CONFIRM);
462 			pk_output (pkp -> pk_chan[0]);
463 		}
464 		break;
465 
466 	/*
467 	 *  Restart confirmation received. All logical channels are set
468 	 *  to READY.
469 	 */
470 	case RESTART_CONF + READY:
471 		switch (pkp -> pk_state) {
472 		case DTE_SENT_RESTART:
473 			pkp -> pk_state = DTE_READY;
474 			pk_message (0, pkp -> pk_xcp,
475 				"Packet level operational");
476 			break;
477 
478 		default:
479 			/* Restart local procedure error. */
480 			pk_restart (pkp, X25_RESTART_LOCAL_PROCEDURE_ERROR);
481 			pkp -> pk_state = DTE_SENT_RESTART;
482 		}
483 		break;
484 
485 	default:
486 		if (lcp) {
487 			pk_procerror (CLEAR, lcp, "unknown packet error");
488 			pk_message (lcn, pkp -> pk_xcp,
489 				"\"%s\" unexpected in \"%s\" state",
490 				pk_name[ptype/MAXSTATES], pk_state[lcdstate]);
491 		}
492 		else	/* Packets arrived on an unassigned channel.
493 			*/
494 			pk_message ((int)xp->logical_channel_number, pkp -> pk_xcp,
495 				"packet arrived on unassigned lcn");
496 		break;
497 	}
498 	if (so == 0 && lcdstate == DATA_TRANSFER && lcp -> lcd_upper)
499 		lcp -> lcd_upper (lcp, m);
500 	else if (ptype != DATA)
501 		m_freem (m);
502 }
503 
504 
505 /*
506  * This routine handles incoming call packets. It matches the protocol
507  * field on the Call User Data field (usually the first four bytes) with
508  * sockets awaiting connections.
509  */
510 
511 static
512 incoming_call (pkp, xp, len)
513 struct pkcb *pkp;
514 struct x25_packet *xp;
515 {
516 	register struct pklcd *lcp = 0, *l;
517 	register struct sockaddr_x25 *sa;
518 	register struct x25_calladdr *a;
519 	register struct socket *so = 0;
520 	struct mbuf *m;
521 	register int l1, l2;
522 	char *e, *errstr = "server unavailable";
523 	octet *u;
524 	int lcn = xp -> logical_channel_number;
525 
526 	/* First, copy the data from the incoming call packet to a X25_socket
527 	   descriptor. */
528 
529 	a = (struct x25_calladdr *) &xp -> packet_data;
530 	l1 = a -> calling_addrlen;
531 	l2 = a -> called_addrlen;
532 	if ((m = m_getclr (M_DONTWAIT, MT_SONAME)) == 0)
533 		return;
534 	sa = mtod (m, struct sockaddr_x25 *);
535 	u = (octet *) (a -> address_field + l2 / 2);
536 	e = sa -> x25_addr;
537 	if (l2 & 0x01) {
538 		*e++ = *u++ & 0x0f;
539 		l1--;
540 	}
541 	from_bcd (e, &u, l1);
542 	if (l1 & 0x01)
543 		u++;
544 
545 	parse_facilities (u, sa);
546 	u += *u + 1;
547 	sa -> x25_udlen = min (16, ((octet *)xp) + len - u);
548 	if (sa -> x25_udlen < 0)
549 		sa -> x25_udlen = 0;
550 	bcopy ((caddr_t)u, sa -> x25_udata, (unsigned)sa -> x25_udlen);
551 
552 	/*
553 	 * Now, loop through the  listen sockets looking for a match on the
554 	 * PID. That is  the first  four octets  of the user data field.  This
555 	 * is the closest thing to a port number for X.25 packets. What it
556 	 * does provide is away of  multiplexing  services at the user level.
557 	 */
558 
559 	for (l = pk_listenhead; l; l = l -> lcd_listen) {
560 		struct sockaddr_x25 *sxp = l -> lcd_ceaddr;
561 
562 		if (bcmp (sxp -> x25_udata, sa -> x25_udata, sxp->x25_udlen))
563 			continue;
564 		if (sxp -> x25_net &&
565 		    sxp -> x25_net != pkp->pk_xc.xc_addr.x25_net)
566 			continue;
567 		/*
568 		 * don't accept incoming collect calls unless
569 		 * the server sets the reverse charging option.
570 		 */
571 		if ((sxp -> x25_opts.op_flags & (X25_OLDSOCKADDR|X25_REVERSE_CHARGE)) == 0 &&
572 			sa -> x25_opts.op_flags & X25_REVERSE_CHARGE) {
573 			errstr = "incoming collect call refused";
574 			break;
575 		}
576 		if (l -> lcd_so) {
577 			if (so = sonewconn (l -> lcd_so, SS_ISCONNECTED))
578 				    lcp = (struct pklcd *) so -> so_pcb;
579 		} else
580 			lcp = pk_attach((struct socket *) 0);
581 		if (lcp == 0) {
582 			/*
583 			 * Insufficient space or too many unaccepted
584 			 * connections.  Just throw the call away.
585 			 */
586 			errstr = "server malfunction";
587 			break;
588 		}
589 		lcp -> lcd_upper = l -> lcd_upper;
590 		lcp -> lcd_upnext = l -> lcd_upnext;
591 		lcp -> lcd_lcn = lcn;
592 		lcp -> lcd_state = RECEIVED_CALL;
593 		lcp -> lcd_craddr = sa;
594 		sa -> x25_opts.op_flags |= sxp -> x25_opts.op_flags &
595 			~X25_REVERSE_CHARGE;
596 		pk_assoc (pkp, lcp, sa);
597 		lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL_ACCEPTED);
598 		if (so) {
599 			pk_output (lcp);
600 			soisconnected (so);
601 		} else if (lcp->lcd_upper)
602 			(*lcp->lcd_upper)(lcp, m);
603 		return;
604 	}
605 
606 	/*
607 	 * If the call fails for whatever reason, we still need to build a
608 	 * skeleton LCD in order to be able to properly  receive the CLEAR
609 	 * CONFIRMATION.
610 	 */
611 #ifdef WATERLOO		/* be explicit */
612 	if (l == 0 && bcmp(sa->x25_udata, "ean", 3) == 0)
613 		pk_message (lcn, pkp -> pk_xcp, "host=%s ean%c: %s",
614 			sa->x25_addr, sa->x25_udata[3] & 0xff, errstr);
615 	else if (l == 0 && bcmp(sa->x25_udata, "\1\0\0\0", 4) == 0)
616 		pk_message (lcn, pkp -> pk_xcp, "host=%s x29d: %s",
617 			sa->x25_addr, errstr);
618 	else
619 #endif
620 	pk_message (lcn, pkp -> pk_xcp, "host=%s pid=%x %x %x %x: %s",
621 		sa -> x25_addr, sa -> x25_udata[0] & 0xff,
622 		sa -> x25_udata[1] & 0xff, sa -> x25_udata[2] & 0xff,
623 		sa -> x25_udata[3] & 0xff, errstr);
624 	if ((lcp = pk_attach((struct socket *)0)) == 0) {
625 		(void) m_free (m);
626 		return;
627 	}
628 	lcp -> lcd_lcn = lcn;
629 	lcp -> lcd_state = RECEIVED_CALL;
630 	pk_assoc (pkp, lcp, sa);
631 	(void) m_free (m);
632 	pk_clear (lcp);
633 }
634 
635 static
636 call_accepted (lcp, xp, len)
637 struct pklcd *lcp;
638 struct x25_packet *xp;
639 {
640 	register struct x25_calladdr *ap;
641 	register octet *fcp;
642 
643 	lcp -> lcd_state = DATA_TRANSFER;
644 	if (lcp -> lcd_so)
645 		soisconnected (lcp -> lcd_so);
646 	if (len > 3) {
647 		ap = (struct x25_calladdr *) &xp -> packet_data;
648 		fcp = (octet *) ap -> address_field + (ap -> calling_addrlen +
649 			ap -> called_addrlen + 1) / 2;
650 		if (fcp + *fcp <= ((octet *)xp) + len)
651 			parse_facilities (fcp, lcp -> lcd_ceaddr);
652 	}
653 	pk_assoc (lcp -> lcd_pkp, lcp, lcp -> lcd_ceaddr);
654 }
655 
656 static
657 parse_facilities (fcp, sa)
658 register octet *fcp;
659 register struct sockaddr_x25 *sa;
660 {
661 	register octet *maxfcp;
662 
663 	maxfcp = fcp + *fcp;
664 	fcp++;
665 	while (fcp < maxfcp) {
666 		/*
667 		 * Ignore national DCE or DTE facilities
668 		 */
669 		if (*fcp == 0 || *fcp == 0xff)
670 			break;
671 		switch (*fcp) {
672 		case FACILITIES_WINDOWSIZE:
673 			sa -> x25_opts.op_wsize = fcp[1];
674 			fcp += 3;
675 			break;
676 
677 		case FACILITIES_PACKETSIZE:
678 			sa -> x25_opts.op_psize = fcp[1];
679 			fcp += 3;
680 			break;
681 
682 		case FACILITIES_THROUGHPUT:
683 			sa -> x25_opts.op_speed = fcp[1];
684 			fcp += 2;
685 			break;
686 
687 		case FACILITIES_REVERSE_CHARGE:
688 			if (fcp[1] & 01)
689 				sa -> x25_opts.op_flags |= X25_REVERSE_CHARGE;
690 			/*
691 			 * Datapac specific: for a X.25(1976) DTE, bit 2
692 			 * indicates a "hi priority" (eg. international) call.
693 			 */
694 			if (fcp[1] & 02 && sa -> x25_opts.op_psize == 0)
695 				sa -> x25_opts.op_psize = X25_PS128;
696 			fcp += 2;
697 			break;
698 
699 		default:
700 /*printf("unknown facility %x, class=%d\n", *fcp, (*fcp & 0xc0) >> 6);*/
701 			switch ((*fcp & 0xc0) >> 6) {
702 			case 0:			/* class A */
703 				fcp += 2;
704 				break;
705 
706 			case 1:
707 				fcp += 3;
708 				break;
709 
710 			case 2:
711 				fcp += 4;
712 				break;
713 
714 			case 3:
715 				fcp++;
716 				fcp += *fcp;
717 			}
718 		}
719 	}
720 }
721 
722 from_bcd (a, x, len)
723 register char *a;
724 register octet **x;
725 register int len;
726 {
727 	register int posn = 0;
728 
729 	while (--len >= 0) {
730 		if (posn++ & 0x01)
731 			*a = *(*x)++ & 0x0f;
732 		else
733 			*a = (**x >> 4) & 0x0F;
734 		*a++ |= 0x30;
735 	}
736 }
737