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