many fixes & changes -- add routine to glue or spit vc to route;
[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 *
fe9ae892 12 * @(#)pk_subr.c 7.14 (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;
334 error = pk_bind (lcp, nam) || pk_listen (lcp);
335 (void) m_free (nam);
336 }
337 if (error)
32f30cd6 338 pk_freelcd (lcp);
c4b47c42
KS
339 }
340 return error; /* Hopefully Zero !*/
341}
342
6567c660
KS
343/*
344 * Associate a logical channel descriptor with a network.
345 * Fill in the default network specific parameters and then
346 * set any parameters explicitly specified by the user or
347 * by the remote DTE.
348 */
349
350pk_assoc (pkp, lcp, sa)
351register struct pkcb *pkp;
352register struct pklcd *lcp;
353register struct sockaddr_x25 *sa;
354{
355
356 lcp -> lcd_pkp = pkp;
357 lcp -> lcd_packetsize = pkp -> pk_xcp -> xc_psize;
358 lcp -> lcd_windowsize = pkp -> pk_xcp -> xc_pwsize;
359 lcp -> lcd_rsn = MODULUS - 1;
360 pkp -> pk_chan[lcp -> lcd_lcn] = lcp;
361
362 if (sa -> x25_opts.op_psize)
363 lcp -> lcd_packetsize = sa -> x25_opts.op_psize;
364 else
365 sa -> x25_opts.op_psize = lcp -> lcd_packetsize;
366 if (sa -> x25_opts.op_wsize)
367 lcp -> lcd_windowsize = sa -> x25_opts.op_wsize;
368 else
369 sa -> x25_opts.op_wsize = lcp -> lcd_windowsize;
4507dea2 370 sa -> x25_net = pkp -> pk_xcp -> xc_addr.x25_net;
6567c660
KS
371 lcp -> lcd_flags = sa -> x25_opts.op_flags;
372 lcp -> lcd_stime = time.tv_sec;
373}
374
c4b47c42 375pk_connect (lcp, sa)
6567c660 376register struct pklcd *lcp;
ffababe5 377register struct sockaddr_x25 *sa;
6567c660
KS
378{
379 register struct pkcb *pkp;
6567c660 380
6567c660
KS
381 if (sa -> x25_addr[0] == '\0')
382 return (EDESTADDRREQ);
1c41f5e9
KS
383 if (lcp -> lcd_pkp == 0)
384 for (pkp = pkcbhead; ; pkp = pkp -> pk_next) {
6567c660
KS
385 if (pkp == 0)
386 return (ENETUNREACH);
387 /*
388 * use first net configured (last in list
389 * headed by pkcbhead) if net is zero
390 */
391 if (sa -> x25_net == 0 && pkp -> pk_next == 0)
392 break;
4507dea2 393 if (sa -> x25_net == pkp -> pk_xcp -> xc_addr.x25_net)
6567c660
KS
394 break;
395 }
396
397 if (pkp -> pk_state != DTE_READY)
398 return (ENETDOWN);
399 if ((lcp -> lcd_lcn = pk_getlcn (pkp)) == 0)
400 return (EMFILE);
ffababe5 401 lcp -> lcd_faddr = *sa;
1c41f5e9 402 lcp -> lcd_ceaddr = & lcp -> lcd_faddr;
6567c660 403 pk_assoc (pkp, lcp, lcp -> lcd_ceaddr);
4507dea2 404 if (lcp -> lcd_so)
039be508 405 soisconnecting (lcp -> lcd_so);
6567c660 406 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_CALL);
ffababe5 407 pk_callrequest (lcp, lcp -> lcd_ceaddr, pkp -> pk_xcp);
32f30cd6 408 return (*pkp -> pk_start) (lcp);
6567c660
KS
409}
410
fe9ae892
KS
411struct bcdinfo {
412 octet *cp;
413 unsigned posn;
414};
6567c660
KS
415/*
416 * Build the rest of the CALL REQUEST packet. Fill in calling
417 * address, facilities fields and the user data field.
418 */
419
ffababe5 420pk_callrequest (lcp, sa, xcp)
6567c660 421struct pklcd *lcp;
ffababe5 422register struct sockaddr_x25 *sa;
6567c660
KS
423register struct x25config *xcp;
424{
425 register struct x25_calladdr *a;
c4b47c42 426 register struct mbuf *m = lcp -> lcd_template;
32f30cd6 427 register struct x25_packet *xp = mtod (m, struct x25_packet *);
fe9ae892 428 struct bcdinfo b;
6567c660 429
9a1afe6f 430 if (lcp -> lcd_flags & X25_DBIT)
c4b47c42
KS
431 xp -> d_bit = 1;
432 a = (struct x25_calladdr *) &xp -> packet_data;
fe9ae892
KS
433 b.cp = (octet *) a -> address_field;
434 b.posn = 0;
435 a -> called_addrlen = to_bcd (&b, sa, xcp);
436 a -> calling_addrlen = to_bcd (&b, &xcp -> xc_addr, xcp);
437 if (b.posn & 0x01)
438 *b.cp++ &= 0xf0;
439 m -> m_pkthdr.len = m -> m_len += b.cp - (octet *) a;
6567c660 440
c4b47c42 441 if (lcp -> lcd_facilities) {
32f30cd6 442 m -> m_pkthdr.len +=
fe9ae892 443 (m -> m_next = lcp -> lcd_facilities) -> m_pkthdr.len;
c4b47c42 444 lcp -> lcd_facilities = 0;
c4b47c42 445 } else
fe9ae892 446 pk_build_facilities (m, sa, (int)xcp -> xc_type);
c4b47c42 447
32f30cd6 448 m_copyback (m, m -> m_pkthdr.len, sa -> x25_udlen, sa -> x25_udata);
6567c660
KS
449}
450
fe9ae892 451pk_build_facilities (m, sa, type)
c4b47c42 452register struct mbuf *m;
6567c660
KS
453struct sockaddr_x25 *sa;
454{
c4b47c42 455 register octet *cp;
6567c660
KS
456 register octet *fcp;
457 register int revcharge;
458
32f30cd6 459 cp = mtod (m, octet *) + m -> m_len;
c4b47c42 460 fcp = cp + 1;
6567c660
KS
461 revcharge = sa -> x25_opts.op_flags & X25_REVERSE_CHARGE ? 1 : 0;
462 /*
463 * This is specific to Datapac X.25(1976) DTEs. International
464 * calls must have the "hi priority" bit on.
465 */
466 if (type == X25_1976 && sa -> x25_opts.op_psize == X25_PS128)
467 revcharge |= 02;
468 if (revcharge) {
469 *fcp++ = FACILITIES_REVERSE_CHARGE;
470 *fcp++ = revcharge;
471 }
472 switch (type) {
473 case X25_1980:
474 case X25_1984:
475 *fcp++ = FACILITIES_PACKETSIZE;
476 *fcp++ = sa -> x25_opts.op_psize;
477 *fcp++ = sa -> x25_opts.op_psize;
478
479 *fcp++ = FACILITIES_WINDOWSIZE;
480 *fcp++ = sa -> x25_opts.op_wsize;
481 *fcp++ = sa -> x25_opts.op_wsize;
482 }
c4b47c42
KS
483 *cp = fcp - cp - 1;
484 m -> m_pkthdr.len = (m -> m_len += *cp + 1);
6567c660
KS
485}
486
fe9ae892
KS
487to_bcd (b, sa, xcp)
488register struct bcdinfo *b;
489struct sockaddr_x25 *sa;
490register struct x25config *xcp;
6567c660 491{
fe9ae892
KS
492 register char *x = sa -> x25_addr;
493 unsigned start = b -> posn;
494 /*
495 * The nodnic and prepnd0 stuff looks tedious,
496 * but it does allow full X.121 addresses to be used,
497 * which is handy for routing info (& OSI type 37 addresses).
498 */
499 if (xcp -> xc_addr.x25_net && (xcp -> xc_nodnic || xcp -> xc_prepnd0)) {
500 char dnicname[sizeof(long) * NBBY/3 + 2];
501 register char *p = dnicname;
502
503 sprintf (p, "%d", xcp -> xc_addr.x25_net & 0x7fff);
504 for (; *p; p++) /* *p == 0 means dnic matched */
505 if ((*p ^ *x++) & 0x0f)
506 break;
507 if (*p || xcp -> xc_nodnic == 0)
508 x = sa -> x25_addr;
509 if (*p && xcp -> xc_prepnd0) {
510 if ((b -> posn)++ & 0x01)
511 *(b -> cp)++;
512 else
513 *(b -> cp) = 0;
514 }
515 }
516 while (*x)
517 if ((b -> posn)++ & 0x01)
518 *(b -> cp)++ |= *x++ & 0x0F;
6567c660 519 else
fe9ae892
KS
520 *(b -> cp) = *x++ << 4;
521 return ((b -> posn) - start);
6567c660
KS
522}
523
524/*
525 * This routine gets the first available logical channel number. The
526 * search is from the highest number to lowest number (DTE).
527 */
528
529pk_getlcn (pkp)
530register struct pkcb *pkp;
531{
532 register int i;
533
1c41f5e9 534 if (pkp -> pk_chan == 0)
039be508 535 return (0);
6567c660
KS
536 for (i = pkp -> pk_maxlcn; i > 0; --i)
537 if (pkp -> pk_chan[i] == NULL)
538 break;
539 return (i);
540
541}
542
6567c660
KS
543/*
544 * This procedure sends a CLEAR request packet. The lc state is
545 * set to "SENT_CLEAR".
546 */
547
c4b47c42
KS
548pk_clear (lcp, diagnostic, abortive)
549register struct pklcd *lcp;
6567c660 550{
c4b47c42
KS
551 register struct mbuf *m = pk_template (lcp -> lcd_lcn, X25_CLEAR);
552
553 m -> m_len += 2;
32f30cd6
KS
554 mtod (m, struct x25_packet *) -> packet_data = 0;
555 mtod (m, octet *)[4] = diagnostic;
c4b47c42
KS
556 if (lcp -> lcd_facilities) {
557 m -> m_next = lcp -> lcd_facilities;
558 m -> m_pkthdr.len += m -> m_next -> m_len;
559 lcp -> lcd_facilities = 0;
560 }
561 if (abortive)
562 lcp -> lcd_template = m;
563 else {
564 struct socket *so = lcp -> lcd_so;
565 struct sockbuf *sb = so ? & so -> so_snd : & lcp -> lcd_sb;
32f30cd6 566 sbappendrecord (sb, m);
c4b47c42 567 }
6567c660
KS
568 pk_output (lcp);
569
570}
571
32f30cd6
KS
572/*
573 * This procedure generates RNR's or RR's to inhibit or enable
574 * inward data flow, if the current state changes (blocked ==> open or
575 * vice versa), or if forced to generate one. One forces RNR's to ack data.
576 */
577pk_flowcontrol (lcp, inhibit, forced)
578register struct pklcd *lcp;
579{
580 inhibit = (inhibit != 0);
581 if (lcp == 0 || lcp -> lcd_state != DATA_TRANSFER ||
582 (forced == 0 && lcp -> lcd_rxrnr_condition == inhibit))
583 return;
584 lcp -> lcd_rxrnr_condition = inhibit;
585 lcp -> lcd_template = pk_template (lcp -> lcd_lcn, inhibit ? RNR : RR);
586 pk_output (lcp);
587}
588
6567c660 589/*
32f30cd6 590 * This procedure sends a RESET request packet. It re-intializes
6567c660
KS
591 * virtual circuit.
592 */
593
594static
c4b47c42 595pk_reset (lcp, diagnostic)
6567c660
KS
596register struct pklcd *lcp;
597{
c4b47c42
KS
598 register struct mbuf *m;
599 register struct socket *so = lcp -> lcd_so;
6567c660
KS
600
601 if (lcp -> lcd_state != DATA_TRANSFER)
602 return;
603
c4b47c42
KS
604 if (so)
605 so -> so_error = ECONNRESET;
6567c660
KS
606 lcp -> lcd_reset_condition = TRUE;
607
608 /* Reset all the control variables for the channel. */
c4b47c42 609 pk_flush (lcp);
6567c660
KS
610 lcp -> lcd_window_condition = lcp -> lcd_rnr_condition =
611 lcp -> lcd_intrconf_pending = FALSE;
612 lcp -> lcd_rsn = MODULUS - 1;
613 lcp -> lcd_ssn = 0;
614 lcp -> lcd_output_window = lcp -> lcd_input_window =
615 lcp -> lcd_last_transmitted_pr = 0;
c4b47c42 616 m = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RESET);
822e810c 617 m -> m_pkthdr.len = m -> m_len += 2;
32f30cd6
KS
618 mtod (m, struct x25_packet *) -> packet_data = 0;
619 mtod (m, octet *)[4] = diagnostic;
c4b47c42
KS
620 pk_output (lcp);
621
622}
623
624/*
625 * This procedure frees all data queued for output or delivery on a
626 * virtual circuit.
627 */
628
629pk_flush (lcp)
630register struct pklcd *lcp;
631{
632 register struct socket *so;
633
634 if (lcp -> lcd_template)
635 m_freem (lcp -> lcd_template);
636
637 if (lcp -> lcd_cps) {
32f30cd6 638 m_freem (lcp -> lcd_cps);
c4b47c42
KS
639 lcp -> lcd_cps = 0;
640 }
32f30cd6
KS
641 if (lcp -> lcd_facilities) {
642 m_freem (lcp -> lcd_facilities);
643 lcp -> lcd_facilities = 0;
644 }
645 if (so = lcp -> lcd_so) {
039be508
KS
646 sbflush (&so -> so_rcv);
647 sbflush (&so -> so_snd);
c4b47c42
KS
648 } else
649 sbflush (&lcp -> lcd_sb);
6567c660
KS
650}
651
6567c660
KS
652/*
653 * This procedure handles all local protocol procedure errors.
654 */
655
c4b47c42 656pk_procerror (error, lcp, errstr, diagnostic)
6567c660
KS
657register struct pklcd *lcp;
658char *errstr;
659{
660
661 pk_message (lcp -> lcd_lcn, lcp -> lcd_pkp -> pk_xcp, errstr);
662
663 switch (error) {
664 case CLEAR:
1c41f5e9
KS
665 if (lcp -> lcd_so) {
666 lcp -> lcd_so -> so_error = ECONNABORTED;
667 soisdisconnecting (lcp -> lcd_so);
6567c660 668 }
c4b47c42 669 pk_clear (lcp, diagnostic, 1);
6567c660
KS
670 break;
671
672 case RESET:
c4b47c42 673 pk_reset (lcp, diagnostic);
6567c660
KS
674 }
675}
676
677/*
678 * This procedure is called during the DATA TRANSFER state to check
679 * and process the P(R) values received in the DATA, RR OR RNR
680 * packets.
681 */
682
683pk_ack (lcp, pr)
684struct pklcd *lcp;
685unsigned pr;
686{
687 register struct socket *so = lcp -> lcd_so;
688
689 if (lcp -> lcd_output_window == pr)
690 return (PACKET_OK);
691 if (lcp -> lcd_output_window < lcp -> lcd_ssn) {
692 if (pr < lcp -> lcd_output_window || pr > lcp -> lcd_ssn) {
c4b47c42
KS
693 pk_procerror (RESET, lcp,
694 "p(r) flow control error", 2);
6567c660
KS
695 return (ERROR_PACKET);
696 }
697 }
698 else {
699 if (pr < lcp -> lcd_output_window && pr > lcp -> lcd_ssn) {
c4b47c42 700 pk_procerror (RESET, lcp,
32f30cd6 701 "p(r) flow control error #2", 2);
6567c660
KS
702 return (ERROR_PACKET);
703 }
704 }
705
706 lcp -> lcd_output_window = pr; /* Rotate window. */
707 if (lcp -> lcd_window_condition == TRUE)
708 lcp -> lcd_window_condition = FALSE;
709
039be508 710 if (so && ((so -> so_snd.sb_flags & SB_WAIT) || so -> so_snd.sb_sel))
6567c660
KS
711 sowwakeup (so);
712
713 return (PACKET_OK);
714}
715
716/*
717 * This procedure decodes the X.25 level 3 packet returning a
718 * code to be used in switchs or arrays.
719 */
720
721pk_decode (xp)
722register struct x25_packet *xp;
723{
724 register int type;
725
726 if (xp -> fmt_identifier != 1)
727 return (INVALID_PACKET);
c4b47c42 728#ifdef ancient_history
6567c660
KS
729 /*
730 * Make sure that the logical channel group number is 0.
731 * This restriction may be removed at some later date.
732 */
733 if (xp -> lc_group_number != 0)
734 return (INVALID_PACKET);
c4b47c42 735#endif
6567c660
KS
736 /*
737 * Test for data packet first.
738 */
739 if (!(xp -> packet_type & DATA_PACKET_DESIGNATOR))
740 return (DATA);
741
742 /*
743 * Test if flow control packet (RR or RNR).
744 */
745 if (!(xp -> packet_type & RR_OR_RNR_PACKET_DESIGNATOR))
32f30cd6
KS
746 switch (xp -> packet_type & 0x1f) {
747 case X25_RR:
6567c660 748 return (RR);
32f30cd6 749 case X25_RNR:
6567c660 750 return (RNR);
32f30cd6
KS
751 case X25_REJECT:
752 return (REJECT);
753 }
6567c660
KS
754
755 /*
756 * Determine the rest of the packet types.
757 */
758 switch (xp -> packet_type) {
759 case X25_CALL:
760 type = CALL;
761 break;
762
763 case X25_CALL_ACCEPTED:
764 type = CALL_ACCEPTED;
765 break;
766
767 case X25_CLEAR:
768 type = CLEAR;
769 break;
770
771 case X25_CLEAR_CONFIRM:
772 type = CLEAR_CONF;
773 break;
774
775 case X25_INTERRUPT:
776 type = INTERRUPT;
777 break;
778
779 case X25_INTERRUPT_CONFIRM:
780 type = INTERRUPT_CONF;
781 break;
782
783 case X25_RESET:
784 type = RESET;
785 break;
786
787 case X25_RESET_CONFIRM:
788 type = RESET_CONF;
789 break;
790
791 case X25_RESTART:
792 type = RESTART;
793 break;
794
795 case X25_RESTART_CONFIRM:
796 type = RESTART_CONF;
797 break;
798
32f30cd6 799 case X25_DIAGNOSTIC:
5336ccc3 800 type = DIAG_TYPE;
32f30cd6
KS
801 break;
802
6567c660
KS
803 default:
804 type = INVALID_PACKET;
805 }
806 return (type);
807}
808
809/*
810 * A restart packet has been received. Print out the reason
811 * for the restart.
812 */
813
814pk_restartcause (pkp, xp)
815struct pkcb *pkp;
816register struct x25_packet *xp;
817{
818 register struct x25config *xcp = pkp -> pk_xcp;
9a1afe6f 819 register int lcn = LCN(xp);
6567c660
KS
820
821 switch (xp -> packet_data) {
822 case X25_RESTART_LOCAL_PROCEDURE_ERROR:
823 pk_message (lcn, xcp, "restart: local procedure error");
824 break;
825
826 case X25_RESTART_NETWORK_CONGESTION:
827 pk_message (lcn, xcp, "restart: network congestion");
828 break;
829
830 case X25_RESTART_NETWORK_OPERATIONAL:
831 pk_message (lcn, xcp, "restart: network operational");
832 break;
833
834 default:
835 pk_message (lcn, xcp, "restart: unknown cause");
836 }
837}
838
839#define MAXRESETCAUSE 7
840
841int Reset_cause[] = {
842 EXRESET, EXROUT, 0, EXRRPE, 0, EXRLPE, 0, EXRNCG
843};
844
845/*
846 * A reset packet has arrived. Return the cause to the user.
847 */
848
849pk_resetcause (pkp, xp)
850struct pkcb *pkp;
851register struct x25_packet *xp;
852{
1c41f5e9 853 register struct pklcd *lcp =
9a1afe6f 854 pkp -> pk_chan[LCN(xp)];
6567c660
KS
855 register int code = xp -> packet_data;
856
857 if (code > MAXRESETCAUSE)
858 code = 7; /* EXRNCG */
859
32f30cd6
KS
860 pk_message(LCN(xp), lcp -> lcd_pkp, "reset code 0x%x, diagnostic 0x%x",
861 xp -> packet_data, 4[(u_char *)xp]);
862
1c41f5e9 863 lcp -> lcd_so -> so_error = Reset_cause[code];
6567c660
KS
864}
865
866#define MAXCLEARCAUSE 25
867
868int Clear_cause[] = {
869 EXCLEAR, EXCBUSY, 0, EXCINV, 0, EXCNCG, 0,
870 0, 0, EXCOUT, 0, EXCAB, 0, EXCNOB, 0, 0, 0, EXCRPE,
871 0, EXCLPE, 0, 0, 0, 0, 0, EXCRRC
872};
873
874/*
875 * A clear packet has arrived. Return the cause to the user.
876 */
877
878pk_clearcause (pkp, xp)
879struct pkcb *pkp;
880register struct x25_packet *xp;
881{
1c41f5e9 882 register struct pklcd *lcp =
9a1afe6f 883 pkp -> pk_chan[LCN(xp)];
6567c660
KS
884 register int code = xp -> packet_data;
885
886 if (code > MAXCLEARCAUSE)
887 code = 5; /* EXRNCG */
822e810c
KS
888 if (lcp -> lcd_so)
889 lcp -> lcd_so -> so_error = Clear_cause[code];
6567c660
KS
890}
891
892char *
893format_ntn (xcp)
894register struct x25config *xcp;
895{
4507dea2
KS
896
897 return (xcp -> xc_addr.x25_addr);
6567c660
KS
898}
899
900/* VARARGS1 */
901pk_message (lcn, xcp, fmt, a1, a2, a3, a4, a5, a6)
902struct x25config *xcp;
903char *fmt;
904{
905
906 if (lcn)
907 if (pkcbhead -> pk_next)
908 printf ("X.25(%s): lcn %d: ", format_ntn (xcp), lcn);
909 else
910 printf ("X.25: lcn %d: ", lcn);
911 else
912 if (pkcbhead -> pk_next)
913 printf ("X.25(%s): ", format_ntn (xcp));
914 else
915 printf ("X.25: ");
916
917 printf (fmt, a1, a2, a3, a4, a5, a6);
918 printf ("\n");
919}
1c41f5e9 920
32f30cd6 921pk_ifattach (ia, lloutput, llnext)
1c41f5e9 922register struct x25_ifaddr *ia;
32f30cd6 923int (*lloutput) ();
1c41f5e9
KS
924caddr_t llnext;
925{
926 /* this is here because you can't include both pk_var and hd_var */
927 /* this will probably be replace by a streams gluing mechanism */
928 ia -> ia_pkcb.pk_lloutput = lloutput;
929 ia -> ia_pkcb.pk_llnext = llnext;
930}
931
32f30cd6 932pk_fragment (lcp, m0, qbit, mbit, wait)
1c41f5e9
KS
933struct mbuf *m0;
934register struct pklcd *lcp;
935{
936 register struct mbuf *m = m0;
937 register struct x25_packet *xp;
938 register struct sockbuf *sb;
32f30cd6 939 struct mbuf *head = 0, *next, **mp = &head, *m_split ();
1c41f5e9
KS
940 int totlen, psize = 1 << (lcp -> lcd_packetsize);
941
942 if (m == 0)
822e810c 943 return 0;
c4b47c42 944 if (m -> m_flags & M_PKTHDR == 0)
32f30cd6 945 panic ("pk_fragment");
1c41f5e9 946 totlen = m -> m_pkthdr.len;
9a1afe6f 947 m -> m_act = 0;
1c41f5e9
KS
948 sb = lcp -> lcd_so ? &lcp -> lcd_so -> so_snd : & lcp -> lcd_sb;
949 do {
950 if (totlen > psize) {
32f30cd6 951 if ((next = m_split (m, psize, wait)) == 0)
1c41f5e9 952 goto abort;
1c41f5e9 953 totlen -= psize;
9a1afe6f
KS
954 } else
955 next = 0;
1c41f5e9
KS
956 M_PREPEND(m, PKHEADERLN, wait);
957 if (m == 0)
958 goto abort;
9a1afe6f
KS
959 *mp = m;
960 mp = & m -> m_act;
961 *mp = 0;
32f30cd6 962 xp = mtod (m, struct x25_packet *);
1c41f5e9
KS
963 0[(char *)xp] = 0;
964 if (qbit)
9a1afe6f
KS
965 xp -> q_bit = 1;
966 if (lcp -> lcd_flags & X25_DBIT)
967 xp -> d_bit = 1;
1c41f5e9 968 xp -> fmt_identifier = 1;
1c41f5e9 969 xp -> packet_type = X25_DATA;
9a1afe6f
KS
970 SET_LCN(xp, lcp -> lcd_lcn);
971 if (next || (mbit && (totlen == psize ||
972 (lcp -> lcd_flags & X25_DBIT))))
1c41f5e9 973 MBIT(xp) = 1;
1c41f5e9 974 } while (m = next);
9a1afe6f 975 for (m = head; m; m = next) {
1c41f5e9
KS
976 next = m -> m_act;
977 m -> m_act = 0;
32f30cd6 978 sbappendrecord (sb, m);
1c41f5e9
KS
979 }
980 return 0;
981abort:
9a1afe6f 982 if (wait)
32f30cd6 983 panic ("pk_fragment null mbuf after wait");
9a1afe6f 984 if (next)
32f30cd6 985 m_freem (next);
9a1afe6f 986 for (m = head; m; m = next) {
1c41f5e9 987 next = m -> m_act;
32f30cd6 988 m_freem (m);
1c41f5e9
KS
989 }
990 return ENOBUFS;
991}
9a1afe6f
KS
992
993struct mbuf *
32f30cd6 994m_split (m0, len0, wait)
9a1afe6f
KS
995register struct mbuf *m0;
996int len0;
997{
998 register struct mbuf *m, *n;
999 unsigned len = len0;
1000
1001 for (m = m0; m && len > m -> m_len; m = m -> m_next)
1002 len -= m -> m_len;
1003 if (m == 0)
1004 return (0);
1005 if (m0 -> m_flags & M_PKTHDR) {
1006 MGETHDR(n, wait, m0 -> m_type);
1007 if (n == 0)
1008 return (0);
1009 n -> m_pkthdr.rcvif = m0 -> m_pkthdr.rcvif;
1010 n -> m_pkthdr.len = m0 -> m_pkthdr.len - len0;
1011 m0 -> m_pkthdr.len = len0;
1012 if (m -> m_flags & M_EXT)
1013 goto extpacket;
1014 if (len > MHLEN) {
1015 /* m can't be the lead packet */
1016 MH_ALIGN(n, 0);
32f30cd6 1017 n -> m_next = m_split (m, len, wait);
9a1afe6f 1018 if (n -> m_next == 0) {
32f30cd6 1019 (void) m_free (n);
9a1afe6f
KS
1020 return (0);
1021 } else
1022 return (n);
1023 } else
1024 MH_ALIGN(n, len);
1025 } else if (len == m -> m_len) {
1026 n = m -> m_next;
1027 m -> m_next = 0;
1028 return (n);
1029 }
1030extpacket:
1031 len = m -> m_len - len; /* remainder to be copied */
1032 m -> m_len -= len; /* now equals original len */
c4b47c42 1033 if (m -> m_flags & M_EXT) {
9a1afe6f
KS
1034 n -> m_flags |= M_EXT;
1035 n -> m_ext = m -> m_ext;
32f30cd6 1036 mclrefcnt[mtocl (m -> m_ext.ext_buf)]++;
9a1afe6f
KS
1037 n -> m_data = m -> m_data + m -> m_len;
1038 } else {
1039 MGET(n, wait, m -> m_type);
1040 if (n == 0) {
1041 m -> m_len += len;
1042 return (0);
1043 }
1044 M_ALIGN(n, len);
32f30cd6 1045 bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len);
9a1afe6f
KS
1046 }
1047 n -> m_len = len;
1048 n -> m_next = m -> m_next;
1049 m -> m_next = 0;
1050 return (n);
1051}