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