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