new copyright; att/bsd/shared
[unix-history] / usr / src / sys / netccitt / pk_subr.c
CommitLineData
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 *
480398a9 12 * @(#)pk_subr.c 7.12 (Berkeley) %G%
51386eb2 13 */
6567c660 14
039be508
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"
22#include "time.h"
23#include "kernel.h"
24
ffababe5
KS
25#include "../net/if.h"
26
039be508
KS
27#include "x25.h"
28#include "pk.h"
29#include "pk_var.h"
30#include "x25err.h"
6567c660
KS
31
32int pk_sendspace = 1024 * 2 + 8;
33int pk_recvspace = 1024 * 2 + 8;
34
32f30cd6
KS
35struct pklcd_q pklcd_q = {&pklcd_q, &pklcd_q};
36
6567c660
KS
37/*
38 * Attach X.25 protocol to socket, allocate logical channel descripter
39 * and buffer space, and enter LISTEN state if we are to accept
40 * IN-COMMING CALL packets.
41 *
42 */
43
ffababe5 44struct pklcd *
6567c660
KS
45pk_attach (so)
46struct socket *so;
47{
48 register struct pklcd *lcp;
ffababe5 49 register int error = ENOBUFS;
480398a9 50 int pk_output();
6567c660 51
32f30cd6 52 MALLOC(lcp, struct pklcd *, sizeof (*lcp), M_PCB, M_NOWAIT);
ffababe5 53 if (lcp) {
32f30cd6
KS
54 bzero ((caddr_t)lcp, sizeof (*lcp));
55 insque (&lcp -> lcd_q, &pklcd_q);
ffababe5
KS
56 if (so) {
57 error = soreserve (so, pk_sendspace, pk_recvspace);
ffababe5
KS
58 lcp -> lcd_so = so;
59 if (so -> so_options & SO_ACCEPTCONN)
60 lcp -> lcd_state = LISTEN;
61 else
62 lcp -> lcd_state = READY;
b84e7ca8 63 } else
4507dea2 64 sbreserve (&lcp -> lcd_sb, pk_sendspace);
ffababe5
KS
65 }
66 if (so) {
67 so -> so_pcb = (caddr_t) lcp;
68 so -> so_error = error;
69 }
480398a9 70 lcp -> lcd_send = pk_output;
ffababe5 71 return (lcp);
6567c660
KS
72}
73
74/*
75 * Disconnect X.25 protocol from socket.
76 */
77
78pk_disconnect (lcp)
79register struct pklcd *lcp;
80{
81 register struct socket *so = lcp -> lcd_so;
82 register struct pklcd *l, *p;
83
84 switch (lcp -> lcd_state) {
85 case LISTEN:
86 for (p = 0, l = pk_listenhead; l && l != lcp; p = l, l = l -> lcd_listen);
87 if (p == 0) {
88 if (l != 0)
89 pk_listenhead = l -> lcd_listen;
90 }
91 else
92 if (l != 0)
93 p -> lcd_listen = l -> lcd_listen;
94 pk_close (lcp);
95 break;
96
97 case READY:
98 pk_acct (lcp);
99 pk_close (lcp);
100 break;
101
102 case SENT_CLEAR:
103 case RECEIVED_CLEAR:
104 break;
105
106 default:
107 pk_acct (lcp);
039be508
KS
108 if (so) {
109 soisdisconnecting (so);
110 sbflush (&so -> so_rcv);
111 }
c4b47c42 112 pk_clear (lcp, 241, 0); /* Normal Disconnect */
6567c660
KS
113
114 }
115}
116
117/*
118 * Close an X.25 Logical Channel. Discard all space held by the
119 * connection and internal descriptors. Wake up any sleepers.
120 */
121
122pk_close (lcp)
123struct pklcd *lcp;
124{
125 register struct socket *so = lcp -> lcd_so;
126
127 pk_freelcd (lcp);
128
129 if (so == NULL)
130 return;
131
132 so -> so_pcb = 0;
6567c660 133 soisdisconnected (so);
c4b47c42 134 /* sofree (so); /* gak!!! you can't do that here */
6567c660
KS
135}
136
137/*
138 * Create a template to be used to send X.25 packets on a logical
139 * channel. It allocates an mbuf and fills in a skeletal packet
140 * depending on its type. This packet is passed to pk_output where
141 * the remainer of the packet is filled in.
142*/
143
c4b47c42 144struct mbuf *
6567c660
KS
145pk_template (lcn, type)
146int lcn, type;
147{
148 register struct mbuf *m;
149 register struct x25_packet *xp;
150
1c41f5e9 151 MGETHDR (m, M_DONTWAIT, MT_HEADER);
6567c660
KS
152 if (m == 0)
153 panic ("pk_template");
154 m -> m_act = 0;
155
156 /*
157 * Efficiency hack: leave a four byte gap at the beginning
158 * of the packet level header with the hope that this will
159 * be enough room for the link level to insert its header.
160 */
1c41f5e9 161 m -> m_data += max_linkhdr;
6567c660
KS
162 m -> m_len = PKHEADERLN;
163
164 xp = mtod (m, struct x25_packet *);
165 *(long *)xp = 0; /* ugly, but fast */
166/* xp -> q_bit = 0;*/
167 xp -> fmt_identifier = 1;
168/* xp -> lc_group_number = 0;*/
169
9a1afe6f 170 SET_LCN(xp, lcn);
6567c660
KS
171 xp -> packet_type = type;
172
c4b47c42 173 return (m);
6567c660
KS
174}
175
176/*
177 * This routine restarts all the virtual circuits. Actually,
178 * the virtual circuits are not "restarted" as such. Instead,
179 * any active switched circuit is simply returned to READY
180 * state.
181 */
182
183pk_restart (pkp, restart_cause)
184register struct pkcb *pkp;
185int restart_cause;
186{
c4b47c42 187 register struct mbuf *m;
6567c660
KS
188 register struct pklcd *lcp;
189 register int i;
190
191 /* Restart all logical channels. */
1c41f5e9 192 if (pkp -> pk_chan == 0)
039be508 193 return;
1c41f5e9
KS
194 for (i = 1; i <= pkp -> pk_maxlcn; ++i)
195 if ((lcp = pkp -> pk_chan[i]) != NULL) {
c4b47c42 196 if (lcp -> lcd_so) {
1c41f5e9 197 lcp -> lcd_so -> so_error = ENETRESET;
c4b47c42
KS
198 pk_close (lcp);
199 } else {
200 pk_flush (lcp);
201 lcp -> lcd_state = READY;
202 if (lcp -> lcd_upper)
32f30cd6 203 lcp -> lcd_upper (lcp, 0);
c4b47c42 204 }
6567c660
KS
205 }
206
207 if (restart_cause < 0)
208 return;
209
1c41f5e9
KS
210 pkp -> pk_state = DTE_SENT_RESTART;
211 lcp = pkp -> pk_chan[0];
c4b47c42
KS
212 m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESTART);
213 m -> m_len += 2;
32f30cd6
KS
214 mtod (m, struct x25_packet *) -> packet_data = 0; /* DTE only */
215 mtod (m, octet *)[4] = restart_cause;
6567c660
KS
216 pk_output (lcp);
217}
218
219
220/*
221 * This procedure frees up the Logical Channel Descripter.
222 */
223
6567c660
KS
224pk_freelcd (lcp)
225register struct pklcd *lcp;
226{
227 if (lcp == NULL)
228 return;
229
6567c660
KS
230 if (lcp -> lcd_lcn > 0)
231 lcp -> lcd_pkp -> pk_chan[lcp -> lcd_lcn] = NULL;
232
32f30cd6
KS
233 pk_flush (lcp);
234 remque (&lcp -> lcd_q);
235 free ((caddr_t)lcp, M_PCB);
6567c660
KS
236}
237
238
239/*
240 * Bind a address and protocol value to a socket. The important
241 * part is the protocol value - the first four characters of the
242 * Call User Data field.
243 */
244
245pk_bind (lcp, nam)
246struct pklcd *lcp;
247struct mbuf *nam;
248{
6567c660 249 register struct pkcb *pkp;
6567c660 250 register struct pklcd *pp;
ffababe5 251 register struct sockaddr_x25 *sa;
6567c660
KS
252
253 if (nam == NULL)
254 return (EADDRNOTAVAIL);
255 if (lcp -> lcd_ceaddr) /* XXX */
256 return (EADDRINUSE);
c4b47c42 257 if (pk_checksockaddr (nam))
6567c660
KS
258 return (EINVAL);
259 sa = mtod (nam, struct sockaddr_x25 *);
260
261 /*
262 * If the user wishes to accept calls only from a particular
263 * net (net != 0), make sure the net is known
264 */
265
266 if (sa -> x25_net)
267 for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
268 if (pkp == 0)
269 return (ENETUNREACH);
4507dea2 270 if (pkp -> pk_xcp -> xc_addr.x25_net == sa -> x25_net)
6567c660
KS
271 break;
272 }
273
c4b47c42
KS
274 /*
275 * For ISO's sake permit default listeners, but only one such . . .
276 */
277 for (pp = pk_listenhead; pp; pp = pp -> lcd_listen) {
278 register struct sockaddr_x25 *sa2 = pp -> lcd_ceaddr;
279 if ((sa2 -> x25_udlen == sa -> x25_udlen) &&
280 (sa2 -> x25_udlen == 0 ||
281 (bcmp (sa2 -> x25_udata, sa -> x25_udata,
282 min (sa2 -> x25_udlen, sa -> x25_udlen)) == 0)))
283 return (EADDRINUSE);
284 }
ffababe5
KS
285 lcp -> lcd_laddr = *sa;
286 lcp -> lcd_ceaddr = &lcp -> lcd_laddr;
6567c660
KS
287 return (0);
288}
289
c4b47c42
KS
290/*
291 * Include a bound control block in the list of listeners.
292 */
293pk_listen (lcp)
294register struct pklcd *lcp;
295{
296 register struct pklcd **pp;
297
298 if (lcp -> lcd_ceaddr == 0)
299 return (EDESTADDRREQ);
300
301 lcp -> lcd_state = LISTEN;
302 /*
303 * Add default listener at end, any others at start.
304 */
305 if (lcp -> lcd_ceaddr -> x25_udlen == 0) {
306 for (pp = &pk_listenhead; *pp; )
307 pp = &((*pp) -> lcd_listen);
308 *pp = lcp;
309 } else {
310 lcp -> lcd_listen = pk_listenhead;
311 pk_listenhead = lcp;
312 }
313 return (0);
314}
315/*
316 * Include a listening control block for the benefit of other protocols.
317 */
318pk_protolisten (spi, spilen, callee)
32f30cd6 319int (*callee) ();
c4b47c42
KS
320{
321 register struct pklcd *lcp = pk_attach ((struct socket *)0);
322 register struct mbuf *nam;
323 register struct sockaddr_x25 *sa;
324 int error = ENOBUFS;
325
326 if (lcp) {
32f30cd6
KS
327 if (nam = m_getclr (MT_SONAME, M_DONTWAIT)) {
328 sa = mtod (nam, struct sockaddr_x25 *);
c4b47c42
KS
329 sa -> x25_family = AF_CCITT;
330 sa -> x25_len = nam -> m_len = sizeof (*sa);
331 sa -> x25_udlen = spilen;
332 sa -> x25_udata[0] = spi;
333 lcp -> lcd_upper = callee;
334 lcp -> lcd_flags = X25_MBS_HOLD;
335 error = pk_bind (lcp, nam) || pk_listen (lcp);
336 (void) m_free (nam);
337 }
338 if (error)
32f30cd6 339 pk_freelcd (lcp);
c4b47c42
KS
340 }
341 return error; /* Hopefully Zero !*/
342}
343
6567c660
KS
344/*
345 * Associate a logical channel descriptor with a network.
346 * Fill in the default network specific parameters and then
347 * set any parameters explicitly specified by the user or
348 * by the remote DTE.
349 */
350
351pk_assoc (pkp, lcp, sa)
352register struct pkcb *pkp;
353register struct pklcd *lcp;
354register struct sockaddr_x25 *sa;
355{
356
357 lcp -> lcd_pkp = pkp;
358 lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize;
359 lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize;
360 lcp -> lcd_rsn = MODULUS - 1;
361 pkp -> pk_chan[lcp -> lcd_lcn] = lcp;
362
363 if (sa -> x25_opts.op_psize)
364 lcp -> lcd_packetsize = sa -> x25_opts.op_psize;
365 else
366 sa -> x25_opts.op_psize = lcp -> lcd_packetsize;
367 if (sa -> x25_opts.op_wsize)
368 lcp -> lcd_windowsize = sa -> x25_opts.op_wsize;
369 else
370 sa -> x25_opts.op_wsize = lcp -> lcd_windowsize;
4507dea2 371 sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net;
6567c660
KS
372 lcp -> lcd_flags = sa -> x25_opts.op_flags;
373 lcp -> lcd_stime = time.tv_sec;
374}
375
c4b47c42 376pk_connect (lcp, sa)
6567c660 377register struct pklcd *lcp;
ffababe5 378register struct sockaddr_x25 *sa;
6567c660
KS
379{
380 register struct pkcb *pkp;
6567c660 381
6567c660
KS
382 if (sa -> x25_addr[0] == '\0')
383 return (EDESTADDRREQ);
1c41f5e9
KS
384 if (lcp -> lcd_pkp == 0)
385 for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
6567c660
KS
386 if (pkp == 0)
387 return (ENETUNREACH);
388 /*
389 * use first net configured (last in list
390 * headed by pkcbhead) if net is zero
391 */
392 if (sa -> x25_net == 0 && pkp -> pk_next == 0)
393 break;
4507dea2 394 if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net)
6567c660
KS
395 break;
396 }
397
398 if (pkp -> pk_state != DTE_READY)
399 return (ENETDOWN);
400 if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0)
401 return (EMFILE);
ffababe5 402 lcp -> lcd_faddr = *sa;
1c41f5e9 403 lcp -> lcd_ceaddr = & lcp -> lcd_faddr;
6567c660 404 pk_assoc (pkp, lcp, lcp -> lcd_ceaddr);
4507dea2 405 if (lcp -> lcd_so)
039be508 406 soisconnecting (lcp -> lcd_so);
6567c660 407 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL);
ffababe5 408 pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp);
32f30cd6 409 return (*pkp -> pk_start) (lcp);
6567c660
KS
410}
411
412/*
413 * Build the rest of the CALL REQUEST packet. Fill in calling
414 * address, facilities fields and the user data field.
415 */
416
ffababe5 417pk_callrequest (lcp, sa, xcp)
6567c660 418struct pklcd *lcp;
ffababe5 419register struct sockaddr_x25 *sa;
6567c660
KS
420register struct x25config *xcp;
421{
422 register struct x25_calladdr *a;
c4b47c42 423 register struct mbuf *m = lcp -> lcd_template;
32f30cd6 424 register struct x25_packet *xp = mtod (m, struct x25_packet *);
6567c660
KS
425 unsigned posn = 0;
426 octet *cp;
6567c660 427
9a1afe6f 428 if (lcp -> lcd_flags & X25_DBIT)
c4b47c42
KS
429 xp -> d_bit = 1;
430 a = (struct x25_calladdr *) &xp -> packet_data;
4507dea2 431 a -> calling_addrlen = strlen (xcp -> xc_addr.x25_addr);
6567c660
KS
432 a -> called_addrlen = strlen (sa -> x25_addr);
433 cp = (octet *) a -> address_field;
434 to_bcd (&cp, (int)a -> called_addrlen, sa -> x25_addr, &posn);
4507dea2 435 to_bcd (&cp, (int)a -> calling_addrlen, xcp -> xc_addr.x25_addr, &posn);
6567c660
KS
436 if (posn & 0x01)
437 *cp++ &= 0xf0;
6567c660
KS
438 m -> m_len += cp - (octet *) a;
439
c4b47c42 440 if (lcp -> lcd_facilities) {
32f30cd6
KS
441 m -> m_pkthdr.len +=
442 (m -> m_next = lcp -> lcd_facilities) -> m_len;
c4b47c42 443 lcp -> lcd_facilities = 0;
c4b47c42
KS
444 } else
445 build_facilities (m, sa, (int)xcp -> xc_type);
446
32f30cd6 447 m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata);
6567c660
KS
448#ifdef ANDREW
449 printf ("call: ");
1c41f5e9 450 for (cp = mtod (m, octet *), posn = 0; posn < m -> m_len; ++posn)
6567c660
KS
451 printf ("%x ", *cp++);
452 printf ("\n");
453#endif
454}
455
32f30cd6 456static
c4b47c42
KS
457build_facilities (m, sa, type)
458register struct mbuf *m;
6567c660
KS
459struct sockaddr_x25 *sa;
460{
c4b47c42 461 register octet *cp;
6567c660
KS
462 register octet *fcp;
463 register int revcharge;
464
32f30cd6 465 cp = mtod (m, octet *) + m -> m_len;
c4b47c42 466 fcp = cp + 1;
6567c660
KS
467 revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0;
468 /*
469 * This is specific to Datapac X.25(1976) DTEs. International
470 * calls must have the "hi priority" bit on.
471 */
472 if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128)
473 revcharge |= 02;
474 if (revcharge) {
475 *fcp++ = FACILITIES_REVERSE_CHARGE;
476 *fcp++ = revcharge;
477 }
478 switch (type) {
479 case X25_1980:
480 case X25_1984:
481 *fcp++ = FACILITIES_PACKETSIZE;
482 *fcp++ = sa -> x25_opts.op_psize;
483 *fcp++ = sa -> x25_opts.op_psize;
484
485 *fcp++ = FACILITIES_WINDOWSIZE;
486 *fcp++ = sa -> x25_opts.op_wsize;
487 *fcp++ = sa -> x25_opts.op_wsize;
488 }
c4b47c42
KS
489 *cp = fcp - cp - 1;
490 m -> m_pkthdr.len = (m -> m_len += *cp + 1);
6567c660
KS
491}
492
493to_bcd (a, len, x, posn)
494register octet **a;
495register char *x;
496register int len;
497register unsigned *posn;
498{
499 while (--len >= 0)
500 if ((*posn)++ & 0x01)
501 *(*a)++ |= *x++ & 0x0F;
502 else
503 **a = *x++ << 4;
504}
505
506/*
507 * This routine gets the first available logical channel number. The
508 * search is from the highest number to lowest number (DTE).
509 */
510
511pk_getlcn (pkp)
512register struct pkcb *pkp;
513{
514 register int i;
515
1c41f5e9 516 if (pkp -> pk_chan == 0)
039be508 517 return (0);
6567c660
KS
518 for (i = pkp -> pk_maxlcn; i > 0; --i)
519 if (pkp -> pk_chan[i] == NULL)
520 break;
521 return (i);
522
523}
524
6567c660
KS
525/*
526 * This procedure sends a CLEAR request packet. The lc state is
527 * set to "SENT_CLEAR".
528 */
529
c4b47c42
KS
530pk_clear (lcp, diagnostic, abortive)
531register struct pklcd *lcp;
6567c660 532{
c4b47c42
KS
533 register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR);
534
535 m -> m_len += 2;
32f30cd6
KS
536 mtod (m, struct x25_packet *) -> packet_data = 0;
537 mtod (m, octet *)[4] = diagnostic;
c4b47c42
KS
538 if (lcp -> lcd_facilities) {
539 m -> m_next = lcp -> lcd_facilities;
540 m -> m_pkthdr.len += m -> m_next -> m_len;
541 lcp -> lcd_facilities = 0;
542 }
543 if (abortive)
544 lcp -> lcd_template = m;
545 else {
546 struct socket *so = lcp -> lcd_so;
547 struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb;
32f30cd6 548 sbappendrecord (sb, m);
c4b47c42 549 }
6567c660
KS
550 pk_output (lcp);
551
552}
553
32f30cd6
KS
554/*
555 * This procedure generates RNR's or RR's to inhibit or enable
556 * inward data flow, if the current state changes (blocked ==> open or
557 * vice versa), or if forced to generate one. One forces RNR's to ack data.
558 */
559pk_flowcontrol (lcp, inhibit, forced)
560register struct pklcd *lcp;
561{
562 inhibit = (inhibit != 0);
563 if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER ||
564 (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit))
565 return;
566 lcp -> lcd_rxrnr_condition = inhibit;
567 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, inhibit ? RNR : RR);
568 pk_output (lcp);
569}
570
6567c660 571/*
32f30cd6 572 * This procedure sends a RESET request packet. It re-intializes
6567c660
KS
573 * virtual circuit.
574 */
575
576static
c4b47c42 577pk_reset (lcp, diagnostic)
6567c660
KS
578register struct pklcd *lcp;
579{
c4b47c42
KS
580 register struct mbuf *m;
581 register struct socket *so = lcp -> lcd_so;
6567c660
KS
582
583 if (lcp -> lcd_state != DATA_TRANSFER)
584 return;
585
c4b47c42
KS
586 if (so)
587 so -> so_error = ECONNRESET;
6567c660
KS
588 lcp -> lcd_reset_condition = TRUE;
589
590 /* Reset all the control variables for the channel. */
c4b47c42 591 pk_flush (lcp);
6567c660
KS
592 lcp -> lcd_window_condition = lcp -> lcd_rnr_condition =
593 lcp -> lcd_intrconf_pending = FALSE;
594 lcp -> lcd_rsn = MODULUS - 1;
595 lcp -> lcd_ssn = 0;
596 lcp -> lcd_output_window = lcp -> lcd_input_window =
597 lcp -> lcd_last_transmitted_pr = 0;
c4b47c42
KS
598 m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET);
599 m -> m_len += 2;
32f30cd6
KS
600 mtod (m, struct x25_packet *) -> packet_data = 0;
601 mtod (m, octet *)[4] = diagnostic;
c4b47c42
KS
602 pk_output (lcp);
603
604}
605
606/*
607 * This procedure frees all data queued for output or delivery on a
608 * virtual circuit.
609 */
610
611pk_flush (lcp)
612register struct pklcd *lcp;
613{
614 register struct socket *so;
615
616 if (lcp -> lcd_template)
617 m_freem (lcp -> lcd_template);
618
619 if (lcp -> lcd_cps) {
32f30cd6 620 m_freem (lcp -> lcd_cps);
c4b47c42
KS
621 lcp -> lcd_cps = 0;
622 }
32f30cd6
KS
623 if (lcp -> lcd_facilities) {
624 m_freem (lcp -> lcd_facilities);
625 lcp -> lcd_facilities = 0;
626 }
627 if (so = lcp -> lcd_so) {
039be508
KS
628 sbflush (&so -> so_rcv);
629 sbflush (&so -> so_snd);
c4b47c42
KS
630 } else
631 sbflush (&lcp -> lcd_sb);
6567c660
KS
632}
633
6567c660
KS
634/*
635 * This procedure handles all local protocol procedure errors.
636 */
637
c4b47c42 638pk_procerror (error, lcp, errstr, diagnostic)
6567c660
KS
639register struct pklcd *lcp;
640char *errstr;
641{
642
643 pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr);
644
645 switch (error) {
646 case CLEAR:
1c41f5e9
KS
647 if (lcp -> lcd_so) {
648 lcp -> lcd_so -> so_error = ECONNABORTED;
649 soisdisconnecting (lcp -> lcd_so);
6567c660 650 }
c4b47c42 651 pk_clear (lcp, diagnostic, 1);
6567c660
KS
652 break;
653
654 case RESET:
c4b47c42 655 pk_reset (lcp, diagnostic);
6567c660
KS
656 }
657}
658
659/*
660 * This procedure is called during the DATA TRANSFER state to check
661 * and process the P(R) values received in the DATA, RR OR RNR
662 * packets.
663 */
664
665pk_ack (lcp, pr)
666struct pklcd *lcp;
667unsigned pr;
668{
669 register struct socket *so = lcp -> lcd_so;
670
671 if (lcp -> lcd_output_window == pr)
672 return (PACKET_OK);
673 if (lcp -> lcd_output_window < lcp -> lcd_ssn) {
674 if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) {
c4b47c42
KS
675 pk_procerror (RESET, lcp,
676 "p(r) flow control error", 2);
6567c660
KS
677 return (ERROR_PACKET);
678 }
679 }
680 else {
681 if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) {
c4b47c42 682 pk_procerror (RESET, lcp,
32f30cd6 683 "p(r) flow control error #2", 2);
6567c660
KS
684 return (ERROR_PACKET);
685 }
686 }
687
688 lcp -> lcd_output_window = pr; /* Rotate window. */
689 if (lcp -> lcd_window_condition == TRUE)
690 lcp -> lcd_window_condition = FALSE;
691
039be508 692 if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel))
6567c660 693 sowwakeup (so);
b84e7ca8 694 if (lcp -> lcd_upper)
32f30cd6 695 (*lcp -> lcd_upper) (lcp, 0);
6567c660
KS
696
697 return (PACKET_OK);
698}
699
700/*
701 * This procedure decodes the X.25 level 3 packet returning a
702 * code to be used in switchs or arrays.
703 */
704
705pk_decode (xp)
706register struct x25_packet *xp;
707{
708 register int type;
709
710 if (xp -> fmt_identifier != 1)
711 return (INVALID_PACKET);
c4b47c42 712#ifdef ancient_history
6567c660
KS
713 /*
714 * Make sure that the logical channel group number is 0.
715 * This restriction may be removed at some later date.
716 */
717 if (xp -> lc_group_number != 0)
718 return (INVALID_PACKET);
c4b47c42 719#endif
6567c660
KS
720 /*
721 * Test for data packet first.
722 */
723 if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR))
724 return (DATA);
725
726 /*
727 * Test if flow control packet (RR or RNR).
728 */
729 if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR))
32f30cd6
KS
730 switch (xp -> packet_type & 0x1f) {
731 case X25_RR:
6567c660 732 return (RR);
32f30cd6 733 case X25_RNR:
6567c660 734 return (RNR);
32f30cd6
KS
735 case X25_REJECT:
736 return (REJECT);
737 }
6567c660
KS
738
739 /*
740 * Determine the rest of the packet types.
741 */
742 switch (xp -> packet_type) {
743 case X25_CALL:
744 type = CALL;
745 break;
746
747 case X25_CALL_ACCEPTED:
748 type = CALL_ACCEPTED;
749 break;
750
751 case X25_CLEAR:
752 type = CLEAR;
753 break;
754
755 case X25_CLEAR_CONFIRM:
756 type = CLEAR_CONF;
757 break;
758
759 case X25_INTERRUPT:
760 type = INTERRUPT;
761 break;
762
763 case X25_INTERRUPT_CONFIRM:
764 type = INTERRUPT_CONF;
765 break;
766
767 case X25_RESET:
768 type = RESET;
769 break;
770
771 case X25_RESET_CONFIRM:
772 type = RESET_CONF;
773 break;
774
775 case X25_RESTART:
776 type = RESTART;
777 break;
778
779 case X25_RESTART_CONFIRM:
780 type = RESTART_CONF;
781 break;
782
32f30cd6 783 case X25_DIAGNOSTIC:
5336ccc3 784 type = DIAG_TYPE;
32f30cd6
KS
785 break;
786
6567c660
KS
787 default:
788 type = INVALID_PACKET;
789 }
790 return (type);
791}
792
793/*
794 * A restart packet has been received. Print out the reason
795 * for the restart.
796 */
797
798pk_restartcause (pkp, xp)
799struct pkcb *pkp;
800register struct x25_packet *xp;
801{
802 register struct x25config *xcp = pkp -> pk_xcp;
9a1afe6f 803 register int lcn = LCN(xp);
6567c660
KS
804
805 switch (xp -> packet_data) {
806 case X25_RESTART_LOCAL_PROCEDURE_ERROR:
807 pk_message (lcn, xcp, "restart: local procedure error");
808 break;
809
810 case X25_RESTART_NETWORK_CONGESTION:
811 pk_message (lcn, xcp, "restart: network congestion");
812 break;
813
814 case X25_RESTART_NETWORK_OPERATIONAL:
815 pk_message (lcn, xcp, "restart: network operational");
816 break;
817
818 default:
819 pk_message (lcn, xcp, "restart: unknown cause");
820 }
821}
822
823#define MAXRESETCAUSE 7
824
825int Reset_cause[] = {
826 EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG
827};
828
829/*
830 * A reset packet has arrived. Return the cause to the user.
831 */
832
833pk_resetcause (pkp, xp)
834struct pkcb *pkp;
835register struct x25_packet *xp;
836{
1c41f5e9 837 register struct pklcd *lcp =
9a1afe6f 838 pkp -> pk_chan[LCN(xp)];
6567c660
KS
839 register int code = xp -> packet_data;
840
841 if (code > MAXRESETCAUSE)
842 code = 7; /* EXRNCG */
843
32f30cd6
KS
844 pk_message(LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x",
845 xp -> packet_data, 4[(u_char *)xp]);
846
1c41f5e9 847 lcp -> lcd_so -> so_error = Reset_cause[code];
6567c660
KS
848}
849
850#define MAXCLEARCAUSE 25
851
852int Clear_cause[] = {
853 EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0,
854 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE,
855 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC
856};
857
858/*
859 * A clear packet has arrived. Return the cause to the user.
860 */
861
862pk_clearcause (pkp, xp)
863struct pkcb *pkp;
864register struct x25_packet *xp;
865{
1c41f5e9 866 register struct pklcd *lcp =
9a1afe6f 867 pkp -> pk_chan[LCN(xp)];
6567c660
KS
868 register int code = xp -> packet_data;
869
870 if (code > MAXCLEARCAUSE)
871 code = 5; /* EXRNCG */
1c41f5e9 872 lcp -> lcd_so -> so_error = Clear_cause[code];
6567c660
KS
873}
874
875char *
876format_ntn (xcp)
877register struct x25config *xcp;
878{
4507dea2
KS
879
880 return (xcp -> xc_addr.x25_addr);
6567c660
KS
881}
882
883/* VARARGS1 */
884pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6)
885struct x25config *xcp;
886char *fmt;
887{
888
889 if (lcn)
890 if (pkcbhead -> pk_next)
891 printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn);
892 else
893 printf ("X.25: lcn %d: ", lcn);
894 else
895 if (pkcbhead -> pk_next)
896 printf ("X.25(%s): ", format_ntn (xcp));
897 else
898 printf ("X.25: ");
899
900 printf (fmt, a1, a2, a3, a4, a5, a6);
901 printf ("\n");
902}
1c41f5e9 903
32f30cd6 904pk_ifattach (ia, lloutput, llnext)
1c41f5e9 905register struct x25_ifaddr *ia;
32f30cd6 906int (*lloutput) ();
1c41f5e9
KS
907caddr_t llnext;
908{
909 /* this is here because you can't include both pk_var and hd_var */
910 /* this will probably be replace by a streams gluing mechanism */
911 ia -> ia_pkcb.pk_lloutput = lloutput;
912 ia -> ia_pkcb.pk_llnext = llnext;
913}
914
32f30cd6 915pk_fragment (lcp, m0, qbit, mbit, wait)
1c41f5e9
KS
916struct mbuf *m0;
917register struct pklcd *lcp;
918{
919 register struct mbuf *m = m0;
920 register struct x25_packet *xp;
921 register struct sockbuf *sb;
32f30cd6 922 struct mbuf *head = 0, *next, **mp = &head, *m_split ();
1c41f5e9
KS
923 int totlen, psize = 1 << (lcp -> lcd_packetsize);
924
925 if (m == 0)
926 return;
c4b47c42 927 if (m -> m_flags & M_PKTHDR == 0)
32f30cd6 928 panic ("pk_fragment");
1c41f5e9 929 totlen = m -> m_pkthdr.len;
9a1afe6f 930 m -> m_act = 0;
1c41f5e9
KS
931 sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb;
932 do {
933 if (totlen > psize) {
32f30cd6 934 if ((next = m_split (m, psize, wait)) == 0)
1c41f5e9 935 goto abort;
1c41f5e9 936 totlen -= psize;
9a1afe6f
KS
937 } else
938 next = 0;
1c41f5e9
KS
939 M_PREPEND(m, PKHEADERLN, wait);
940 if (m == 0)
941 goto abort;
9a1afe6f
KS
942 *mp = m;
943 mp = & m -> m_act;
944 *mp = 0;
32f30cd6 945 xp = mtod (m, struct x25_packet *);
1c41f5e9
KS
946 0[(char *)xp] = 0;
947 if (qbit)
9a1afe6f
KS
948 xp -> q_bit = 1;
949 if (lcp -> lcd_flags & X25_DBIT)
950 xp -> d_bit = 1;
1c41f5e9 951 xp -> fmt_identifier = 1;
1c41f5e9 952 xp -> packet_type = X25_DATA;
9a1afe6f
KS
953 SET_LCN(xp, lcp -> lcd_lcn);
954 if (next || (mbit && (totlen == psize ||
955 (lcp -> lcd_flags & X25_DBIT))))
1c41f5e9 956 MBIT(xp) = 1;
1c41f5e9 957 } while (m = next);
9a1afe6f 958 for (m = head; m; m = next) {
1c41f5e9
KS
959 next = m -> m_act;
960 m -> m_act = 0;
32f30cd6 961 sbappendrecord (sb, m);
1c41f5e9
KS
962 }
963 return 0;
964abort:
9a1afe6f 965 if (wait)
32f30cd6 966 panic ("pk_fragment null mbuf after wait");
9a1afe6f 967 if (next)
32f30cd6 968 m_freem (next);
9a1afe6f 969 for (m = head; m; m = next) {
1c41f5e9 970 next = m -> m_act;
32f30cd6 971 m_freem (m);
1c41f5e9
KS
972 }
973 return ENOBUFS;
974}
9a1afe6f
KS
975
976struct mbuf *
32f30cd6 977m_split (m0, len0, wait)
9a1afe6f
KS
978register struct mbuf *m0;
979int len0;
980{
981 register struct mbuf *m, *n;
982 unsigned len = len0;
983
984 for (m = m0; m && len > m -> m_len; m = m -> m_next)
985 len -= m -> m_len;
986 if (m == 0)
987 return (0);
988 if (m0 -> m_flags & M_PKTHDR) {
989 MGETHDR(n, wait, m0 -> m_type);
990 if (n == 0)
991 return (0);
992 n -> m_pkthdr.rcvif = m0 -> m_pkthdr.rcvif;
993 n -> m_pkthdr.len = m0 -> m_pkthdr.len - len0;
994 m0 -> m_pkthdr.len = len0;
995 if (m -> m_flags & M_EXT)
996 goto extpacket;
997 if (len > MHLEN) {
998 /* m can't be the lead packet */
999 MH_ALIGN(n, 0);
32f30cd6 1000 n -> m_next = m_split (m, len, wait);
9a1afe6f 1001 if (n -> m_next == 0) {
32f30cd6 1002 (void) m_free (n);
9a1afe6f
KS
1003 return (0);
1004 } else
1005 return (n);
1006 } else
1007 MH_ALIGN(n, len);
1008 } else if (len == m -> m_len) {
1009 n = m -> m_next;
1010 m -> m_next = 0;
1011 return (n);
1012 }
1013extpacket:
1014 len = m -> m_len - len; /* remainder to be copied */
1015 m -> m_len -= len; /* now equals original len */
c4b47c42 1016 if (m -> m_flags & M_EXT) {
9a1afe6f
KS
1017 n -> m_flags |= M_EXT;
1018 n -> m_ext = m -> m_ext;
32f30cd6 1019 mclrefcnt[mtocl (m -> m_ext.ext_buf)]++;
9a1afe6f
KS
1020 n -> m_data = m -> m_data + m -> m_len;
1021 } else {
1022 MGET(n, wait, m -> m_type);
1023 if (n == 0) {
1024 m -> m_len += len;
1025 return (0);
1026 }
1027 M_ALIGN(n, len);
32f30cd6 1028 bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len);
9a1afe6f
KS
1029 }
1030 n -> m_len = len;
1031 n -> m_next = m -> m_next;
1032 m -> m_next = 0;
1033 return (n);
1034}