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