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.9 (Berkeley) 05/03/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 51 #define senderr(x) {error = x; goto bad;} 52 /* 53 * X.25 output routine. 54 */ 55 x25_ifoutput(ifp, m0, dst, rt) 56 struct ifnet *ifp; 57 struct mbuf *m0; 58 struct sockaddr *dst; 59 register struct rtentry *rt; 60 { 61 register struct mbuf *m; 62 register struct llinfo_x25 *lx; 63 register struct pq *pq; 64 struct pklcd *lcp; 65 struct x25_ifaddr *ia; 66 struct mbuf *prev; 67 int s, error = 0, flags = 0, af; 68 69 if ((ifp->if_flags & IFF_UP) == 0) 70 return (ENETDOWN); 71 if (rt == 0 || 72 ((rt->rt_flags & RTF_GATEWAY) && (dst = rt->rt_gateway))) { 73 if ((rt = rtalloc1(dst, 1)) == 0) 74 return (EHOSTUNREACH); 75 rt->rt_refcnt++; 76 flags = LXF_RTHELD; 77 } 78 /* 79 * Sanity checks. 80 */ 81 if ((rt->rt_ifp != ifp) || 82 (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) || 83 ((lx = (struct llinfo_x25 *)rt->rt_llinfo) == 0)) { 84 printf("Inconsistent call to x25_output, should panic\n"); 85 senderr(ENETUNREACH); 86 } 87 { 88 register struct ifaddr *ifa; 89 for (ifa = ifp->if_addrlist; ; ifa = ifa->ifa_next) { 90 if (ifa == 0) 91 senderr(ENETDOWN); 92 if (ifa->ifa_addr->sa_family == AF_CCITT) 93 break; 94 } 95 ia = (struct x25_ifaddr *)ifa; 96 } 97 switch (lx->lx_state) { 98 99 case LXS_NEWBORN: 100 if (dst->sa_family == AF_INET && 101 ia->ia_ifp->if_type == IFT_X25DDN && 102 rt->rt_gateway->sa_family != AF_CCITT) 103 x25_ddnip_to_ccitt(dst, rt->rt_gateway); 104 lcp->lcd_flags |= X25_DG_CIRCUIT; 105 lx->lx_state = LXS_FREE; 106 if (rt->rt_gateway->sa_family != AF_CCITT) { 107 /* 108 * Need external resolution of dst 109 */ 110 if ((rt->rt_flags & RTF_XRESOLVE) == 0) 111 senderr(ENETUNREACH); 112 lx->lx_flags |= flags; 113 flags = 0; 114 lx->lx_state = LXS_RESOLVING; 115 /* FALLTHROUGH */ 116 case LXS_CONNECTED: 117 lcp->lcd_dg_timer = ia->ia_xc.xc_dg_idletimo; 118 /* FALLTHROUGH */ 119 case LXS_CONNECTING: 120 case LXS_RESOLVING: 121 if (sbspace(&lcp->lcd_sb) < 0) 122 senderr(ENOBUFS); 123 pk_send(lcp, m); 124 break; 125 } 126 /* FALLTHROUGH */ 127 case LXS_FREE: 128 lcp->lcd_pkp = &(lx->lx_ia->ia_pkcb); 129 pk_connect(lcp, (struct sockaddr_x25 *)rt->rt_gateway); 130 pk_send(lcp, m); 131 break; 132 133 default: 134 /* 135 * We count on the timer routine to close idle 136 * connections, if there are not enough circuits to go 137 * around. 138 * 139 * So throw away data for now. 140 * After we get it all working, we'll rewrite to handle 141 * actively closing connections (other than by timers), 142 * when circuits get tight. 143 * 144 * In the DDN case, the imp itself closes connections 145 * under heavy load. 146 */ 147 error = ENOBUFS; 148 bad: 149 if (m) 150 m_freem(m); 151 } 152 out: 153 if (flags & LXF_RTHELD) 154 RTFREE(rt); 155 return (error); 156 } 157 158 /* 159 * Simpleminded timer routine. 160 */ 161 x25_iftimeout(ifp) 162 struct ifnet *ifp; 163 { 164 register struct pkcb *pkcb = 0; 165 register struct ifaddr *ifa; 166 register struct pklcd **lcpp, *lcp; 167 int s = splimp(); 168 169 for (ifa = ifp->if_addrlist; ; ifa = ifa->ifa_next) { 170 if (ifa->ifa_addr->sa_family == AF_CCITT) 171 break; 172 } 173 if (ifa) 174 pkcb = &((struct x25_ifaddr *)ifa)->ia_pkcb; 175 if (pkcb) 176 for (lcpp = pkcb->pk_chan + pkcb->pk_maxlcn; 177 --lcpp > pkcb->pk_chan;) 178 if ((lcp = *lcpp) && 179 lcp->lcd_state == DATA_TRANSFER && 180 (lcp->lcd_flags & X25_DG_CIRCUIT) && 181 (lcp->lcd_dg_timer && --lcp->lcd_dg_timer == 0)) { 182 pk_disconnect(lcp); 183 } 184 splx(s); 185 } 186 187 /* 188 * Process a x25 packet as datagram; 189 */ 190 x25_ifinput(lcp, m) 191 struct pklcd *lcp; 192 register struct mbuf *m; 193 { 194 struct llinfo_x25 *lx = (struct llinfo_x25 *)lcp->lcd_upnext; 195 register struct ifnet *ifp = m->m_pkthdr.rcvif; 196 struct ifqueue *inq; 197 struct rtentry *rt; 198 extern struct timeval time; 199 int s, len, isr; 200 201 if (m == 0) 202 goto trouble; 203 ifp = m->m_pkthdr.rcvif; 204 ifp->if_lastchange = time; 205 switch (m->m_type) { 206 trouble: 207 case MT_CONTROL: 208 if (lcp->lcd_state != DATA_TRANSFER) { 209 lx->lx_lcd = 0; 210 if (lx->lx_rt == 0) 211 FREE(lx, M_PCB); 212 pk_close(lcp); 213 } 214 case MT_OOBDATA: 215 if (m) 216 m_freem(m); 217 return; 218 } 219 220 switch (lx->lx_family) { 221 #ifdef INET 222 case AF_INET: 223 isr = NETISR_IP; 224 inq = &ipintrq; 225 break; 226 227 #endif 228 #ifdef NS 229 case AF_NS: 230 isr = NETISR_NS; 231 inq = &nsintrq; 232 break; 233 234 #endif 235 #ifdef ISO 236 case AF_ISO: 237 isr = NETISR_ISO; 238 inq = &clnlintrq; 239 break; 240 #endif 241 default: 242 m_freem(m); 243 ifp->if_noproto++; 244 return; 245 } 246 s = splimp(); 247 schednetisr(isr); 248 if (IF_QFULL(inq)) { 249 IF_DROP(inq); 250 m_freem(m); 251 } else { 252 IF_ENQUEUE(inq, m); 253 ifp->if_ibytes += m->m_pkthdr.len; 254 } 255 splx(s); 256 } 257 258 /* 259 * This routine gets called when validing new routes or deletions of old 260 * ones. 261 */ 262 x25_ifrtchange(cmd, rt, dst) 263 register struct rtentry *rt; 264 struct sockaddr *dst; 265 { 266 register struct llinfo_x25 *lx = (struct llinfo_x25 *)rt->rt_llinfo; 267 register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway; 268 register struct pklcd *lcp; 269 register struct x25_ifaddr *ia; 270 register struct sockaddr *sa2; 271 struct rtentry *rt2; 272 int x25_ifinput(); 273 #define SA(p) ((struct sockaddr *)(p)) 274 275 if (cmd == RTM_DELETE) { 276 if (rt->rt_flags & RTF_GATEWAY) { 277 rt = (struct rtentry *)rt->rt_llinfo; 278 } else { 279 if (lx) { 280 if (lcp = lx->lx_lcd) 281 pk_disconnect(lcp); 282 FREE(lx, M_PCB); 283 } 284 rtrequest(RTM_DELETE, rt->rt_gateway, rt_key(rt), 285 SA(0), 0, (struct rtentry **) 0); 286 } 287 rt->rt_refcnt--; 288 rt->rt_llinfo = 0; 289 return; 290 } 291 if (lx == 0) { 292 MALLOC(lx, struct llinfo_x25 *, sizeof (*lx), M_PCB, M_NOWAIT); 293 if (lx == 0) 294 return; 295 Bzero(lx, sizeof(*lx)); 296 rt->rt_llinfo = (caddr_t)lx; 297 rt->rt_refcnt++; 298 lx->lx_rt = rt; 299 lx->lx_ia = (struct x25_ifaddr *)rt->rt_ifa; 300 } 301 if (rt->rt_flags & RTF_GATEWAY) { 302 rt2 = rtalloc1(rt_key(rt), 1); 303 if (rt2) { 304 rt->rt_refcnt++; 305 rt->rt_llinfo = (caddr_t)rt2; 306 } 307 return; 308 } 309 if (lcp && lcp->lcd_state != READY) { 310 pk_disconnect(lcp); 311 lcp = 0; 312 } 313 if (lcp == 0) { 314 if (rt->rt_flags & RTF_XRESOLVE || sa->x25_family != AF_CCITT) 315 return; 316 lx->lx_lcd = lcp = pk_attach((struct socket *)0); 317 ia = lx->lx_ia; 318 if (lcp == 0) 319 return; 320 lcp->lcd_upnext = (caddr_t)lx; 321 lcp->lcd_upper = x25_ifinput; 322 lcp->lcd_packetsize = ia->ia_xc.xc_psize; /* XXX pk_fragment */ 323 lcp->lcd_pkp = &(ia->ia_pkcb); 324 } 325 pk_connect(lcp, sa); 326 if (rt->rt_ifp->if_type == IFT_X25DDN) 327 return; 328 rtrequest(cmd, rt->rt_gateway, rt_key(rt), rt_mask(rt), rt->rt_flags, 329 &rt2); 330 if (rt2) { 331 rt2->rt_llinfo = (caddr_t) rt; 332 } 333 sa2 = rt_key(rt); 334 if (cmd == RTM_CHANGE) { 335 if (sa->x25_family == AF_CCITT) { 336 sa->x25_opts.op_speed = sa2->sa_family; 337 (void) rtrequest(RTM_DELETE, SA(sa), sa2, 338 SA(0), RTF_HOST, (struct rtentry **)0); 339 } 340 sa = (struct sockaddr_x25 *)dst; 341 cmd = RTM_ADD; 342 } 343 if (sa->x25_family == AF_CCITT) { 344 sa->x25_opts.op_speed = sa2->sa_family; 345 (void) rtrequest(cmd, SA(sa), sa2, SA(0), RTF_HOST, 346 (struct rtentry **)0); 347 sa->x25_opts.op_speed = 0; 348 } 349 } 350 351 static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; 352 /* 353 * IP to X25 address routine copyright ACC, used by permission. 354 */ 355 union imp_addr { 356 struct in_addr ip; 357 struct imp { 358 u_char s_net; 359 u_char s_host; 360 u_char s_lh; 361 u_char s_impno; 362 } imp; 363 }; 364 365 x25_ddnip_to_ccitt(src, dst) 366 struct sockaddr_in *src; 367 register struct sockaddr_x25 *dst; 368 { 369 union imp_addr imp_addr; 370 int imp_no, imp_port, temp; 371 char *x25addr = dst->x25_addr; 372 373 374 imp_addr.ip = src->sin_addr; 375 *dst = blank_x25; 376 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ 377 imp_no = imp_addr.imp.s_impno; 378 imp_port = imp_addr.imp.s_host; 379 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ 380 imp_no = imp_addr.imp.s_impno; 381 imp_port = imp_addr.imp.s_lh; 382 } else { /* class C */ 383 imp_no = imp_addr.imp.s_impno / 32; 384 imp_port = imp_addr.imp.s_impno % 32; 385 } 386 387 x25addr[0] = 12; /* length */ 388 /* DNIC is cleared by struct copy above */ 389 390 if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno 391 * -> III, s_host -> HH */ 392 x25addr[5] = 0; /* set flag bit */ 393 x25addr[6] = imp_no / 100; 394 x25addr[7] = (imp_no % 100) / 10; 395 x25addr[8] = imp_no % 10; 396 x25addr[9] = imp_port / 10; 397 x25addr[10] = imp_port % 10; 398 } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s 399 * _host * 256 + s_impno -> RRRRR */ 400 temp = (imp_port << 8) + imp_no; 401 x25addr[5] = 1; 402 x25addr[6] = temp / 10000; 403 x25addr[7] = (temp % 10000) / 1000; 404 x25addr[8] = (temp % 1000) / 100; 405 x25addr[9] = (temp % 100) / 10; 406 x25addr[10] = temp % 10; 407 } 408 } 409 410 static struct sockaddr_in sin = {sizeof(sin), AF_INET}; 411 /* 412 * This routine is a sketch and is not to be believed!!!!! 413 * 414 * This is a utility routine to be called by x25 devices when a 415 * call request is honored with the intent of starting datagram forwarding. 416 */ 417 x25_dg_rtinit(dst, ia, af) 418 struct sockaddr_x25 *dst; 419 register struct x25_ifaddr *ia; 420 { 421 struct sockaddr *sa = 0; 422 struct rtentry *rt; 423 struct in_addr my_addr; 424 425 if (ia->ia_ifp->if_type == IFT_X25DDN && af == AF_INET) { 426 /* 427 * Inverse X25 to IP mapping copyright and courtesy ACC. 428 */ 429 int imp_no, imp_port, temp; 430 union imp_addr imp_addr; 431 { 432 /* 433 * First determine our IP addr for network 434 */ 435 register struct in_ifaddr *ina; 436 extern struct in_ifaddr *in_ifaddr; 437 438 for (ina = in_ifaddr; ina; ina = ina->ia_next) 439 if (ina->ia_ifp == ia->ia_ifp) { 440 my_addr = ina->ia_addr.sin_addr; 441 break; 442 } 443 } 444 { 445 446 register char *x25addr = dst->x25_addr; 447 448 switch (x25addr[5] & 0x0f) { 449 case 0: /* Physical: 0000 0 IIIHH00 [SS] */ 450 imp_no = 451 ((int) (x25addr[6] & 0x0f) * 100) + 452 ((int) (x25addr[7] & 0x0f) * 10) + 453 ((int) (x25addr[8] & 0x0f)); 454 455 456 imp_port = 457 ((int) (x25addr[9] & 0x0f) * 10) + 458 ((int) (x25addr[10] & 0x0f)); 459 break; 460 case 1: /* Logical: 0000 1 RRRRR00 [SS] */ 461 temp = ((int) (x25addr[6] & 0x0f) * 10000) 462 + ((int) (x25addr[7] & 0x0f) * 1000) 463 + ((int) (x25addr[8] & 0x0f) * 100) 464 + ((int) (x25addr[9] & 0x0f) * 10) 465 + ((int) (x25addr[10] & 0x0f)); 466 467 imp_port = temp >> 8; 468 imp_no = temp & 0xff; 469 break; 470 default: 471 return (0L); 472 } 473 imp_addr.ip = my_addr; 474 if ((imp_addr.imp.s_net & 0x80) == 0x00) { 475 /* class A */ 476 imp_addr.imp.s_host = imp_port; 477 imp_addr.imp.s_impno = imp_no; 478 imp_addr.imp.s_lh = 0; 479 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { 480 /* class B */ 481 imp_addr.imp.s_lh = imp_port; 482 imp_addr.imp.s_impno = imp_no; 483 } else { 484 /* class C */ 485 imp_addr.imp.s_impno = (imp_no << 5) + imp_port; 486 } 487 } 488 sin.sin_addr = imp_addr.ip; 489 sa = (struct sockaddr *)&sin; 490 } else { 491 /* 492 * This uses the X25 routing table to do inverse 493 * lookup of x25 address to sockaddr. 494 */ 495 dst->x25_opts.op_speed = af; 496 if (rt = rtalloc1(dst, 0)) { 497 sa = rt->rt_gateway; 498 rt->rt_refcnt--; 499 } 500 dst->x25_opts.op_speed = 0; 501 } 502 /* 503 * Call to rtalloc1 will create rtentry for reverse path 504 * to callee by virtue of cloning magic and will allocate 505 * space for local control block. 506 */ 507 if (sa && (rt = rtalloc1(sa, 1))) 508 rt->rt_refcnt--; 509 } 510 511 struct radix_tree_head *x25_rnhead; 512 513 pk_init() 514 { 515 /* 516 * warning, sizeof (struct sockaddr_x25) > 32, 517 * but contains no data of interest beyond 32 518 */ 519 rn_inithead(&x25_rnhead, 32, AF_CCITT); 520 } 521