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