1 /* 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)if_x25subr.c 7.12 (Berkeley) 05/29/91 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "malloc.h" 13 #include "mbuf.h" 14 #include "protosw.h" 15 #include "socket.h" 16 #include "socketvar.h" 17 #include "ioctl.h" 18 #include "errno.h" 19 #include "syslog.h" 20 21 #include "../net/if.h" 22 #include "../net/if_types.h" 23 #include "../net/netisr.h" 24 #include "../net/route.h" 25 26 #include "x25.h" 27 #include "x25err.h" 28 #include "pk.h" 29 #include "pk_var.h" 30 31 #include "machine/mtpr.h" 32 33 #ifdef INET 34 #include "../netinet/in.h" 35 #include "../netinet/in_var.h" 36 #endif 37 38 #ifdef NS 39 #include "../netns/ns.h" 40 #include "../netns/ns_if.h" 41 #endif 42 43 #ifdef ISO 44 int tp_incoming(); 45 #include "../netiso/argo_debug.h" 46 #include "../netiso/iso.h" 47 #include "../netiso/iso_var.h" 48 #endif 49 50 extern struct ifnet loif; 51 struct llinfo_x25 llinfo_x25 = {&llinfo_x25, &llinfo_x25}; 52 struct sockaddr *x25_dgram_sockmask; 53 54 int x25_autoconnect = 0; 55 56 #define senderr(x) {error = x; goto bad;} 57 /* 58 * Ancillary routines 59 */ 60 static struct llinfo_x25 * 61 x25_lxalloc(rt) 62 register struct rtentry *rt; 63 { 64 register struct llinfo_x25 *lx; 65 register struct sockaddr *dst = rt_key(rt); 66 register struct ifaddr *ifa; 67 68 MALLOC(lx, struct llinfo_x25 *, sizeof (*lx), M_PCB, M_NOWAIT); 69 if (lx == 0) 70 return lx; 71 Bzero(lx, sizeof(*lx)); 72 lx->lx_rt = rt; 73 lx->lx_family = dst->sa_family; 74 rt->rt_refcnt++; 75 if (rt->rt_llinfo) 76 insque(lx, (struct llinfo_x25 *)rt->rt_llinfo); 77 else { 78 rt->rt_llinfo = (caddr_t)lx; 79 insque(lx, &llinfo_x25); 80 } 81 for (ifa = rt->rt_ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { 82 if (ifa->ifa_addr->sa_family == AF_CCITT) 83 lx->lx_ia = (struct x25_ifaddr *)ifa; 84 } 85 return lx; 86 } 87 x25_lxfree(lx) 88 register struct llinfo_x25 *lx; 89 { 90 register struct rtentry *rt = lx->lx_rt; 91 register struct pklcd *lcp = lx->lx_lcd; 92 93 if (lcp) { 94 lcp->lcd_upper = 0; 95 pk_disconnect(lcp); 96 } 97 if ((rt->rt_llinfo == (caddr_t)lx) && (lx->lx_next->lx_rt == rt)) 98 rt->rt_llinfo = (caddr_t)lx->lx_next; 99 else 100 rt->rt_llinfo = 0; 101 RTFREE(rt); 102 remque(lx); 103 FREE(lx, M_PCB); 104 } 105 /* 106 * Process a x25 packet as datagram; 107 */ 108 x25_ifinput(lcp, m) 109 struct pklcd *lcp; 110 register struct mbuf *m; 111 { 112 struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; 113 register struct ifnet *ifp; 114 struct ifqueue *inq; 115 extern struct timeval time; 116 int s, len, isr; 117 118 if (m == 0 || lcp->lcd_state != DATA_TRANSFER) { 119 x25_connect_callback(lcp, 0); 120 return; 121 } 122 pk_flowcontrol(lcp, 0, 1); /* Generate RR */ 123 ifp = m->m_pkthdr.rcvif; 124 ifp->if_lastchange = time; 125 switch (m->m_type) { 126 case MT_OOBDATA: 127 if (m) 128 m_freem(m); 129 default: 130 return; 131 132 case MT_DATA: 133 /* FALLTHROUGH */; 134 } 135 switch (lx->lx_family) { 136 #ifdef INET 137 case AF_INET: 138 isr = NETISR_IP; 139 inq = &ipintrq; 140 break; 141 142 #endif 143 #ifdef NS 144 case AF_NS: 145 isr = NETISR_NS; 146 inq = &nsintrq; 147 break; 148 149 #endif 150 #ifdef ISO 151 case AF_ISO: 152 isr = NETISR_ISO; 153 inq = &clnlintrq; 154 break; 155 #endif 156 default: 157 m_freem(m); 158 ifp->if_noproto++; 159 return; 160 } 161 s = splimp(); 162 schednetisr(isr); 163 if (IF_QFULL(inq)) { 164 IF_DROP(inq); 165 m_freem(m); 166 } else { 167 IF_ENQUEUE(inq, m); 168 ifp->if_ibytes += m->m_pkthdr.len; 169 } 170 splx(s); 171 } 172 x25_connect_callback(lcp, m) 173 register struct pklcd *lcp; 174 register struct mbuf *m; 175 { 176 register struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; 177 if (m == 0) 178 goto refused; 179 if (m->m_type != MT_CONTROL) { 180 printf("x25_connect_callback: should panic\n"); 181 goto refused; 182 } 183 switch (pk_decode(mtod(m, struct x25_packet *))) { 184 case CALL_ACCEPTED: 185 lcp->lcd_upper = x25_ifinput; 186 if (lcp->lcd_sb.sb_mb) 187 lcp->lcd_send(lcp); /* XXX start queued packets */ 188 return; 189 default: 190 refused: 191 lcp->lcd_upper = 0; 192 lx->lx_lcd = 0; 193 pk_disconnect(lcp); 194 return; 195 } 196 } 197 #define SA(p) ((struct sockaddr *)(p)) 198 #define RT(p) ((struct rtentry *)(p)) 199 200 x25_dgram_incoming(lcp, m0) 201 register struct pklcd *lcp; 202 struct mbuf *m0; 203 { 204 register struct rtentry *rt, *nrt; 205 register struct mbuf *m = m0->m_next; /* m0 has calling sockaddr_x25 */ 206 int x25_rtrequest(); 207 208 rt = rtalloc1(SA(&lcp->lcd_faddr), 0); 209 if (rt == 0) { 210 refuse: lcp->lcd_upper = 0; 211 pk_close(lcp); 212 return; 213 } 214 rt->rt_refcnt--; 215 if ((nrt = RT(rt->rt_llinfo)) == 0 || rt_mask(rt) != x25_dgram_sockmask) 216 goto refuse; 217 if ((nrt->rt_flags & RTF_UP) == 0) { 218 rt->rt_llinfo = (caddr_t)rtalloc1(rt->rt_gateway, 0); 219 rtfree(nrt); 220 if ((nrt = RT(rt->rt_llinfo)) == 0) 221 goto refuse; 222 nrt->rt_refcnt--; 223 } 224 if (nrt->rt_ifa == 0 || nrt->rt_ifa->ifa_rtrequest != x25_rtrequest) 225 goto refuse; 226 lcp->lcd_send(lcp); /* confirm call */ 227 x25_rtattach(lcp, nrt); 228 m_freem(m); 229 } 230 231 /* 232 * X.25 output routine. 233 */ 234 x25_ifoutput(ifp, m0, dst, rt) 235 struct ifnet *ifp; 236 struct mbuf *m0; 237 struct sockaddr *dst; 238 register struct rtentry *rt; 239 { 240 register struct mbuf *m = m0; 241 register struct llinfo_x25 *lx; 242 struct pklcd *lcp; 243 int s, error = 0; 244 245 if ((ifp->if_flags & IFF_UP) == 0) 246 senderr(ENETDOWN); 247 while (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) { 248 if (rt) { 249 if (rt->rt_llinfo) { 250 rt = (struct rtentry *)rt->rt_llinfo; 251 continue; 252 } 253 dst = rt->rt_gateway; 254 } 255 if ((rt = rtalloc1(dst, 1)) == 0) 256 senderr(EHOSTUNREACH); 257 rt->rt_refcnt--; 258 } 259 /* 260 * Sanity checks. 261 */ 262 if ((rt->rt_ifp != ifp) || 263 (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) || 264 ((lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)) { 265 senderr(ENETUNREACH); 266 } 267 next_circuit: 268 lcp = lx->lx_lcd; 269 if (lcp == 0) { 270 lx->lx_lcd = lcp = pk_attach((struct socket *)0); 271 if (lcp == 0) 272 senderr(ENOBUFS); 273 lcp->lcd_upper = x25_connect_callback; 274 lcp->lcd_upnext = (caddr_t)lx; 275 lcp->lcd_packetsize = lx->lx_ia->ia_xc.xc_psize; 276 } 277 switch (lcp->lcd_state) { 278 case READY: 279 if (dst->sa_family == AF_INET && 280 ifp->if_type == IFT_X25DDN && 281 rt->rt_gateway->sa_family != AF_CCITT) 282 x25_ddnip_to_ccitt(dst, rt); 283 if (rt->rt_gateway->sa_family != AF_CCITT) { 284 if ((rt->rt_flags & RTF_XRESOLVE) == 0) 285 senderr(EHOSTUNREACH); 286 } else if (x25_autoconnect) 287 error = pk_connect(lcp, 288 (struct sockaddr_x25 *)rt->rt_gateway); 289 if (error) 290 senderr(error); 291 /* FALLTHROUGH */ 292 case SENT_CALL: 293 case DATA_TRANSFER: 294 if (sbspace(&lcp->lcd_sb) < 0) { 295 lx = lx->lx_next; 296 if (lx->lx_rt != rt) 297 senderr(ENOSPC); 298 goto next_circuit; 299 } 300 if (lx->lx_ia) 301 lcp->lcd_dg_timer = 302 lx->lx_ia->ia_xc.xc_dg_idletimo; 303 pk_send(lcp, m); 304 break; 305 default: 306 /* 307 * We count on the timer routine to close idle 308 * connections, if there are not enough circuits to go 309 * around. 310 * 311 * So throw away data for now. 312 * After we get it all working, we'll rewrite to handle 313 * actively closing connections (other than by timers), 314 * when circuits get tight. 315 * 316 * In the DDN case, the imp itself closes connections 317 * under heavy load. 318 */ 319 error = ENOBUFS; 320 bad: 321 if (m) 322 m_freem(m); 323 } 324 return (error); 325 } 326 327 /* 328 * Simpleminded timer routine. 329 */ 330 x25_iftimeout(ifp) 331 struct ifnet *ifp; 332 { 333 register struct pkcb *pkcb = 0; 334 register struct pklcd **lcpp, *lcp; 335 int s = splimp(); 336 337 for (pkcb = pkcbhead; pkcb; pkcb = pkcb->pk_next) 338 if (pkcb->pk_ia->ia_ifp == ifp) 339 for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn; 340 --lcpp > pkcb->pk_chan;) 341 if ((lcp = *lcpp) && 342 lcp->lcd_state == DATA_TRANSFER && 343 (lcp->lcd_flags & X25_DG_CIRCUIT) && 344 (lcp->lcd_dg_timer && --lcp->lcd_dg_timer == 0)) { 345 lcp->lcd_upper(lcp, 0); 346 } 347 splx(s); 348 } 349 /* 350 * This routine gets called when validating additions of new routes 351 * or deletions of old ones. 352 */ 353 x25_rtrequest(cmd, rt, dst) 354 register struct rtentry *rt; 355 struct sockaddr *dst; 356 { 357 register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; 358 register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway; 359 register struct pklcd *lcp; 360 361 if (rt->rt_flags & RTF_GATEWAY) { 362 if (rt->rt_llinfo) 363 RTFREE((struct rtentry *)rt->rt_llinfo); 364 rt->rt_llinfo = (cmd == RTM_ADD) ? 365 (caddr_t)rtalloc1(rt->rt_gateway, 1) : 0; 366 return; 367 } 368 if ((rt->rt_flags & RTF_HOST) == 0) 369 return; 370 if (cmd == RTM_DELETE) { 371 while (rt->rt_llinfo) 372 x25_lxfree((struct llinfo *)rt->rt_llinfo); 373 x25_rtinvert(RTM_DELETE, rt->rt_gateway, rt); 374 return; 375 } 376 if (lx == 0 && (lx = x25_lxalloc(rt)) == 0) 377 return; 378 if ((lcp = lx->lx_lcd) && lcp->lcd_state != READY) { 379 /* 380 * This can only happen on a RTM_CHANGE operation 381 * though cmd will be RTM_ADD. 382 */ 383 if (lcp->lcd_ceaddr && 384 Bcmp(rt->rt_gateway, lcp->lcd_ceaddr, 385 lcp->lcd_ceaddr->x25_len) != 0) { 386 x25_rtinvert(RTM_DELETE, lcp->lcd_ceaddr, rt); 387 lcp->lcd_upper = 0; 388 pk_disconnect(lcp); 389 } 390 lcp = 0; 391 } 392 x25_rtinvert(RTM_ADD, rt->rt_gateway, rt); 393 } 394 395 int x25_dont_rtinvert = 0; 396 397 x25_rtinvert(cmd, sa, rt) 398 register struct sockaddr *sa; 399 register struct rtentry *rt; 400 { 401 struct rtentry *rt2 = 0; 402 /* 403 * rt_gateway contains PID indicating which proto 404 * family on the other end, so will be different 405 * from general host route via X.25. 406 */ 407 if (rt->rt_ifp->if_type == IFT_X25DDN || x25_dont_rtinvert) 408 return; 409 if (sa->sa_family != AF_CCITT) 410 return; 411 if (cmd != RTM_DELETE) { 412 rtrequest(RTM_ADD, sa, rt_key(rt), x25_dgram_sockmask, 413 RTF_PROTO2, &rt2); 414 if (rt2) { 415 rt2->rt_llinfo = (caddr_t) rt; 416 rt->rt_refcnt++; 417 } 418 return; 419 } 420 rt2 = rt; 421 if ((rt = rtalloc1(sa, 0)) == 0 || 422 (rt->rt_flags & RTF_PROTO2) == 0 || 423 rt->rt_llinfo != (caddr_t)rt2) { 424 printf("x25_rtchange: inverse route screwup\n"); 425 return; 426 } else 427 rt2->rt_refcnt--; 428 rtrequest(RTM_DELETE, sa, rt_key(rt2), x25_dgram_sockmask, 429 0, (struct rtentry **) 0); 430 } 431 432 static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; 433 /* 434 * IP to X25 address routine copyright ACC, used by permission. 435 */ 436 union imp_addr { 437 struct in_addr ip; 438 struct imp { 439 u_char s_net; 440 u_char s_host; 441 u_char s_lh; 442 u_char s_impno; 443 } imp; 444 }; 445 446 /* 447 * The following is totally bogus and here only to preserve 448 * the IP to X.25 translation. 449 */ 450 x25_ddnip_to_ccitt(src, rt) 451 struct sockaddr_in *src; 452 register struct rtentry *rt; 453 { 454 register struct sockaddr_x25 *dst = (struct sockaddr_x25 *)rt->rt_gateway; 455 union imp_addr imp_addr; 456 int imp_no, imp_port, temp; 457 char *x25addr = dst->x25_addr; 458 459 460 imp_addr.ip = src->sin_addr; 461 *dst = blank_x25; 462 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ 463 imp_no = imp_addr.imp.s_impno; 464 imp_port = imp_addr.imp.s_host; 465 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ 466 imp_no = imp_addr.imp.s_impno; 467 imp_port = imp_addr.imp.s_lh; 468 } else { /* class C */ 469 imp_no = imp_addr.imp.s_impno / 32; 470 imp_port = imp_addr.imp.s_impno % 32; 471 } 472 473 x25addr[0] = 12; /* length */ 474 /* DNIC is cleared by struct copy above */ 475 476 if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno 477 * -> III, s_host -> HH */ 478 x25addr[5] = 0; /* set flag bit */ 479 x25addr[6] = imp_no / 100; 480 x25addr[7] = (imp_no % 100) / 10; 481 x25addr[8] = imp_no % 10; 482 x25addr[9] = imp_port / 10; 483 x25addr[10] = imp_port % 10; 484 } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s 485 * _host * 256 + s_impno -> RRRRR */ 486 temp = (imp_port << 8) + imp_no; 487 x25addr[5] = 1; 488 x25addr[6] = temp / 10000; 489 x25addr[7] = (temp % 10000) / 1000; 490 x25addr[8] = (temp % 1000) / 100; 491 x25addr[9] = (temp % 100) / 10; 492 x25addr[10] = temp % 10; 493 } 494 } 495 496 /* 497 * This routine is a sketch and is not to be believed!!!!! 498 * 499 * This is a utility routine to be called by x25 devices when a 500 * call request is honored with the intent of starting datagram forwarding. 501 */ 502 x25_dg_rtinit(dst, ia, af) 503 struct sockaddr_x25 *dst; 504 register struct x25_ifaddr *ia; 505 { 506 struct sockaddr *sa = 0; 507 struct rtentry *rt; 508 struct in_addr my_addr; 509 static struct sockaddr_in sin = {sizeof(sin), AF_INET}; 510 511 if (ia->ia_ifp->if_type == IFT_X25DDN && af == AF_INET) { 512 /* 513 * Inverse X25 to IP mapping copyright and courtesy ACC. 514 */ 515 int imp_no, imp_port, temp; 516 union imp_addr imp_addr; 517 { 518 /* 519 * First determine our IP addr for network 520 */ 521 register struct in_ifaddr *ina; 522 extern struct in_ifaddr *in_ifaddr; 523 524 for (ina = in_ifaddr; ina; ina = ina->ia_next) 525 if (ina->ia_ifp == ia->ia_ifp) { 526 my_addr = ina->ia_addr.sin_addr; 527 break; 528 } 529 } 530 { 531 532 register char *x25addr = dst->x25_addr; 533 534 switch (x25addr[5] & 0x0f) { 535 case 0: /* Physical: 0000 0 IIIHH00 [SS] */ 536 imp_no = 537 ((int) (x25addr[6] & 0x0f) * 100) + 538 ((int) (x25addr[7] & 0x0f) * 10) + 539 ((int) (x25addr[8] & 0x0f)); 540 541 542 imp_port = 543 ((int) (x25addr[9] & 0x0f) * 10) + 544 ((int) (x25addr[10] & 0x0f)); 545 break; 546 case 1: /* Logical: 0000 1 RRRRR00 [SS] */ 547 temp = ((int) (x25addr[6] & 0x0f) * 10000) 548 + ((int) (x25addr[7] & 0x0f) * 1000) 549 + ((int) (x25addr[8] & 0x0f) * 100) 550 + ((int) (x25addr[9] & 0x0f) * 10) 551 + ((int) (x25addr[10] & 0x0f)); 552 553 imp_port = temp >> 8; 554 imp_no = temp & 0xff; 555 break; 556 default: 557 return (0L); 558 } 559 imp_addr.ip = my_addr; 560 if ((imp_addr.imp.s_net & 0x80) == 0x00) { 561 /* class A */ 562 imp_addr.imp.s_host = imp_port; 563 imp_addr.imp.s_impno = imp_no; 564 imp_addr.imp.s_lh = 0; 565 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { 566 /* class B */ 567 imp_addr.imp.s_lh = imp_port; 568 imp_addr.imp.s_impno = imp_no; 569 } else { 570 /* class C */ 571 imp_addr.imp.s_impno = (imp_no << 5) + imp_port; 572 } 573 } 574 sin.sin_addr = imp_addr.ip; 575 sa = (struct sockaddr *)&sin; 576 } else { 577 /* 578 * This uses the X25 routing table to do inverse 579 * lookup of x25 address to sockaddr. 580 */ 581 if (rt = rtalloc1(dst, 0)) { 582 sa = rt->rt_gateway; 583 rt->rt_refcnt--; 584 } 585 } 586 /* 587 * Call to rtalloc1 will create rtentry for reverse path 588 * to callee by virtue of cloning magic and will allocate 589 * space for local control block. 590 */ 591 if (sa && (rt = rtalloc1(sa, 1))) 592 rt->rt_refcnt--; 593 } 594 #ifndef _offsetof 595 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 596 #endif 597 struct sockaddr_x25 x25_dgmask = { 598 _offsetof(struct sockaddr_x25, x25_udata[1]), /* _len */ 599 0, /* _family */ 600 0, /* _net */ 601 { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* _addr */ 602 {0}, /* opts */ 603 -1, /* _udlen */ 604 {-1} /* _udata */ 605 }; 606 int x25_startproto = 1; 607 struct radix_tree_head *x25_rnhead; 608 609 pk_init() 610 { 611 /* 612 * warning, sizeof (struct sockaddr_x25) > 32, 613 * but contains no data of interest beyond 32 614 */ 615 struct radix_node *rn_addmask(); 616 rn_inithead(&x25_rnhead, 32, AF_CCITT); 617 x25_dgram_sockmask = 618 SA(rn_addmask((caddr_t)&x25_dgmask, 0, 4)->rn_key); 619 if (x25_startproto) { 620 pk_protolisten(0xcc, 1, x25_dgram_incoming); 621 pk_protolisten(0x81, 1, x25_dgram_incoming); 622 } 623 } 624 625 struct x25_dgproto { 626 u_char spi; 627 u_char spilen; 628 int (*f)(); 629 } x25_dgprototab[] = { 630 #if defined(ISO) && defined(TPCONS) 631 { 0x0, 0, tp_incoming}, 632 #endif 633 { 0xcc, 1, x25_dgram_incoming}, 634 { 0xcd, 1, x25_dgram_incoming}, 635 { 0x81, 1, x25_dgram_incoming}, 636 }; 637 638 pk_user_protolisten(info) 639 register u_char *info; 640 { 641 register struct x25_dgproto *dp = x25_dgprototab 642 + ((sizeof x25_dgprototab) / (sizeof *dp)); 643 register struct pklcd *lcp; 644 645 while (dp > x25_dgprototab) 646 if ((--dp)->spi == info[0]) 647 goto gotspi; 648 return ESRCH; 649 650 gotspi: if (info[1]) 651 return pk_protolisten(dp->spi, dp->spilen, dp->f); 652 for (lcp = pk_listenhead; lcp; lcp = lcp->lcd_listen) 653 if (lcp->lcd_laddr.x25_udlen == dp->spilen && 654 Bcmp(&dp->spi, lcp->lcd_laddr.x25_udata, dp->spilen) == 0) { 655 pk_close(lcp); 656 return 0; 657 } 658 return ESRCH; 659 } 660 661 /* 662 * This routine transfers an X.25 circuit to or from a routing entry. 663 * If the supplied circuit is * in DATA_TRANSFER state, it is added to the 664 * routing entry. If freshly allocated, it glues back the vc from 665 * the rtentry to the socket. 666 */ 667 pk_rtattach(so, m0) 668 register struct socket *so; 669 struct mbuf *m0; 670 { 671 register struct pklcd *lcp = (struct pklcd *)so->so_pcb; 672 register struct mbuf *m = m0; 673 struct sockaddr *dst = mtod(m, struct sockaddr *); 674 register struct rtentry *rt = rtalloc1(dst, 0); 675 register struct llinfo_x25 *lx; 676 caddr_t cp; 677 #define ROUNDUP(a) \ 678 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 679 #define transfer_sockbuf(s, f, l) \ 680 while (m = (s)->sb_mb)\ 681 {(s)->sb_mb = m->m_act; m->m_act = 0; sbfree((s), m); f(l, m);} 682 683 if (rt) 684 rt->rt_refcnt--; 685 cp = (dst->sa_len < m->m_len) ? ROUNDUP(dst->sa_len) + (caddr_t)dst : 0; 686 while (rt && 687 ((cp == 0 && rt_mask(rt) != 0) || 688 (cp != 0 && (rt_mask(rt) == 0 || 689 Bcmp(cp, rt_mask(rt), rt_mask(rt)->sa_len)) != 0))) 690 rt = (struct rtentry *)rt->rt_nodes->rn_dupedkey; 691 if (rt == 0 || (rt->rt_flags & RTF_GATEWAY) || 692 (lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0) 693 return ESRCH; 694 if (lcp == 0) 695 return ENOTCONN; 696 switch (lcp->lcd_state) { 697 default: 698 return ENOTCONN; 699 700 case READY: 701 /* Detach VC from rtentry */ 702 if (lx->lx_lcd == 0) 703 return ENOTCONN; 704 lcp->lcd_so = 0; 705 pk_close(lcp); 706 lcp = lx->lx_lcd; 707 if (lx->lx_next->lx_rt == rt) 708 x25_lxfree(lx); 709 lcp->lcd_so = so; 710 lcp->lcd_upper = 0; 711 lcp->lcd_upnext = 0; 712 transfer_sockbuf(&lcp->lcd_sb, sbappendrecord, &so->so_snd); 713 soisconnected(so); 714 return 0; 715 716 case DATA_TRANSFER: 717 /* Add VC to rtentry */ 718 lcp->lcd_so = 0; 719 lcp->lcd_sb = so->so_snd; /* structure copy */ 720 bzero((caddr_t)&so->so_snd, sizeof(so->so_snd)); /* XXXXXX */ 721 so->so_pcb = 0; 722 x25_rtattach(lcp, rt); 723 transfer_sockbuf(&so->so_rcv, x25_ifinput, lcp); 724 soisdisconnected(so); 725 } 726 return 0; 727 } 728 x25_rtattach(lcp0, rt) 729 register struct pklcd *lcp0; 730 struct rtentry *rt; 731 { 732 register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; 733 register struct pklcd *lcp; 734 register struct mbuf *m; 735 if (lcp = lx->lx_lcd) { /* adding an additional VC */ 736 if (lcp->lcd_state == READY) { 737 transfer_sockbuf(&lcp->lcd_sb, pk_output, lcp0); 738 lcp->lcd_upper = 0; 739 pk_close(lcp); 740 } else { 741 lx = x25_lxalloc(rt); 742 if (lx == 0) 743 return ENOBUFS; 744 } 745 } 746 lx->lx_lcd = lcp = lcp0; 747 lcp->lcd_upper = x25_ifinput; 748 lcp->lcd_upnext = (caddr_t)lx; 749 } 750