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