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