Commit | Line | Data |
---|---|---|
51386eb2 KS |
1 | /* |
2 | * Copyright (c) University of British Columbia, 1984 | |
a130a8be KS |
3 | * Copyright (C) Computer Science Department IV, |
4 | * University of Erlangen-Nuremberg, Germany, 1992 | |
5 | * Copyright (c) 1991, 1992 The Regents of the University of California. | |
51386eb2 KS |
6 | * All rights reserved. |
7 | * | |
a130a8be KS |
8 | * This code is derived from software contributed to Berkeley by the |
9 | * Laboratory for Computation Vision and the Computer Science Department | |
10 | * of the the University of British Columbia and the Computer Science | |
11 | * Department (IV) of the University of Erlangen-Nuremberg, Germany. | |
51386eb2 KS |
12 | * |
13 | * %sccs.include.redist.c% | |
14 | * | |
b5b78ee5 | 15 | * @(#)pk_input.c 7.20 (Berkeley) %G% |
51386eb2 | 16 | */ |
7f874860 | 17 | |
5548a02f KB |
18 | #include <sys/param.h> |
19 | #include <sys/systm.h> | |
20 | #include <sys/mbuf.h> | |
21 | #include <sys/socket.h> | |
22 | #include <sys/protosw.h> | |
23 | #include <sys/socketvar.h> | |
24 | #include <sys/errno.h> | |
7f874860 | 25 | |
5548a02f | 26 | #include <net/if.h> |
3773afb6 KS |
27 | #include <net/if_dl.h> |
28 | #include <net/if_llc.h> | |
29 | #include <net/route.h> | |
7f874860 | 30 | |
a130a8be | 31 | #include <netccitt/dll.h> |
5548a02f KB |
32 | #include <netccitt/x25.h> |
33 | #include <netccitt/pk.h> | |
34 | #include <netccitt/pk_var.h> | |
a130a8be KS |
35 | #include <netccitt/llc_var.h> |
36 | ||
37 | struct pkcb_q pkcb_q = {&pkcb_q, &pkcb_q}; | |
38 | ||
39 | /* | |
40 | * ccittintr() is the generic interrupt handler for HDLC, LLC2, and X.25. This | |
41 | * allows to have kernel running X.25 but no HDLC or LLC2 or both (in case we | |
42 | * employ boards that do all the stuff themselves, e.g. ADAX X.25 or TPS ISDN.) | |
43 | */ | |
44 | void | |
b5b78ee5 | 45 | ccittintr () |
a130a8be KS |
46 | { |
47 | extern struct ifqueue pkintrq; | |
48 | extern struct ifqueue hdintrq; | |
49 | extern struct ifqueue llcintrq; | |
50 | ||
51 | #ifdef HDLC | |
52 | if (hdintrq.ifq_len) | |
53 | hdintr (); | |
54 | #endif | |
55 | #ifdef LLC | |
56 | if (llcintrq.ifq_len) | |
57 | llcintr (); | |
58 | #endif | |
59 | if (pkintrq.ifq_len) | |
60 | pkintr (); | |
61 | } | |
7f874860 | 62 | |
8b8aa987 KS |
63 | struct pkcb * |
64 | pk_newlink (ia, llnext) | |
65 | struct x25_ifaddr *ia; | |
66 | caddr_t llnext; | |
67 | { | |
b5b78ee5 | 68 | register struct x25config *xcp = &ia -> ia_xc; |
8b8aa987 KS |
69 | register struct pkcb *pkp; |
70 | register struct pklcd *lcp; | |
71 | register struct protosw *pp; | |
72 | unsigned size; | |
73 | ||
b5b78ee5 | 74 | pp = pffindproto (AF_CCITT, (int) xcp -> xc_lproto, 0); |
8b8aa987 KS |
75 | if (pp == 0 || pp -> pr_output == 0) { |
76 | pk_message (0, xcp, "link level protosw error"); | |
77 | return ((struct pkcb *)0); | |
78 | } | |
79 | /* | |
80 | * Allocate a network control block structure | |
81 | */ | |
82 | size = sizeof (struct pkcb); | |
b5b78ee5 | 83 | pkp = (struct pkcb *) malloc (size, M_PCB, M_WAITOK); |
8b8aa987 KS |
84 | if (pkp == 0) |
85 | return ((struct pkcb *)0); | |
b5b78ee5 | 86 | bzero ((caddr_t) pkp, size); |
8b8aa987 | 87 | pkp -> pk_lloutput = pp -> pr_output; |
b5b78ee5 | 88 | pkp -> pk_llctlinput = (caddr_t (*)()) pp -> pr_ctlinput; |
8b8aa987 KS |
89 | pkp -> pk_xcp = xcp; |
90 | pkp -> pk_ia = ia; | |
91 | pkp -> pk_state = DTE_WAITING; | |
8b8aa987 | 92 | pkp -> pk_llnext = llnext; |
b5b78ee5 | 93 | insque (pkp, &pkcb_q); |
8b8aa987 KS |
94 | |
95 | /* | |
96 | * set defaults | |
97 | */ | |
98 | ||
99 | if (xcp -> xc_pwsize == 0) | |
100 | xcp -> xc_pwsize = DEFAULT_WINDOW_SIZE; | |
101 | if (xcp -> xc_psize == 0) | |
102 | xcp -> xc_psize = X25_PS128; | |
103 | /* | |
104 | * Allocate logical channel descriptor vector | |
105 | */ | |
106 | ||
b5b78ee5 | 107 | (void) pk_resize (pkp); |
8b8aa987 KS |
108 | return (pkp); |
109 | } | |
110 | ||
a130a8be KS |
111 | |
112 | pk_dellink (pkp) | |
113 | register struct pkcb *pkp; | |
114 | { | |
115 | register int i; | |
116 | register struct protosw *pp; | |
117 | ||
118 | /* | |
119 | * Essentially we have the choice to | |
120 | * (a) go ahead and let the route be deleted and | |
121 | * leave the pkcb associated with that route | |
122 | * as it is, i.e. the connections stay open | |
123 | * (b) do a pk_disconnect() on all channels associated | |
124 | * with the route via the pkcb and then proceed. | |
125 | * | |
126 | * For the time being we stick with (b) | |
127 | */ | |
128 | ||
b5b78ee5 KS |
129 | for (i = 1; i < pkp -> pk_maxlcn; ++i) |
130 | if (pkp -> pk_chan[i]) | |
131 | pk_disconnect (pkp -> pk_chan[i]); | |
a130a8be KS |
132 | |
133 | /* | |
134 | * Free the pkcb | |
135 | */ | |
136 | ||
137 | /* | |
138 | * First find the protoswitch to get hold of the link level | |
139 | * protocol to be notified that the packet level entity is | |
140 | * dissolving ... | |
141 | */ | |
b5b78ee5 | 142 | pp = pffindproto (AF_CCITT, (int) pkp -> pk_xcp -> xc_lproto, 0); |
a130a8be KS |
143 | if (pp == 0 || pp -> pr_output == 0) { |
144 | pk_message (0, pkp -> pk_xcp, "link level protosw error"); | |
b5b78ee5 | 145 | return (EPROTONOSUPPORT); |
a130a8be KS |
146 | } |
147 | ||
148 | pkp -> pk_refcount--; | |
149 | if (!pkp -> pk_refcount) { | |
150 | struct dll_ctlinfo ctlinfo; | |
151 | ||
b5b78ee5 | 152 | remque (pkp); |
a130a8be KS |
153 | if (pkp -> pk_rt -> rt_llinfo == (caddr_t) pkp) |
154 | pkp -> pk_rt -> rt_llinfo = (caddr_t) NULL; | |
155 | ||
156 | /* | |
157 | * Tell the link level that the pkcb is dissolving | |
158 | */ | |
159 | if (pp -> pr_ctlinput && pkp -> pk_llnext) { | |
160 | ctlinfo.dlcti_pcb = pkp -> pk_llnext; | |
161 | ctlinfo.dlcti_rt = pkp -> pk_rt; | |
162 | (pp -> pr_ctlinput)(PRC_DISCONNECT_REQUEST, | |
163 | pkp -> pk_xcp, &ctlinfo); | |
164 | } | |
b5b78ee5 KS |
165 | free ((caddr_t) pkp -> pk_chan, M_IFADDR); |
166 | free ((caddr_t) pkp, M_PCB); | |
a130a8be KS |
167 | } |
168 | ||
169 | return (0); | |
170 | } | |
171 | ||
172 | ||
8b8aa987 KS |
173 | pk_resize (pkp) |
174 | register struct pkcb *pkp; | |
175 | { | |
176 | struct pklcd *dev_lcp = 0; | |
177 | struct x25config *xcp = pkp -> pk_xcp; | |
178 | if (pkp -> pk_chan && | |
179 | (pkp -> pk_maxlcn != xcp -> xc_maxlcn)) { | |
180 | pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); | |
181 | dev_lcp = pkp -> pk_chan[0]; | |
b5b78ee5 | 182 | free ((caddr_t) pkp -> pk_chan, M_IFADDR); |
8b8aa987 KS |
183 | pkp -> pk_chan = 0; |
184 | } | |
185 | if (pkp -> pk_chan == 0) { | |
186 | unsigned size; | |
187 | pkp -> pk_maxlcn = xcp -> xc_maxlcn; | |
188 | size = (pkp -> pk_maxlcn + 1) * sizeof (struct pklcd *); | |
189 | pkp -> pk_chan = | |
190 | (struct pklcd **) malloc (size, M_IFADDR, M_WAITOK); | |
191 | if (pkp -> pk_chan) { | |
b5b78ee5 | 192 | bzero ((caddr_t) pkp -> pk_chan, size); |
8b8aa987 KS |
193 | /* |
194 | * Allocate a logical channel descriptor for lcn 0 | |
195 | */ | |
196 | if (dev_lcp == 0 && | |
197 | (dev_lcp = pk_attach ((struct socket *)0)) == 0) | |
198 | return (ENOBUFS); | |
199 | dev_lcp -> lcd_state = READY; | |
200 | dev_lcp -> lcd_pkp = pkp; | |
201 | pkp -> pk_chan[0] = dev_lcp; | |
202 | } else { | |
203 | if (dev_lcp) | |
204 | pk_close (dev_lcp); | |
205 | return (ENOBUFS); | |
206 | } | |
207 | } | |
208 | return 0; | |
209 | } | |
210 | ||
7f874860 KS |
211 | /* |
212 | * This procedure is called by the link level whenever the link | |
213 | * becomes operational, is reset, or when the link goes down. | |
214 | */ | |
a130a8be KS |
215 | /*VARARGS*/ |
216 | caddr_t | |
217 | pk_ctlinput (code, src, addr) | |
218 | struct sockaddr *src; | |
219 | caddr_t addr; | |
7f874860 | 220 | { |
b5b78ee5 | 221 | register struct pkcb *pkp = (struct pkcb *) addr; |
1c41f5e9 | 222 | |
7f874860 KS |
223 | switch (code) { |
224 | case PRC_LINKUP: | |
225 | if (pkp -> pk_state == DTE_WAITING) | |
226 | pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); | |
227 | break; | |
228 | ||
229 | case PRC_LINKDOWN: | |
230 | pk_restart (pkp, -1); /* Clear all active circuits */ | |
231 | pkp -> pk_state = DTE_WAITING; | |
232 | break; | |
233 | ||
234 | case PRC_LINKRESET: | |
235 | pk_restart (pkp, X25_RESTART_NETWORK_CONGESTION); | |
236 | break; | |
a130a8be KS |
237 | |
238 | case PRC_CONNECT_INDICATION: { | |
239 | struct rtentry *llrt; | |
240 | ||
241 | if ((llrt = rtalloc1(src, 0)) == 0) | |
242 | return 0; | |
b5b78ee5 | 243 | else llrt -> rt_refcnt--; |
a130a8be | 244 | |
b5b78ee5 KS |
245 | pkp = (((struct npaidbentry *) llrt -> rt_llinfo) -> np_rt) ? |
246 | (struct pkcb *)(((struct npaidbentry *) llrt -> rt_llinfo) -> np_rt -> rt_llinfo) : (struct pkcb *) 0; | |
a130a8be KS |
247 | if (pkp == (struct pkcb *) 0) |
248 | return 0; | |
b5b78ee5 | 249 | pkp -> pk_llnext = addr; |
a130a8be KS |
250 | |
251 | return ((caddr_t) pkp); | |
252 | } | |
253 | case PRC_DISCONNECT_INDICATION: | |
254 | pk_restart (pkp, -1) ; /* Clear all active circuits */ | |
b5b78ee5 KS |
255 | pkp -> pk_state = DTE_WAITING; |
256 | pkp -> pk_llnext = (caddr_t) 0; | |
7f874860 KS |
257 | } |
258 | return (0); | |
259 | } | |
1c41f5e9 KS |
260 | struct ifqueue pkintrq; |
261 | /* | |
262 | * This routine is called if there are semi-smart devices that do HDLC | |
263 | * in hardware and want to queue the packet and call level 3 directly | |
264 | */ | |
265 | pkintr () | |
266 | { | |
267 | register struct mbuf *m; | |
268 | register struct ifaddr *ifa; | |
269 | register struct ifnet *ifp; | |
270 | register int s; | |
271 | ||
272 | for (;;) { | |
273 | s = splimp (); | |
274 | IF_DEQUEUE (&pkintrq, m); | |
275 | splx (s); | |
276 | if (m == 0) | |
277 | break; | |
b5b78ee5 | 278 | if (m -> m_len < PKHEADERLN) { |
1c41f5e9 | 279 | printf ("pkintr: packet too short (len=%d)\n", |
b5b78ee5 | 280 | m -> m_len); |
1c41f5e9 KS |
281 | m_freem (m); |
282 | continue; | |
283 | } | |
b5b78ee5 | 284 | pk_input (m); |
1c41f5e9 KS |
285 | } |
286 | } | |
287 | struct mbuf *pk_bad_packet; | |
a833b510 | 288 | struct mbuf_cache pk_input_cache = {0 }; |
7f874860 KS |
289 | /* |
290 | * X.25 PACKET INPUT | |
291 | * | |
292 | * This procedure is called by a link level procedure whenever | |
293 | * an information frame is received. It decodes the packet and | |
294 | * demultiplexes based on the logical channel number. | |
295 | * | |
8b8aa987 | 296 | * We change the original conventions of the UBC code here -- |
538be1a4 KS |
297 | * since there may be multiple pkcb's for a given interface |
298 | * of type 802.2 class 2, we retrieve which one it is from | |
299 | * m_pkthdr.rcvif (which has been overwritten by lower layers); | |
300 | * That field is then restored for the benefit of upper layers which | |
301 | * may make use of it, such as CLNP. | |
b5b78ee5 | 302 | * |
7f874860 KS |
303 | */ |
304 | ||
a130a8be KS |
305 | #define RESTART_DTE_ORIGINATED(xp) (((xp) -> packet_cause == X25_RESTART_DTE_ORIGINATED) || \ |
306 | ((xp) -> packet_cause >= X25_RESTART_DTE_ORIGINATED2)) | |
307 | ||
8b8aa987 | 308 | pk_input (m) |
7f874860 | 309 | register struct mbuf *m; |
7f874860 KS |
310 | { |
311 | register struct x25_packet *xp; | |
312 | register struct pklcd *lcp; | |
313 | register struct socket *so = 0; | |
314 | register struct pkcb *pkp; | |
315 | int ptype, lcn, lcdstate = LISTEN; | |
7f874860 | 316 | |
a833b510 | 317 | if (pk_input_cache.mbc_size || pk_input_cache.mbc_oldsize) |
b5b78ee5 KS |
318 | mbuf_cache (&pk_input_cache, m); |
319 | if ((m -> m_flags & M_PKTHDR) == 0) | |
320 | panic ("pkintr"); | |
a130a8be | 321 | |
b5b78ee5 | 322 | if ((pkp = (struct pkcb *) m -> m_pkthdr.rcvif) == 0) |
8b8aa987 | 323 | return; |
7f874860 KS |
324 | xp = mtod (m, struct x25_packet *); |
325 | ptype = pk_decode (xp); | |
1b5dbaef | 326 | lcn = LCN(xp); |
7f874860 KS |
327 | lcp = pkp -> pk_chan[lcn]; |
328 | ||
329 | /* | |
330 | * If the DTE is in Restart state, then it will ignore data, | |
331 | * interrupt, call setup and clearing, flow control and reset | |
332 | * packets. | |
333 | */ | |
334 | if (lcn < 0 || lcn > pkp -> pk_maxlcn) { | |
335 | pk_message (lcn, pkp -> pk_xcp, "illegal lcn"); | |
336 | m_freem (m); | |
337 | return; | |
338 | } | |
339 | ||
c4b47c42 | 340 | pk_trace (pkp -> pk_xcp, m, "P-In"); |
7f874860 KS |
341 | |
342 | if (pkp -> pk_state != DTE_READY && ptype != RESTART && ptype != RESTART_CONF) { | |
343 | m_freem (m); | |
344 | return; | |
345 | } | |
346 | if (lcp) { | |
347 | so = lcp -> lcd_so; | |
348 | lcdstate = lcp -> lcd_state; | |
349 | } else { | |
350 | if (ptype == CLEAR) { /* idle line probe (Datapac specific) */ | |
351 | /* send response on lcd 0's output queue */ | |
8b8aa987 | 352 | lcp = pkp -> pk_chan[0]; |
7f874860 KS |
353 | lcp -> lcd_template = pk_template (lcn, X25_CLEAR_CONFIRM); |
354 | pk_output (lcp); | |
355 | m_freem (m); | |
356 | return; | |
357 | } | |
358 | if (ptype != CALL) | |
359 | ptype = INVALID_PACKET; | |
360 | } | |
361 | ||
362 | if (lcn == 0 && ptype != RESTART && ptype != RESTART_CONF) { | |
1c41f5e9 KS |
363 | pk_message (0, pkp -> pk_xcp, "illegal ptype (%d, %s) on lcn 0", |
364 | ptype, pk_name[ptype / MAXSTATES]); | |
365 | if (pk_bad_packet) | |
366 | m_freem (pk_bad_packet); | |
367 | pk_bad_packet = m; | |
7f874860 KS |
368 | return; |
369 | } | |
370 | ||
538be1a4 KS |
371 | m -> m_pkthdr.rcvif = pkp -> pk_ia -> ia_ifp; |
372 | ||
7f874860 KS |
373 | switch (ptype + lcdstate) { |
374 | /* | |
375 | * Incoming Call packet received. | |
376 | */ | |
377 | case CALL + LISTEN: | |
a833b510 | 378 | pk_incoming_call (pkp, m); |
7f874860 KS |
379 | break; |
380 | ||
381 | /* | |
382 | * Call collision: Just throw this "incoming call" away since | |
383 | * the DCE will ignore it anyway. | |
384 | */ | |
385 | case CALL + SENT_CALL: | |
b5b78ee5 | 386 | pk_message ((int) lcn, pkp -> pk_xcp, |
7f874860 KS |
387 | "incoming call collision"); |
388 | break; | |
389 | ||
390 | /* | |
391 | * Call confirmation packet received. This usually means our | |
392 | * previous connect request is now complete. | |
393 | */ | |
394 | case CALL_ACCEPTED + SENT_CALL: | |
60be2f67 | 395 | MCHTYPE(m, MT_CONTROL); |
a833b510 | 396 | pk_call_accepted (lcp, m); |
7f874860 KS |
397 | break; |
398 | ||
399 | /* | |
400 | * This condition can only happen if the previous state was | |
401 | * SENT_CALL. Just ignore the packet, eventually a clear | |
402 | * confirmation should arrive. | |
403 | */ | |
404 | case CALL_ACCEPTED + SENT_CLEAR: | |
405 | break; | |
406 | ||
407 | /* | |
408 | * Clear packet received. This requires a complete tear down | |
409 | * of the virtual circuit. Free buffers and control blocks. | |
410 | * and send a clear confirmation. | |
411 | */ | |
412 | case CLEAR + READY: | |
413 | case CLEAR + RECEIVED_CALL: | |
414 | case CLEAR + SENT_CALL: | |
415 | case CLEAR + DATA_TRANSFER: | |
416 | lcp -> lcd_state = RECEIVED_CLEAR; | |
417 | lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CLEAR_CONFIRM); | |
418 | pk_output (lcp); | |
419 | pk_clearcause (pkp, xp); | |
60be2f67 KS |
420 | if (lcp -> lcd_upper) { |
421 | MCHTYPE(m, MT_CONTROL); | |
422 | lcp -> lcd_upper (lcp, m); | |
423 | } | |
7f874860 | 424 | pk_close (lcp); |
60be2f67 | 425 | lcp = 0; |
7f874860 KS |
426 | break; |
427 | ||
428 | /* | |
429 | * Clear collision: Treat this clear packet as a confirmation. | |
430 | */ | |
431 | case CLEAR + SENT_CLEAR: | |
432 | pk_close (lcp); | |
433 | break; | |
434 | ||
435 | /* | |
436 | * Clear confirmation received. This usually means the virtual | |
437 | * circuit is now completely removed. | |
438 | */ | |
439 | case CLEAR_CONF + SENT_CLEAR: | |
440 | pk_close (lcp); | |
441 | break; | |
442 | ||
443 | /* | |
444 | * A clear confirmation on an unassigned logical channel - just | |
445 | * ignore it. Note: All other packets on an unassigned channel | |
446 | * results in a clear. | |
447 | */ | |
448 | case CLEAR_CONF + READY: | |
8b8aa987 | 449 | case CLEAR_CONF + LISTEN: |
7f874860 KS |
450 | break; |
451 | ||
452 | /* | |
453 | * Data packet received. Pass on to next level. Move the Q and M | |
454 | * bits into the data portion for the next level. | |
455 | */ | |
456 | case DATA + DATA_TRANSFER: | |
457 | if (lcp -> lcd_reset_condition) { | |
458 | ptype = DELETE_PACKET; | |
459 | break; | |
460 | } | |
461 | ||
462 | /* | |
463 | * Process the P(S) flow control information in this Data packet. | |
464 | * Check that the packets arrive in the correct sequence and that | |
465 | * they are within the "lcd_input_window". Input window rotation is | |
466 | * initiated by the receive interface. | |
467 | */ | |
468 | ||
469 | if (PS(xp) != ((lcp -> lcd_rsn + 1) % MODULUS) || | |
b5b78ee5 | 470 | PS(xp) == ((lcp -> lcd_input_window + lcp -> lcd_windowsize) % MODULUS)) { |
7f874860 | 471 | m_freem (m); |
c4b47c42 | 472 | pk_procerror (RESET, lcp, "p(s) flow control error", 1); |
7f874860 KS |
473 | break; |
474 | } | |
475 | lcp -> lcd_rsn = PS(xp); | |
476 | ||
477 | if (pk_ack (lcp, PR(xp)) != PACKET_OK) { | |
478 | m_freem (m); | |
479 | break; | |
480 | } | |
b84e7ca8 | 481 | m -> m_data += PKHEADERLN; |
7f874860 | 482 | m -> m_len -= PKHEADERLN; |
c4b47c42 KS |
483 | m -> m_pkthdr.len -= PKHEADERLN; |
484 | ||
8b8aa987 | 485 | lcp -> lcd_rxcnt++; |
c4b47c42 KS |
486 | if (lcp -> lcd_flags & X25_MBS_HOLD) { |
487 | register struct mbuf *n = lcp -> lcd_cps; | |
488 | int mbit = MBIT(xp); | |
489 | octet q_and_d_bits; | |
490 | ||
491 | if (n) { | |
492 | n -> m_pkthdr.len += m -> m_pkthdr.len; | |
493 | while (n -> m_next) | |
494 | n = n -> m_next; | |
495 | n -> m_next = m; | |
496 | m = lcp -> lcd_cps; | |
497 | ||
498 | if (lcp -> lcd_cpsmax && | |
499 | n -> m_pkthdr.len > lcp -> lcd_cpsmax) { | |
500 | pk_procerror (RESET, lcp, | |
501 | "C.P.S. overflow", 128); | |
502 | return; | |
503 | } | |
b5b78ee5 | 504 | q_and_d_bits = 0xc0 & *(octet *) xp; |
c4b47c42 | 505 | xp = (struct x25_packet *) |
b5b78ee5 KS |
506 | (mtod (m, octet *) - PKHEADERLN); |
507 | *(octet *) xp |= q_and_d_bits; | |
c4b47c42 KS |
508 | } |
509 | if (mbit) { | |
510 | lcp -> lcd_cps = m; | |
b5b78ee5 | 511 | pk_flowcontrol (lcp, 0, 1); |
c4b47c42 KS |
512 | return; |
513 | } | |
514 | lcp -> lcd_cps = 0; | |
515 | } | |
516 | if (so == 0) | |
517 | break; | |
7f874860 | 518 | if (lcp -> lcd_flags & X25_MQBIT) { |
a130a8be | 519 | octet t = (X25GBITS(xp -> bits, q_bit)) ? t = 0x80 : 0; |
7f874860 | 520 | |
1b5dbaef KS |
521 | if (MBIT(xp)) |
522 | t |= 0x40; | |
b84e7ca8 | 523 | m -> m_data -= 1; |
7f874860 | 524 | m -> m_len += 1; |
c4b47c42 | 525 | m -> m_pkthdr.len += 1; |
b5b78ee5 | 526 | *mtod (m, octet *) = t; |
7f874860 KS |
527 | } |
528 | ||
529 | /* | |
530 | * Discard Q-BIT packets if the application | |
531 | * doesn't want to be informed of M and Q bit status | |
532 | */ | |
a130a8be KS |
533 | if (X25GBITS(xp -> bits, q_bit) |
534 | && (lcp -> lcd_flags & X25_MQBIT) == 0) { | |
7f874860 | 535 | m_freem (m); |
7f874860 KS |
536 | /* |
537 | * NB. This is dangerous: sending a RR here can | |
538 | * cause sequence number errors if a previous data | |
539 | * packet has not yet been passed up to the application | |
540 | * (RR's are normally generated via PRU_RCVD). | |
541 | */ | |
b5b78ee5 | 542 | pk_flowcontrol (lcp, 0, 1); |
7f874860 | 543 | } else { |
7f874860 | 544 | sbappendrecord (&so -> so_rcv, m); |
7f874860 KS |
545 | sorwakeup (so); |
546 | } | |
547 | break; | |
548 | ||
549 | /* | |
550 | * Interrupt packet received. | |
551 | */ | |
552 | case INTERRUPT + DATA_TRANSFER: | |
553 | if (lcp -> lcd_reset_condition) | |
554 | break; | |
555 | lcp -> lcd_intrdata = xp -> packet_data; | |
7f874860 KS |
556 | lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT_CONFIRM); |
557 | pk_output (lcp); | |
c4b47c42 KS |
558 | m -> m_data += PKHEADERLN; |
559 | m -> m_len -= PKHEADERLN; | |
560 | m -> m_pkthdr.len -= PKHEADERLN; | |
1c41f5e9 | 561 | MCHTYPE(m, MT_OOBDATA); |
c4b47c42 KS |
562 | if (so) { |
563 | if (so -> so_options & SO_OOBINLINE) | |
564 | sbinsertoob (&so -> so_rcv, m); | |
565 | else | |
566 | m_freem (m); | |
1c41f5e9 | 567 | sohasoutofband (so); |
c4b47c42 | 568 | } |
7f874860 KS |
569 | break; |
570 | ||
571 | /* | |
572 | * Interrupt confirmation packet received. | |
573 | */ | |
574 | case INTERRUPT_CONF + DATA_TRANSFER: | |
575 | if (lcp -> lcd_reset_condition) | |
576 | break; | |
577 | if (lcp -> lcd_intrconf_pending == TRUE) | |
578 | lcp -> lcd_intrconf_pending = FALSE; | |
579 | else | |
c4b47c42 | 580 | pk_procerror (RESET, lcp, "unexpected packet", 43); |
7f874860 KS |
581 | break; |
582 | ||
583 | /* | |
584 | * Receiver ready received. Rotate the output window and output | |
585 | * any data packets waiting transmission. | |
586 | */ | |
587 | case RR + DATA_TRANSFER: | |
1c41f5e9 KS |
588 | if (lcp -> lcd_reset_condition || |
589 | pk_ack (lcp, PR(xp)) != PACKET_OK) { | |
590 | ptype = DELETE_PACKET; | |
7f874860 | 591 | break; |
1c41f5e9 | 592 | } |
7f874860 KS |
593 | if (lcp -> lcd_rnr_condition == TRUE) |
594 | lcp -> lcd_rnr_condition = FALSE; | |
595 | pk_output (lcp); | |
596 | break; | |
597 | ||
598 | /* | |
599 | * Receiver Not Ready received. Packets up to the P(R) can be | |
600 | * be sent. Condition is cleared with a RR. | |
601 | */ | |
602 | case RNR + DATA_TRANSFER: | |
1c41f5e9 KS |
603 | if (lcp -> lcd_reset_condition || |
604 | pk_ack (lcp, PR(xp)) != PACKET_OK) { | |
605 | ptype = DELETE_PACKET; | |
7f874860 | 606 | break; |
1c41f5e9 | 607 | } |
7f874860 KS |
608 | lcp -> lcd_rnr_condition = TRUE; |
609 | break; | |
610 | ||
611 | /* | |
612 | * Reset packet received. Set state to FLOW_OPEN. The Input and | |
613 | * Output window edges ar set to zero. Both the send and receive | |
614 | * numbers are reset. A confirmation is returned. | |
615 | */ | |
616 | case RESET + DATA_TRANSFER: | |
617 | if (lcp -> lcd_reset_condition) | |
618 | /* Reset collision. Just ignore packet. */ | |
619 | break; | |
620 | ||
621 | pk_resetcause (pkp, xp); | |
7f874860 KS |
622 | lcp -> lcd_window_condition = lcp -> lcd_rnr_condition = |
623 | lcp -> lcd_intrconf_pending = FALSE; | |
624 | lcp -> lcd_output_window = lcp -> lcd_input_window = | |
625 | lcp -> lcd_last_transmitted_pr = 0; | |
626 | lcp -> lcd_ssn = 0; | |
627 | lcp -> lcd_rsn = MODULUS - 1; | |
628 | ||
629 | lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET_CONFIRM); | |
630 | pk_output (lcp); | |
1c41f5e9 | 631 | |
b5b78ee5 | 632 | pk_flush (lcp); |
1c41f5e9 KS |
633 | if (so == 0) |
634 | break; | |
1c41f5e9 KS |
635 | wakeup ((caddr_t) & so -> so_timeo); |
636 | sorwakeup (so); | |
637 | sowwakeup (so); | |
7f874860 KS |
638 | break; |
639 | ||
640 | /* | |
641 | * Reset confirmation received. | |
642 | */ | |
643 | case RESET_CONF + DATA_TRANSFER: | |
644 | if (lcp -> lcd_reset_condition) { | |
645 | lcp -> lcd_reset_condition = FALSE; | |
646 | pk_output (lcp); | |
647 | } | |
648 | else | |
c4b47c42 | 649 | pk_procerror (RESET, lcp, "unexpected packet", 32); |
7f874860 KS |
650 | break; |
651 | ||
652 | case DATA + SENT_CLEAR: | |
653 | ptype = DELETE_PACKET; | |
654 | case RR + SENT_CLEAR: | |
655 | case RNR + SENT_CLEAR: | |
656 | case INTERRUPT + SENT_CLEAR: | |
657 | case INTERRUPT_CONF + SENT_CLEAR: | |
658 | case RESET + SENT_CLEAR: | |
659 | case RESET_CONF + SENT_CLEAR: | |
1c41f5e9 | 660 | /* Just ignore p if we have sent a CLEAR already. |
7f874860 KS |
661 | */ |
662 | break; | |
663 | ||
664 | /* | |
665 | * Restart sets all the permanent virtual circuits to the "Data | |
666 | * Transfer" stae and all the switched virtual circuits to the | |
667 | * "Ready" state. | |
668 | */ | |
669 | case RESTART + READY: | |
670 | switch (pkp -> pk_state) { | |
671 | case DTE_SENT_RESTART: | |
a130a8be KS |
672 | /* |
673 | * Restart collision. | |
674 | * If case the restart cause is "DTE originated" we | |
675 | * have a DTE-DTE situation and are trying to resolve | |
676 | * who is going to play DTE/DCE [ISO 8208:4.2-4.5] | |
677 | */ | |
678 | if (RESTART_DTE_ORIGINATED(xp)) { | |
679 | pk_restart (pkp, X25_RESTART_DTE_ORIGINATED); | |
680 | pk_message (0, pkp -> pk_xcp, | |
681 | "RESTART collision"); | |
682 | if ((pkp -> pk_restartcolls++) > MAXRESTARTCOLLISIONS) { | |
683 | pk_message (0, pkp -> pk_xcp, | |
684 | "excessive RESTART collisions"); | |
685 | pkp -> pk_restartcolls = 0; | |
686 | } | |
687 | break; | |
688 | } | |
7f874860 | 689 | pkp -> pk_state = DTE_READY; |
a130a8be KS |
690 | pkp -> pk_dxerole |= DTE_PLAYDTE; |
691 | pkp -> pk_dxerole &= ~DTE_PLAYDCE; | |
7f874860 KS |
692 | pk_message (0, pkp -> pk_xcp, |
693 | "Packet level operational"); | |
a130a8be KS |
694 | pk_message (0, pkp -> pk_xcp, |
695 | "Assuming DTE role"); | |
696 | if (pkp -> pk_dxerole & DTE_CONNECTPENDING) | |
b5b78ee5 | 697 | pk_callcomplete (pkp); |
7f874860 KS |
698 | break; |
699 | ||
700 | default: | |
701 | pk_restart (pkp, -1); | |
702 | pk_restartcause (pkp, xp); | |
703 | pkp -> pk_chan[0] -> lcd_template = pk_template (0, | |
704 | X25_RESTART_CONFIRM); | |
705 | pk_output (pkp -> pk_chan[0]); | |
a130a8be KS |
706 | pkp -> pk_state = DTE_READY; |
707 | pkp -> pk_dxerole |= RESTART_DTE_ORIGINATED(xp) ? DTE_PLAYDCE : | |
708 | DTE_PLAYDTE; | |
709 | if (pkp -> pk_dxerole & DTE_PLAYDTE) { | |
710 | pkp -> pk_dxerole &= ~DTE_PLAYDCE; | |
711 | pk_message (0, pkp -> pk_xcp, | |
712 | "Assuming DTE role"); | |
713 | } else { | |
714 | pkp -> pk_dxerole &= ~DTE_PLAYDTE; | |
715 | pk_message (0, pkp -> pk_xcp, | |
716 | "Assuming DCE role"); | |
717 | } | |
718 | if (pkp -> pk_dxerole & DTE_CONNECTPENDING) | |
b5b78ee5 | 719 | pk_callcomplete (pkp); |
7f874860 KS |
720 | } |
721 | break; | |
722 | ||
723 | /* | |
724 | * Restart confirmation received. All logical channels are set | |
725 | * to READY. | |
726 | */ | |
727 | case RESTART_CONF + READY: | |
728 | switch (pkp -> pk_state) { | |
729 | case DTE_SENT_RESTART: | |
730 | pkp -> pk_state = DTE_READY; | |
a130a8be KS |
731 | pkp -> pk_dxerole |= DTE_PLAYDTE; |
732 | pkp -> pk_dxerole &= ~DTE_PLAYDCE; | |
7f874860 | 733 | pk_message (0, pkp -> pk_xcp, |
a130a8be | 734 | "Packet level operational"); |
b5b78ee5 | 735 | pk_message (0, pkp -> pk_xcp, |
a130a8be KS |
736 | "Assuming DTE role"); |
737 | if (pkp -> pk_dxerole & DTE_CONNECTPENDING) | |
b5b78ee5 | 738 | pk_callcomplete (pkp); |
7f874860 KS |
739 | break; |
740 | ||
741 | default: | |
742 | /* Restart local procedure error. */ | |
743 | pk_restart (pkp, X25_RESTART_LOCAL_PROCEDURE_ERROR); | |
744 | pkp -> pk_state = DTE_SENT_RESTART; | |
a130a8be | 745 | pkp -> pk_dxerole &= ~(DTE_PLAYDTE | DTE_PLAYDCE); |
7f874860 KS |
746 | } |
747 | break; | |
748 | ||
749 | default: | |
750 | if (lcp) { | |
c4b47c42 | 751 | pk_procerror (CLEAR, lcp, "unknown packet error", 33); |
7f874860 KS |
752 | pk_message (lcn, pkp -> pk_xcp, |
753 | "\"%s\" unexpected in \"%s\" state", | |
754 | pk_name[ptype/MAXSTATES], pk_state[lcdstate]); | |
c4b47c42 | 755 | } else |
1b5dbaef | 756 | pk_message (lcn, pkp -> pk_xcp, |
7f874860 KS |
757 | "packet arrived on unassigned lcn"); |
758 | break; | |
759 | } | |
60be2f67 | 760 | if (so == 0 && lcp && lcp -> lcd_upper && lcdstate == DATA_TRANSFER) { |
c4b47c42 KS |
761 | if (ptype != DATA && ptype != INTERRUPT) |
762 | MCHTYPE(m, MT_CONTROL); | |
1c41f5e9 | 763 | lcp -> lcd_upper (lcp, m); |
c4b47c42 | 764 | } else if (ptype != DATA && ptype != INTERRUPT) |
7f874860 KS |
765 | m_freem (m); |
766 | } | |
767 | ||
8b8aa987 | 768 | static |
b5b78ee5 | 769 | prune_dnic (from, to, dnicname, xcp) |
8b8aa987 KS |
770 | char *from, *to, *dnicname; |
771 | register struct x25config *xcp; | |
772 | { | |
773 | register char *cp1 = from, *cp2 = from; | |
b5b78ee5 | 774 | if (xcp -> xc_prepnd0 && *cp1 == '0') { |
8b8aa987 KS |
775 | from = ++cp1; |
776 | goto copyrest; | |
777 | } | |
b5b78ee5 | 778 | if (xcp -> xc_nodnic) { |
8b8aa987 KS |
779 | for (cp1 = dnicname; *cp2 = *cp1++;) |
780 | cp2++; | |
781 | cp1 = from; | |
782 | } | |
783 | copyrest: | |
784 | for (cp1 = dnicname; *cp2 = *cp1++;) | |
785 | cp2++; | |
786 | } | |
787 | /* static */ | |
788 | pk_simple_bsd (from, to, lower, len) | |
789 | register octet *from, *to; | |
790 | register len, lower; | |
791 | { | |
792 | register int c; | |
793 | while (--len >= 0) { | |
794 | c = *from; | |
795 | if (lower & 0x01) | |
796 | *from++; | |
797 | else | |
798 | c >>= 4; | |
799 | c &= 0x0f; c |= 0x30; *to++ = c; lower++; | |
800 | } | |
801 | *to = 0; | |
802 | } | |
803 | ||
804 | /*static octet * */ | |
805 | pk_from_bcd (a, iscalling, sa, xcp) | |
806 | register struct x25_calladdr *a; | |
807 | register struct sockaddr_x25 *sa; | |
808 | register struct x25config *xcp; | |
809 | { | |
810 | octet buf[MAXADDRLN+1]; | |
811 | octet *cp; | |
812 | unsigned count; | |
813 | ||
b5b78ee5 | 814 | bzero ((caddr_t) sa, sizeof (*sa)); |
8b8aa987 KS |
815 | sa -> x25_len = sizeof (*sa); |
816 | sa -> x25_family = AF_CCITT; | |
817 | if (iscalling) { | |
a130a8be KS |
818 | cp = a -> address_field + (X25GBITS(a -> addrlens, called_addrlen) / 2); |
819 | count = X25GBITS(a -> addrlens, calling_addrlen); | |
820 | pk_simple_bsd (cp, buf, X25GBITS(a -> addrlens, called_addrlen), count); | |
8b8aa987 | 821 | } else { |
a130a8be | 822 | count = X25GBITS(a -> addrlens, called_addrlen); |
8b8aa987 KS |
823 | pk_simple_bsd (a -> address_field, buf, 0, count); |
824 | } | |
b5b78ee5 KS |
825 | if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) { |
826 | octet dnicname[sizeof (long) * NBBY/3 + 2]; | |
8b8aa987 | 827 | |
a130a8be | 828 | sprintf ((char *) dnicname, "%d", xcp -> xc_addr.x25_net); |
b5b78ee5 | 829 | prune_dnic ((char *) buf, sa -> x25_addr, dnicname, xcp); |
8b8aa987 | 830 | } else |
b5b78ee5 | 831 | bcopy ((caddr_t) buf, (caddr_t) sa -> x25_addr, count + 1); |
8b8aa987 KS |
832 | } |
833 | ||
834 | static | |
b5b78ee5 | 835 | save_extra (m0, fp, so) |
8b8aa987 KS |
836 | struct mbuf *m0; |
837 | octet *fp; | |
838 | struct socket *so; | |
839 | { | |
840 | register struct mbuf *m; | |
841 | struct cmsghdr cmsghdr; | |
ef85d011 | 842 | if (m = m_copy (m, 0, (int)M_COPYALL)) { |
8b8aa987 | 843 | int off = fp - mtod (m0, octet *); |
b5b78ee5 | 844 | int len = m -> m_pkthdr.len - off + sizeof (cmsghdr); |
8b8aa987 KS |
845 | cmsghdr.cmsg_len = len; |
846 | cmsghdr.cmsg_level = AF_CCITT; | |
847 | cmsghdr.cmsg_type = PK_FACILITIES; | |
848 | m_adj (m, off); | |
b5b78ee5 | 849 | M_PREPEND (m, sizeof (cmsghdr), M_DONTWAIT); |
8b8aa987 KS |
850 | if (m == 0) |
851 | return; | |
852 | bcopy ((caddr_t)&cmsghdr, mtod (m, caddr_t), sizeof (cmsghdr)); | |
853 | MCHTYPE(m, MT_CONTROL); | |
b5b78ee5 | 854 | sbappendrecord (&so -> so_rcv, m); |
8b8aa987 KS |
855 | } |
856 | } | |
7f874860 KS |
857 | |
858 | /* | |
859 | * This routine handles incoming call packets. It matches the protocol | |
860 | * field on the Call User Data field (usually the first four bytes) with | |
861 | * sockets awaiting connections. | |
862 | */ | |
863 | ||
a833b510 | 864 | pk_incoming_call (pkp, m0) |
c4b47c42 | 865 | struct mbuf *m0; |
7f874860 | 866 | struct pkcb *pkp; |
7f874860 | 867 | { |
ffababe5 | 868 | register struct pklcd *lcp = 0, *l; |
7f874860 KS |
869 | register struct sockaddr_x25 *sa; |
870 | register struct x25_calladdr *a; | |
ffababe5 | 871 | register struct socket *so = 0; |
b5b78ee5 | 872 | struct x25_packet *xp = mtod (m0, struct x25_packet *); |
8b8aa987 KS |
873 | struct mbuf *m; |
874 | struct x25config *xcp = pkp -> pk_xcp; | |
b5b78ee5 | 875 | int len = m0 -> m_pkthdr.len; |
8b8aa987 KS |
876 | unsigned udlen; |
877 | char *errstr = "server unavailable"; | |
c4b47c42 | 878 | octet *u, *facp; |
1b5dbaef | 879 | int lcn = LCN(xp); |
7f874860 | 880 | |
8b8aa987 KS |
881 | /* First, copy the data from the incoming call packet to a X25 address |
882 | descriptor. It is to be regretted that you have | |
883 | to parse the facilities into a sockaddr to determine | |
884 | if reverse charging is being requested */ | |
885 | if ((m = m_get (M_DONTWAIT, MT_SONAME)) == 0) | |
7f874860 KS |
886 | return; |
887 | sa = mtod (m, struct sockaddr_x25 *); | |
8b8aa987 KS |
888 | a = (struct x25_calladdr *) &xp -> packet_data; |
889 | facp = u = (octet *) (a -> address_field + | |
a130a8be | 890 | ((X25GBITS(a -> addrlens, called_addrlen) + X25GBITS(a -> addrlens, calling_addrlen) + 1) / 2)); |
7f874860 | 891 | u += *u + 1; |
b5b78ee5 | 892 | udlen = min (16, ((octet *) xp) + len - u); |
8b8aa987 KS |
893 | if (udlen < 0) |
894 | udlen = 0; | |
895 | pk_from_bcd (a, 1, sa, pkp -> pk_xcp); /* get calling address */ | |
d18ac824 | 896 | pk_parse_facilities (facp, sa); |
b5b78ee5 | 897 | bcopy ((caddr_t) u, sa -> x25_udata, udlen); |
8b8aa987 | 898 | sa -> x25_udlen = udlen; |
7f874860 KS |
899 | |
900 | /* | |
d18ac824 KS |
901 | * Now, loop through the listen sockets looking for a match on the |
902 | * PID. That is the first few octets of the user data field. | |
903 | * This is the closest thing to a port number for X.25 packets. | |
904 | * It does provide a way of multiplexing services at the user level. | |
7f874860 KS |
905 | */ |
906 | ||
907 | for (l = pk_listenhead; l; l = l -> lcd_listen) { | |
908 | struct sockaddr_x25 *sxp = l -> lcd_ceaddr; | |
909 | ||
b5b78ee5 | 910 | if (bcmp (sxp -> x25_udata, u, sxp -> x25_udlen)) |
7f874860 | 911 | continue; |
4507dea2 | 912 | if (sxp -> x25_net && |
8b8aa987 | 913 | sxp -> x25_net != xcp -> xc_addr.x25_net) |
7f874860 | 914 | continue; |
8b8aa987 KS |
915 | /* |
916 | * don't accept incoming calls with the D-Bit on | |
917 | * unless the server agrees | |
918 | */ | |
a130a8be | 919 | if (X25GBITS(xp -> bits, d_bit) && !(sxp -> x25_opts.op_flags & X25_DBIT)) { |
8b8aa987 KS |
920 | errstr = "incoming D-Bit mismatch"; |
921 | break; | |
922 | } | |
7f874860 KS |
923 | /* |
924 | * don't accept incoming collect calls unless | |
925 | * the server sets the reverse charging option. | |
926 | */ | |
927 | if ((sxp -> x25_opts.op_flags & (X25_OLDSOCKADDR|X25_REVERSE_CHARGE)) == 0 && | |
928 | sa -> x25_opts.op_flags & X25_REVERSE_CHARGE) { | |
929 | errstr = "incoming collect call refused"; | |
930 | break; | |
931 | } | |
ffababe5 | 932 | if (l -> lcd_so) { |
4507dea2 | 933 | if (so = sonewconn (l -> lcd_so, SS_ISCONNECTED)) |
ffababe5 KS |
934 | lcp = (struct pklcd *) so -> so_pcb; |
935 | } else | |
b5b78ee5 | 936 | lcp = pk_attach ((struct socket *) 0); |
ffababe5 | 937 | if (lcp == 0) { |
7f874860 KS |
938 | /* |
939 | * Insufficient space or too many unaccepted | |
940 | * connections. Just throw the call away. | |
941 | */ | |
942 | errstr = "server malfunction"; | |
943 | break; | |
944 | } | |
b84e7ca8 KS |
945 | lcp -> lcd_upper = l -> lcd_upper; |
946 | lcp -> lcd_upnext = l -> lcd_upnext; | |
7f874860 KS |
947 | lcp -> lcd_lcn = lcn; |
948 | lcp -> lcd_state = RECEIVED_CALL; | |
f60b6d8f KS |
949 | sa -> x25_opts.op_flags |= (sxp -> x25_opts.op_flags & |
950 | ~X25_REVERSE_CHARGE) | l -> lcd_flags; | |
7f874860 | 951 | pk_assoc (pkp, lcp, sa); |
8b8aa987 KS |
952 | lcp -> lcd_faddr = *sa; |
953 | lcp -> lcd_laddr.x25_udlen = sxp -> x25_udlen; | |
b5b78ee5 | 954 | lcp -> lcd_craddr = &lcp -> lcd_faddr; |
7f874860 | 955 | lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL_ACCEPTED); |
1b5dbaef | 956 | if (lcp -> lcd_flags & X25_DBIT) { |
a130a8be | 957 | if (X25GBITS(xp -> bits, d_bit)) |
b5b78ee5 | 958 | X25SBITS(mtod (lcp -> lcd_template, |
a130a8be | 959 | struct x25_packet *) -> bits, d_bit, 1); |
1b5dbaef KS |
960 | else |
961 | lcp -> lcd_flags &= ~X25_DBIT; | |
962 | } | |
b84e7ca8 KS |
963 | if (so) { |
964 | pk_output (lcp); | |
ffababe5 | 965 | soisconnected (so); |
c4b47c42 | 966 | if (so -> so_options & SO_OOBINLINE) |
b5b78ee5 | 967 | save_extra (m0, facp, so); |
c4b47c42 | 968 | } else if (lcp -> lcd_upper) { |
8b8aa987 | 969 | (*lcp -> lcd_upper) (lcp, m0); |
c4b47c42 | 970 | } |
8b8aa987 | 971 | (void) m_free (m); |
7f874860 KS |
972 | return; |
973 | } | |
974 | ||
975 | /* | |
976 | * If the call fails for whatever reason, we still need to build a | |
977 | * skeleton LCD in order to be able to properly receive the CLEAR | |
978 | * CONFIRMATION. | |
979 | */ | |
980 | #ifdef WATERLOO /* be explicit */ | |
b5b78ee5 | 981 | if (l == 0 && bcmp (sa -> x25_udata, "ean", 3) == 0) |
7f874860 | 982 | pk_message (lcn, pkp -> pk_xcp, "host=%s ean%c: %s", |
b5b78ee5 KS |
983 | sa -> x25_addr, sa -> x25_udata[3] & 0xff, errstr); |
984 | else if (l == 0 && bcmp (sa -> x25_udata, "\1\0\0\0", 4) == 0) | |
7f874860 | 985 | pk_message (lcn, pkp -> pk_xcp, "host=%s x29d: %s", |
b5b78ee5 | 986 | sa -> x25_addr, errstr); |
7f874860 KS |
987 | else |
988 | #endif | |
989 | pk_message (lcn, pkp -> pk_xcp, "host=%s pid=%x %x %x %x: %s", | |
990 | sa -> x25_addr, sa -> x25_udata[0] & 0xff, | |
991 | sa -> x25_udata[1] & 0xff, sa -> x25_udata[2] & 0xff, | |
992 | sa -> x25_udata[3] & 0xff, errstr); | |
b5b78ee5 | 993 | if ((lcp = pk_attach ((struct socket *)0)) == 0) { |
1c41f5e9 | 994 | (void) m_free (m); |
7f874860 KS |
995 | return; |
996 | } | |
7f874860 KS |
997 | lcp -> lcd_lcn = lcn; |
998 | lcp -> lcd_state = RECEIVED_CALL; | |
999 | pk_assoc (pkp, lcp, sa); | |
1c41f5e9 | 1000 | (void) m_free (m); |
c4b47c42 KS |
1001 | pk_clear (lcp, 0, 1); |
1002 | } | |
1003 | ||
a833b510 | 1004 | pk_call_accepted (lcp, m) |
7f874860 | 1005 | struct pklcd *lcp; |
60be2f67 | 1006 | struct mbuf *m; |
7f874860 KS |
1007 | { |
1008 | register struct x25_calladdr *ap; | |
1009 | register octet *fcp; | |
60be2f67 KS |
1010 | struct x25_packet *xp = mtod (m, struct x25_packet *); |
1011 | int len = m -> m_len; | |
7f874860 KS |
1012 | |
1013 | lcp -> lcd_state = DATA_TRANSFER; | |
1c41f5e9 KS |
1014 | if (lcp -> lcd_so) |
1015 | soisconnected (lcp -> lcd_so); | |
a130a8be | 1016 | if ((lcp -> lcd_flags & X25_DBIT) && (X25GBITS(xp -> bits, d_bit) == 0)) |
1b5dbaef | 1017 | lcp -> lcd_flags &= ~X25_DBIT; |
7f874860 KS |
1018 | if (len > 3) { |
1019 | ap = (struct x25_calladdr *) &xp -> packet_data; | |
a130a8be KS |
1020 | fcp = (octet *) ap -> address_field + (X25GBITS(ap -> addrlens, calling_addrlen) + |
1021 | X25GBITS(ap -> addrlens, called_addrlen) + 1) / 2; | |
b5b78ee5 | 1022 | if (fcp + *fcp <= ((octet *) xp) + len) |
a833b510 | 1023 | pk_parse_facilities (fcp, lcp -> lcd_ceaddr); |
7f874860 KS |
1024 | } |
1025 | pk_assoc (lcp -> lcd_pkp, lcp, lcp -> lcd_ceaddr); | |
60be2f67 | 1026 | if (lcp -> lcd_so == 0 && lcp -> lcd_upper) |
b5b78ee5 | 1027 | lcp -> lcd_upper (lcp, m); |
7f874860 KS |
1028 | } |
1029 | ||
a833b510 | 1030 | pk_parse_facilities (fcp, sa) |
7f874860 KS |
1031 | register octet *fcp; |
1032 | register struct sockaddr_x25 *sa; | |
1033 | { | |
1034 | register octet *maxfcp; | |
1035 | ||
1036 | maxfcp = fcp + *fcp; | |
1037 | fcp++; | |
1038 | while (fcp < maxfcp) { | |
1039 | /* | |
1040 | * Ignore national DCE or DTE facilities | |
1041 | */ | |
1042 | if (*fcp == 0 || *fcp == 0xff) | |
1043 | break; | |
1044 | switch (*fcp) { | |
1045 | case FACILITIES_WINDOWSIZE: | |
1046 | sa -> x25_opts.op_wsize = fcp[1]; | |
1047 | fcp += 3; | |
1048 | break; | |
1049 | ||
1050 | case FACILITIES_PACKETSIZE: | |
1051 | sa -> x25_opts.op_psize = fcp[1]; | |
1052 | fcp += 3; | |
1053 | break; | |
1054 | ||
1055 | case FACILITIES_THROUGHPUT: | |
1056 | sa -> x25_opts.op_speed = fcp[1]; | |
1057 | fcp += 2; | |
1058 | break; | |
1059 | ||
1060 | case FACILITIES_REVERSE_CHARGE: | |
1061 | if (fcp[1] & 01) | |
1062 | sa -> x25_opts.op_flags |= X25_REVERSE_CHARGE; | |
1063 | /* | |
1064 | * Datapac specific: for a X.25(1976) DTE, bit 2 | |
1065 | * indicates a "hi priority" (eg. international) call. | |
1066 | */ | |
1067 | if (fcp[1] & 02 && sa -> x25_opts.op_psize == 0) | |
1068 | sa -> x25_opts.op_psize = X25_PS128; | |
1069 | fcp += 2; | |
1070 | break; | |
1071 | ||
1072 | default: | |
1073 | /*printf("unknown facility %x, class=%d\n", *fcp, (*fcp & 0xc0) >> 6);*/ | |
1074 | switch ((*fcp & 0xc0) >> 6) { | |
1075 | case 0: /* class A */ | |
1076 | fcp += 2; | |
1077 | break; | |
1078 | ||
1079 | case 1: | |
1080 | fcp += 3; | |
1081 | break; | |
1082 | ||
1083 | case 2: | |
1084 | fcp += 4; | |
1085 | break; | |
1086 | ||
1087 | case 3: | |
1088 | fcp++; | |
1089 | fcp += *fcp; | |
1090 | } | |
1091 | } | |
1092 | } | |
1093 | } |