Commit | Line | Data |
---|---|---|
51386eb2 KS |
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 | * | |
1c41f5e9 | 12 | * @(#)pk_input.c 7.6 (Berkeley) %G% |
51386eb2 | 13 | */ |
7f874860 | 14 | |
4507dea2 KS |
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" | |
7f874860 KS |
22 | |
23 | #include "../net/if.h" | |
24 | ||
4507dea2 KS |
25 | #include "x25.h" |
26 | #include "pk.h" | |
27 | #include "pk_var.h" | |
7f874860 | 28 | |
7f874860 KS |
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 | ||
1c41f5e9 KS |
34 | pk_ctlinput (code, xcp) |
35 | register struct x25config *xcp; | |
7f874860 | 36 | { |
7f874860 | 37 | |
1c41f5e9 KS |
38 | register struct pkcb *pkp; |
39 | ||
40 | for (pkp = pkcbhead; pkp; pkp = pkp -> pk_next) | |
41 | if (pkp -> pk_xcp == xcp) | |
42 | break; | |
43 | ||
ffababe5 | 44 | if (pkp == 0) |
7f874860 | 45 | return (EINVAL); |
1c41f5e9 | 46 | |
7f874860 KS |
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 | } | |
1c41f5e9 KS |
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; | |
7f874860 KS |
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) { | |
1c41f5e9 KS |
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; | |
7f874860 KS |
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 | } | |
1c41f5e9 KS |
288 | if (so == 0) |
289 | break; | |
b84e7ca8 | 290 | m -> m_data += PKHEADERLN; |
7f874860 KS |
291 | m -> m_len -= PKHEADERLN; |
292 | if (lcp -> lcd_flags & X25_MQBIT) { | |
293 | octet *t; | |
294 | ||
b84e7ca8 | 295 | m -> m_data -= 1; |
7f874860 KS |
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; | |
7f874860 KS |
337 | lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT_CONFIRM); |
338 | pk_output (lcp); | |
1c41f5e9 KS |
339 | MCHTYPE(m, MT_OOBDATA); |
340 | if (so) | |
341 | sohasoutofband (so); | |
7f874860 KS |
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"); | |
1c41f5e9 | 354 | MCHTYPE(m, MT_CONTROL); |
7f874860 KS |
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: | |
1c41f5e9 KS |
362 | if (lcp -> lcd_reset_condition || |
363 | pk_ack (lcp, PR(xp)) != PACKET_OK) { | |
364 | ptype = DELETE_PACKET; | |
7f874860 | 365 | break; |
1c41f5e9 | 366 | } |
7f874860 KS |
367 | if (lcp -> lcd_rnr_condition == TRUE) |
368 | lcp -> lcd_rnr_condition = FALSE; | |
369 | pk_output (lcp); | |
1c41f5e9 | 370 | MCHTYPE(m, MT_CONTROL); |
7f874860 KS |
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: | |
1c41f5e9 KS |
378 | if (lcp -> lcd_reset_condition || |
379 | pk_ack (lcp, PR(xp)) != PACKET_OK) { | |
380 | ptype = DELETE_PACKET; | |
7f874860 | 381 | break; |
1c41f5e9 | 382 | } |
7f874860 | 383 | lcp -> lcd_rnr_condition = TRUE; |
1c41f5e9 | 384 | MCHTYPE(m, MT_CONTROL); |
7f874860 KS |
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); | |
7f874860 KS |
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); | |
1c41f5e9 KS |
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); | |
7f874860 KS |
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"); | |
1c41f5e9 | 428 | MCHTYPE(m, MT_CONTROL); |
7f874860 KS |
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: | |
1c41f5e9 | 439 | /* Just ignore p if we have sent a CLEAR already. |
7f874860 KS |
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 | } | |
1c41f5e9 KS |
498 | if (so == 0 && lcdstate == DATA_TRANSFER && lcp -> lcd_upper) |
499 | lcp -> lcd_upper (lcp, m); | |
500 | else if (ptype != DATA) | |
7f874860 KS |
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 | { | |
ffababe5 | 516 | register struct pklcd *lcp = 0, *l; |
7f874860 KS |
517 | register struct sockaddr_x25 *sa; |
518 | register struct x25_calladdr *a; | |
ffababe5 | 519 | register struct socket *so = 0; |
7f874860 KS |
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; | |
1c41f5e9 | 532 | if ((m = m_getclr (M_DONTWAIT, MT_SONAME)) == 0) |
7f874860 KS |
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; | |
4507dea2 KS |
564 | if (sxp -> x25_net && |
565 | sxp -> x25_net != pkp->pk_xc.xc_addr.x25_net) | |
7f874860 KS |
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 | } | |
ffababe5 | 576 | if (l -> lcd_so) { |
4507dea2 | 577 | if (so = sonewconn (l -> lcd_so, SS_ISCONNECTED)) |
ffababe5 KS |
578 | lcp = (struct pklcd *) so -> so_pcb; |
579 | } else | |
580 | lcp = pk_attach((struct socket *) 0); | |
581 | if (lcp == 0) { | |
7f874860 KS |
582 | /* |
583 | * Insufficient space or too many unaccepted | |
584 | * connections. Just throw the call away. | |
585 | */ | |
586 | errstr = "server malfunction"; | |
587 | break; | |
588 | } | |
b84e7ca8 KS |
589 | lcp -> lcd_upper = l -> lcd_upper; |
590 | lcp -> lcd_upnext = l -> lcd_upnext; | |
7f874860 KS |
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); | |
b84e7ca8 KS |
598 | if (so) { |
599 | pk_output (lcp); | |
ffababe5 | 600 | soisconnected (so); |
b84e7ca8 | 601 | } else if (lcp->lcd_upper) |
1c41f5e9 | 602 | (*lcp->lcd_upper)(lcp, m); |
7f874860 KS |
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); | |
1c41f5e9 KS |
624 | if ((lcp = pk_attach((struct socket *)0)) == 0) { |
625 | (void) m_free (m); | |
7f874860 KS |
626 | return; |
627 | } | |
7f874860 KS |
628 | lcp -> lcd_lcn = lcn; |
629 | lcp -> lcd_state = RECEIVED_CALL; | |
630 | pk_assoc (pkp, lcp, sa); | |
1c41f5e9 | 631 | (void) m_free (m); |
7f874860 KS |
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; | |
1c41f5e9 KS |
644 | if (lcp -> lcd_so) |
645 | soisconnected (lcp -> lcd_so); | |
7f874860 KS |
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 | } |