]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netccitt/if_x25subr.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1990, 1993
24 * The Regents of the University of California. All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * @(#)if_x25subr.c 8.1 (Berkeley) 6/10/93
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/malloc.h>
61 #include <sys/protosw.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
64 #include <sys/ioctl.h>
65 #include <sys/errno.h>
66 #include <sys/syslog.h>
69 #include <net/if_types.h>
70 #include <net/netisr.h>
71 #include <net/route.h>
73 #include <netccitt/x25.h>
74 #include <netccitt/x25err.h>
75 #include <netccitt/pk.h>
76 #include <netccitt/pk_var.h>
79 #include <netinet/in.h>
80 #include <netinet/in_var.h>
85 #include <netns/ns_if.h>
90 #include <netiso/argo_debug.h>
91 #include <netiso/iso.h>
92 #include <netiso/iso_var.h>
95 extern struct ifnet loif
;
96 struct llinfo_x25 llinfo_x25
= {&llinfo_x25
, &llinfo_x25
};
98 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
100 struct sockaddr
*x25_dgram_sockmask
;
101 struct sockaddr_x25 x25_dgmask
= {
102 _offsetof(struct sockaddr_x25
, x25_udata
[1]), /* _len */
105 { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _addr */
115 int x25_autoconnect
= 0;
117 #define senderr(x) {error = x; goto bad;}
121 static struct llinfo_x25
*
123 register struct rtentry
*rt
;
125 register struct llinfo_x25
*lx
;
126 register struct sockaddr
*dst
= rt_key(rt
);
127 register struct ifaddr
*ifa
;
129 MALLOC(lx
, struct llinfo_x25
*, sizeof (*lx
), M_PCB
, M_NOWAIT
);
132 Bzero(lx
, sizeof(*lx
));
134 lx
->lx_family
= dst
->sa_family
;
137 insque(lx
, (struct llinfo_x25
*)rt
->rt_llinfo
);
139 rt
->rt_llinfo
= (caddr_t
)lx
;
140 insque(lx
, &llinfo_x25
);
142 for (ifa
= rt
->rt_ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
) {
143 if (ifa
->ifa_addr
->sa_family
== AF_CCITT
)
144 lx
->lx_ia
= (struct x25_ifaddr
*)ifa
;
149 register struct llinfo_x25
*lx
;
151 register struct rtentry
*rt
= lx
->lx_rt
;
152 register struct pklcd
*lcp
= lx
->lx_lcd
;
158 if ((rt
->rt_llinfo
== (caddr_t
)lx
) && (lx
->lx_next
->lx_rt
== rt
))
159 rt
->rt_llinfo
= (caddr_t
)lx
->lx_next
;
167 * Process a x25 packet as datagram;
171 register struct mbuf
*m
;
173 struct llinfo_x25
*lx
= (struct llinfo_x25
*)lcp
->lcd_upnext
;
174 register struct ifnet
*ifp
;
176 extern struct timeval time
;
179 if (m
== 0 || lcp
->lcd_state
!= DATA_TRANSFER
) {
180 x25_connect_callback(lcp
, 0);
183 pk_flowcontrol(lcp
, 0, 1); /* Generate RR */
184 ifp
= m
->m_pkthdr
.rcvif
;
185 ifp
->if_lastchange
= time
;
195 switch (lx
->lx_family
) {
228 ifp
->if_ibytes
+= m
->m_pkthdr
.len
;
232 x25_connect_callback(lcp
, m
)
233 register struct pklcd
*lcp
;
234 register struct mbuf
*m
;
236 register struct llinfo_x25
*lx
= (struct llinfo_x25
*)lcp
->lcd_upnext
;
240 if (m
->m_type
!= MT_CONTROL
) {
241 printf("x25_connect_callback: should panic\n");
244 switch (pk_decode(mtod(m
, struct x25_packet
*))) {
246 lcp
->lcd_upper
= x25_ifinput
;
247 if (lcp
->lcd_sb
.sb_mb
)
248 lcp
->lcd_send(lcp
); /* XXX start queued packets */
260 #define SA(p) ((struct sockaddr *)(p))
261 #define RT(p) ((struct rtentry *)(p))
263 x25_dgram_incoming(lcp
, m0
)
264 register struct pklcd
*lcp
;
267 register struct rtentry
*rt
, *nrt
;
268 register struct mbuf
*m
= m0
->m_next
; /* m0 has calling sockaddr_x25 */
269 void x25_rtrequest();
271 rt
= rtalloc1(SA(&lcp
->lcd_faddr
), 0);
273 refuse
: lcp
->lcd_upper
= 0;
278 if ((nrt
= RT(rt
->rt_llinfo
)) == 0 || rt_mask(rt
) != x25_dgram_sockmask
)
280 if ((nrt
->rt_flags
& RTF_UP
) == 0) {
281 rt
->rt_llinfo
= (caddr_t
)rtalloc1(rt
->rt_gateway
, 0);
283 if ((nrt
= RT(rt
->rt_llinfo
)) == 0)
287 if (nrt
->rt_ifa
== 0 || nrt
->rt_ifa
->ifa_rtrequest
!= x25_rtrequest
)
289 lcp
->lcd_send(lcp
); /* confirm call */
290 x25_rtattach(lcp
, nrt
);
295 * X.25 output routine.
297 x25_ifoutput(ifp
, m0
, dst
, rt
)
300 struct sockaddr
*dst
;
301 register struct rtentry
*rt
;
303 register struct mbuf
*m
= m0
;
304 register struct llinfo_x25
*lx
;
309 for (plen
= 0; m
; m
= m
->m_next
)
313 if ((ifp
->if_flags
& IFF_UP
) == 0)
315 while (rt
== 0 || (rt
->rt_flags
& RTF_GATEWAY
)) {
318 rt
= (struct rtentry
*)rt
->rt_llinfo
;
321 dst
= rt
->rt_gateway
;
323 if ((rt
= rtalloc1(dst
, 1)) == 0)
324 senderr(EHOSTUNREACH
);
330 if ((rt
->rt_ifp
!= ifp
) ||
331 (rt
->rt_flags
& (RTF_CLONING
| RTF_GATEWAY
)) ||
332 ((lx
= (struct llinfo_x25
*)rt
->rt_llinfo
) == 0)) {
333 senderr(ENETUNREACH
);
335 if ((m
->m_flags
& M_PKTHDR
) == 0) {
336 if_x25stats
.ifx_nophdr
++;
337 m
= m_gethdr(M_NOWAIT
, MT_HEADER
);
340 m
->m_pkthdr
.len
= plen
;
343 if (plen
!= m
->m_pkthdr
.len
) {
344 if_x25stats
.ifx_wrongplen
++;
345 m
->m_pkthdr
.len
= plen
;
350 lx
->lx_lcd
= lcp
= pk_attach((struct socket
*)0);
353 lcp
->lcd_upper
= x25_connect_callback
;
354 lcp
->lcd_upnext
= (caddr_t
)lx
;
355 lcp
->lcd_packetsize
= lx
->lx_ia
->ia_xc
.xc_psize
;
356 lcp
->lcd_flags
= X25_MBS_HOLD
;
358 switch (lcp
->lcd_state
) {
360 if (dst
->sa_family
== AF_INET
&&
361 ifp
->if_type
== IFT_X25DDN
&&
362 rt
->rt_gateway
->sa_family
!= AF_CCITT
)
363 x25_ddnip_to_ccitt(dst
, rt
);
364 if (rt
->rt_gateway
->sa_family
!= AF_CCITT
) {
365 if ((rt
->rt_flags
& RTF_XRESOLVE
) == 0)
366 senderr(EHOSTUNREACH
);
367 } else if (x25_autoconnect
)
368 error
= pk_connect(lcp
,
369 (struct sockaddr_x25
*)rt
->rt_gateway
);
375 if (sbspace(&lcp
->lcd_sb
) < 0) {
383 lx
->lx_ia
->ia_xc
.xc_dg_idletimo
;
388 * We count on the timer routine to close idle
389 * connections, if there are not enough circuits to go
392 * So throw away data for now.
393 * After we get it all working, we'll rewrite to handle
394 * actively closing connections (other than by timers),
395 * when circuits get tight.
397 * In the DDN case, the imp itself closes connections
409 * Simpleminded timer routine.
414 register struct pkcb
*pkcb
= 0;
415 register struct pklcd
**lcpp
, *lcp
;
419 if (pkcb
->pk_ia
->ia_ifp
== ifp
)
420 for (lcpp
= pkcb
->pk_chan
+ pkcb
->pk_maxlcn
;
421 --lcpp
> pkcb
->pk_chan
;)
423 lcp
->lcd_state
== DATA_TRANSFER
&&
424 (lcp
->lcd_flags
& X25_DG_CIRCUIT
) &&
425 (lcp
->lcd_dg_timer
&& --lcp
->lcd_dg_timer
== 0)) {
426 lcp
->lcd_upper(lcp
, 0);
431 * This routine gets called when validating additions of new routes
432 * or deletions of old ones.
434 x25_rtrequest(cmd
, rt
, dst
)
435 register struct rtentry
*rt
;
436 struct sockaddr
*dst
;
438 register struct llinfo_x25
*lx
= (struct llinfo_x25
*)rt
->rt_llinfo
;
439 register struct sockaddr_x25
*sa
=(struct sockaddr_x25
*)rt
->rt_gateway
;
440 register struct pklcd
*lcp
;
442 /* would put this pk_init, except routing table doesn't
444 if (x25_dgram_sockmask
== 0) {
445 struct radix_node
*rn_addmask();
447 SA(rn_addmask((caddr_t
)&x25_dgmask
, 0, 4)->rn_key
);
449 if (rt
->rt_flags
& RTF_GATEWAY
) {
451 RTFREE((struct rtentry
*)rt
->rt_llinfo
);
452 rt
->rt_llinfo
= (cmd
== RTM_ADD
) ?
453 (caddr_t
)rtalloc1(rt
->rt_gateway
, 1) : 0;
456 if ((rt
->rt_flags
& RTF_HOST
) == 0)
458 if (cmd
== RTM_DELETE
) {
459 while (rt
->rt_llinfo
)
460 x25_lxfree((struct llinfo
*)rt
->rt_llinfo
);
461 x25_rtinvert(RTM_DELETE
, rt
->rt_gateway
, rt
);
464 if (lx
== 0 && (lx
= x25_lxalloc(rt
)) == 0)
466 if ((lcp
= lx
->lx_lcd
) && lcp
->lcd_state
!= READY
) {
468 * This can only happen on a RTM_CHANGE operation
469 * though cmd will be RTM_ADD.
471 if (lcp
->lcd_ceaddr
&&
472 Bcmp(rt
->rt_gateway
, lcp
->lcd_ceaddr
,
473 lcp
->lcd_ceaddr
->x25_len
) != 0) {
474 x25_rtinvert(RTM_DELETE
, lcp
->lcd_ceaddr
, rt
);
480 x25_rtinvert(RTM_ADD
, rt
->rt_gateway
, rt
);
483 int x25_dont_rtinvert
= 0;
485 x25_rtinvert(cmd
, sa
, rt
)
486 register struct sockaddr
*sa
;
487 register struct rtentry
*rt
;
489 struct rtentry
*rt2
= 0;
491 * rt_gateway contains PID indicating which proto
492 * family on the other end, so will be different
493 * from general host route via X.25.
495 if (rt
->rt_ifp
->if_type
== IFT_X25DDN
|| x25_dont_rtinvert
)
497 if (sa
->sa_family
!= AF_CCITT
)
499 if (cmd
!= RTM_DELETE
) {
500 rtrequest(RTM_ADD
, sa
, rt_key(rt
), x25_dgram_sockmask
,
503 rt2
->rt_llinfo
= (caddr_t
) rt
;
509 if ((rt
= rtalloc1(sa
, 0)) == 0 ||
510 (rt
->rt_flags
& RTF_PROTO2
) == 0 ||
511 rt
->rt_llinfo
!= (caddr_t
)rt2
) {
512 printf("x25_rtchange: inverse route foulup\n");
516 rtrequest(RTM_DELETE
, sa
, rt_key(rt2
), x25_dgram_sockmask
,
517 0, (struct rtentry
**) 0);
520 static struct sockaddr_x25 blank_x25
= {sizeof blank_x25
, AF_CCITT
};
522 * IP to X25 address routine copyright ACC, used by permission.
535 * The following is totally bogus and here only to preserve
536 * the IP to X.25 translation.
538 x25_ddnip_to_ccitt(src
, rt
)
539 struct sockaddr_in
*src
;
540 register struct rtentry
*rt
;
542 register struct sockaddr_x25
*dst
= (struct sockaddr_x25
*)rt
->rt_gateway
;
543 union imp_addr imp_addr
;
544 int imp_no
, imp_port
, temp
;
545 char *x25addr
= dst
->x25_addr
;
548 imp_addr
.ip
= src
->sin_addr
;
550 if ((imp_addr
.imp
.s_net
& 0x80) == 0x00) { /* class A */
551 imp_no
= imp_addr
.imp
.s_impno
;
552 imp_port
= imp_addr
.imp
.s_host
;
553 } else if ((imp_addr
.imp
.s_net
& 0xc0) == 0x80) { /* class B */
554 imp_no
= imp_addr
.imp
.s_impno
;
555 imp_port
= imp_addr
.imp
.s_lh
;
556 } else { /* class C */
557 imp_no
= imp_addr
.imp
.s_impno
/ 32;
558 imp_port
= imp_addr
.imp
.s_impno
% 32;
561 x25addr
[0] = 12; /* length */
562 /* DNIC is cleared by struct copy above */
564 if (imp_port
< 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno
565 * -> III, s_host -> HH */
566 x25addr
[5] = 0; /* set flag bit */
567 x25addr
[6] = imp_no
/ 100;
568 x25addr
[7] = (imp_no
% 100) / 10;
569 x25addr
[8] = imp_no
% 10;
570 x25addr
[9] = imp_port
/ 10;
571 x25addr
[10] = imp_port
% 10;
572 } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s
573 * _host * 256 + s_impno -> RRRRR */
574 temp
= (imp_port
<< 8) + imp_no
;
576 x25addr
[6] = temp
/ 10000;
577 x25addr
[7] = (temp
% 10000) / 1000;
578 x25addr
[8] = (temp
% 1000) / 100;
579 x25addr
[9] = (temp
% 100) / 10;
580 x25addr
[10] = temp
% 10;
585 * This routine is a sketch and is not to be believed!!!!!
587 * This is a utility routine to be called by x25 devices when a
588 * call request is honored with the intent of starting datagram forwarding.
590 x25_dg_rtinit(dst
, ia
, af
)
591 struct sockaddr_x25
*dst
;
592 register struct x25_ifaddr
*ia
;
594 struct sockaddr
*sa
= 0;
596 struct in_addr my_addr
;
597 static struct sockaddr_in sin
= {sizeof(sin
), AF_INET
};
599 if (ia
->ia_ifp
->if_type
== IFT_X25DDN
&& af
== AF_INET
) {
601 * Inverse X25 to IP mapping copyright and courtesy ACC.
603 int imp_no
, imp_port
, temp
;
604 union imp_addr imp_addr
;
607 * First determine our IP addr for network
609 register struct in_ifaddr
*ina
;
610 extern struct in_ifaddr
*in_ifaddr
;
612 for (ina
= in_ifaddr
; ina
; ina
= ina
->ia_next
)
613 if (ina
->ia_ifp
== ia
->ia_ifp
) {
614 my_addr
= ina
->ia_addr
.sin_addr
;
620 register char *x25addr
= dst
->x25_addr
;
622 switch (x25addr
[5] & 0x0f) {
623 case 0: /* Physical: 0000 0 IIIHH00 [SS] */
625 ((int) (x25addr
[6] & 0x0f) * 100) +
626 ((int) (x25addr
[7] & 0x0f) * 10) +
627 ((int) (x25addr
[8] & 0x0f));
631 ((int) (x25addr
[9] & 0x0f) * 10) +
632 ((int) (x25addr
[10] & 0x0f));
634 case 1: /* Logical: 0000 1 RRRRR00 [SS] */
635 temp
= ((int) (x25addr
[6] & 0x0f) * 10000)
636 + ((int) (x25addr
[7] & 0x0f) * 1000)
637 + ((int) (x25addr
[8] & 0x0f) * 100)
638 + ((int) (x25addr
[9] & 0x0f) * 10)
639 + ((int) (x25addr
[10] & 0x0f));
641 imp_port
= temp
>> 8;
642 imp_no
= temp
& 0xff;
647 imp_addr
.ip
= my_addr
;
648 if ((imp_addr
.imp
.s_net
& 0x80) == 0x00) {
650 imp_addr
.imp
.s_host
= imp_port
;
651 imp_addr
.imp
.s_impno
= imp_no
;
652 imp_addr
.imp
.s_lh
= 0;
653 } else if ((imp_addr
.imp
.s_net
& 0xc0) == 0x80) {
655 imp_addr
.imp
.s_lh
= imp_port
;
656 imp_addr
.imp
.s_impno
= imp_no
;
659 imp_addr
.imp
.s_impno
= (imp_no
<< 5) + imp_port
;
662 sin
.sin_addr
= imp_addr
.ip
;
663 sa
= (struct sockaddr
*)&sin
;
666 * This uses the X25 routing table to do inverse
667 * lookup of x25 address to sockaddr.
669 if (rt
= rtalloc1(SA(dst
), 0)) {
675 * Call to rtalloc1 will create rtentry for reverse path
676 * to callee by virtue of cloning magic and will allocate
677 * space for local control block.
679 if (sa
&& (rt
= rtalloc1(sa
, 1)))
682 int x25_startproto
= 1;
687 * warning, sizeof (struct sockaddr_x25) > 32,
688 * but contains no data of interest beyond 32
690 if (x25_startproto
) {
691 pk_protolisten(0xcc, 1, x25_dgram_incoming
);
692 pk_protolisten(0x81, 1, x25_dgram_incoming
);
700 } x25_dgprototab
[] = {
701 #if (ISO) && (TPCONS)
702 { 0x0, 0, tp_incoming
},
704 { 0xcc, 1, x25_dgram_incoming
},
705 { 0xcd, 1, x25_dgram_incoming
},
706 { 0x81, 1, x25_dgram_incoming
},
709 pk_user_protolisten(info
)
710 register u_char
*info
;
712 register struct x25_dgproto
*dp
= x25_dgprototab
713 + ((sizeof x25_dgprototab
) / (sizeof *dp
));
714 register struct pklcd
*lcp
;
716 while (dp
> x25_dgprototab
)
717 if ((--dp
)->spi
== info
[0])
722 return pk_protolisten(dp
->spi
, dp
->spilen
, dp
->f
);
723 for (lcp
= pk_listenhead
; lcp
; lcp
= lcp
->lcd_listen
)
724 if (lcp
->lcd_laddr
.x25_udlen
== dp
->spilen
&&
725 Bcmp(&dp
->spi
, lcp
->lcd_laddr
.x25_udata
, dp
->spilen
) == 0) {
733 * This routine transfers an X.25 circuit to or from a routing entry.
734 * If the supplied circuit is * in DATA_TRANSFER state, it is added to the
735 * routing entry. If freshly allocated, it glues back the vc from
736 * the rtentry to the socket.
739 register struct socket
*so
;
742 register struct pklcd
*lcp
= (struct pklcd
*)so
->so_pcb
;
743 register struct mbuf
*m
= m0
;
744 struct sockaddr
*dst
= mtod(m
, struct sockaddr
*);
745 register struct rtentry
*rt
= rtalloc1(dst
, 0);
746 register struct llinfo_x25
*lx
;
749 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
750 #define transfer_sockbuf(s, f, l) \
751 while (m = (s)->sb_mb)\
752 {(s)->sb_mb = m->m_act; m->m_act = 0; sbfree((s), m); f(l, m);}
756 cp
= (dst
->sa_len
< m
->m_len
) ? ROUNDUP(dst
->sa_len
) + (caddr_t
)dst
: 0;
758 ((cp
== 0 && rt_mask(rt
) != 0) ||
759 (cp
!= 0 && (rt_mask(rt
) == 0 ||
760 Bcmp(cp
, rt_mask(rt
), rt_mask(rt
)->sa_len
)) != 0)))
761 rt
= (struct rtentry
*)rt
->rt_nodes
->rn_dupedkey
;
762 if (rt
== 0 || (rt
->rt_flags
& RTF_GATEWAY
) ||
763 (lx
= (struct llinfo_x25
*)rt
->rt_llinfo
) == 0)
767 switch (lcp
->lcd_state
) {
772 /* Detach VC from rtentry */
778 if (lx
->lx_next
->lx_rt
== rt
)
783 transfer_sockbuf(&lcp
->lcd_sb
, sbappendrecord
, &so
->so_snd
);
788 /* Add VC to rtentry */
790 lcp
->lcd_sb
= so
->so_snd
; /* structure copy */
791 bzero((caddr_t
)&so
->so_snd
, sizeof(so
->so_snd
)); /* XXXXXX */
793 x25_rtattach(lcp
, rt
);
794 transfer_sockbuf(&so
->so_rcv
, x25_ifinput
, lcp
);
795 soisdisconnected(so
);
799 x25_rtattach(lcp0
, rt
)
800 register struct pklcd
*lcp0
;
803 register struct llinfo_x25
*lx
= (struct llinfo_x25
*)rt
->rt_llinfo
;
804 register struct pklcd
*lcp
;
805 register struct mbuf
*m
;
806 if (lcp
= lx
->lx_lcd
) { /* adding an additional VC */
807 if (lcp
->lcd_state
== READY
) {
808 transfer_sockbuf(&lcp
->lcd_sb
, pk_output
, lcp0
);
812 lx
= x25_lxalloc(rt
);
817 lx
->lx_lcd
= lcp
= lcp0
;
818 lcp
->lcd_upper
= x25_ifinput
;
819 lcp
->lcd_upnext
= (caddr_t
)lx
;