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