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.2 (Berkeley) 05/11/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 "if.h" 21 #include "netisr.h" 22 #include "route.h" 23 24 #include "x25_var.h" 25 #include "x25_pk.h" 26 #include "machine/mtpr.h" 27 28 #ifdef INET 29 #include "../netinet/in.h" 30 #include "../netinet/in_var.h" 31 #endif 32 33 #ifdef NS 34 #include "../netns/ns.h" 35 #include "../netns/ns_if.h" 36 #endif 37 38 #ifdef ISO 39 #include "../netiso/argo_debug.h" 40 #include "../netiso/iso.h" 41 #include "../netiso/iso_var.h" 42 #endif 43 44 extern struct ifnet loif; 45 46 #define senderr(x) {error = x; goto bad;} 47 /* 48 * X.25 output routine. 49 */ 50 x25_ifoutput(xc, m0, dst, rt) 51 struct x25com *xc; 52 struct mbuf *m0; 53 struct sockaddr *dst; 54 register struct rtentry *rt; 55 { 56 register struct mbuf *m = m0; 57 register struct x25lcb *xl; 58 register struct xq *oq; 59 register struct x25lcb **xlp; 60 struct mbuf *prev; 61 int s, error = 0, flags = 0; 62 union imp_addr imp_addr; 63 int flags = 0; 64 65 if ((xc->xc_if.if_flags & IFF_UP) == 0) 66 return (ENETDOWN); 67 if (rt == 0 || 68 ((rt->rt_flags & RTF_GATEWAY) && (dst = rt->rt_gateway))) { 69 if ((rt = rtalloc1(dst, 1)) == 0) 70 return (EHOSTUNREACH); 71 rt->rt_refcnt++; 72 flags = XL_RTHELD; 73 } 74 /* 75 * Sanity checks. 76 */ 77 if ((rt->rt_ifp != (struct ifnet *)xc) || 78 (rt->rt_flags & (RTF_CLONING | RTF_GATEWAY)) || 79 ((xl = (struct x25lcb *)rt->rt_llinfo) == 0)) { 80 printf("Inconsistent call to x25_output, should panic\n"); 81 senderr(ENETUNREACH); 82 } 83 xq = &xl->xl_downq; 84 switch (xl->xl_state) { 85 86 case XLS_CONNECTED: 87 xl->xl_timer = xc->xc_dg_idletimo; 88 /* FALLTHROUGH */ 89 case XLS_CONNECTING: 90 if (xq->xq_space < 0) 91 senderr(ENOBUFS); 92 xq->xq_put(xq, m); 93 break; 94 95 case XLS_NEWBORN: 96 xq = &xl->xl_upq; 97 xq->xq_next = (caddr_t)rt; 98 xq->xq_put = x25_ifinput; 99 if (dst->sa_family == AF_INET && 100 xc->xc_if.if_type == IFT_DDN && 101 rt->rt_gateway->sa_family != AF_CCITT) 102 x25_ddnip_to_ccitt(dst, rt->rt_gateway); 103 xl->xl_xc = xc; 104 xq = &xl->xl_downq; 105 xq->xq_space = 2048; /* XXX: bogus xq before if_start called */ 106 xl->xl_flags |= XL_DGRAM; 107 xl->xl_state = XLS_FREE; 108 if (rt->rt_gateway->sa_family != AF_CCITT) { 109 /* 110 * Need external resolution of dst 111 */ 112 if ((rt->rt_flags & RTF_XRESOLVE) == 0) 113 senderr(ENETUNREACH); 114 xl->xl_flags |= flags; 115 xl->xl_timer = xc->xc_rslvtimo; 116 flags = 0; 117 rt_missmsg(RTM_RESOLVE, dst, 118 (struct sockaddr *)0, (struct sockaddr *)0, 119 (struct sockaddr *)0, 0, 0); 120 xl->xl_state = XLS_RESOLVING; 121 /* FALLTHROUGH */ 122 case XLS_RESOLVING: 123 if (xq->xq_space < 0) 124 senderr(ENOBUFS); 125 xq->xq_space -= m->m_pkthdr.len; 126 if (xq->xq_data == 0) 127 xq->xq_data = m; 128 else { 129 for (m = xq->xq_data; m->m_nextpkt; ) 130 m = m->m_nextpkt; 131 m->m_nextpkt = m0; 132 } 133 break; 134 } 135 /* FALLTHROUGH */ 136 case XLS_FREE: 137 xlp = xc->xc_lcbvec + xc->xc_nchan; 138 s = splimp(); /* need to block out incoming requests */ 139 if (xc->xc_nactive < xc->xc_nchan) { 140 while (--xlp > xc->xc_lcbvec && *xlp) 141 ; 142 if (xlp > xc->xc_lcbvec) { 143 xc->xc_nactive++; 144 *xlp = xl; 145 xl->xl_index = xlp - xc->xc_lcbvec; 146 x25_ifstart(xl, m, rt->rt_gateway, dst); 147 splx(s); 148 break; 149 } 150 } 151 splx(s); 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 & XL_RTHELD) 174 RTFREE(rt); 175 return (error); 176 } 177 178 /* 179 * Simpleminded timer for very smart devices. 180 */ 181 x25_iftimeout(xc) 182 register struct x25com *xc; 183 { 184 register struct x25lcb **xlp = xc->xc_lcbvec + xc->xc_nchan; 185 register struct x25lcb *xl; 186 int s = splimp(); 187 188 if (xc->xc_disconnect) 189 while (--xlp > xc->xc_lcbvec) 190 if ((xl = *xlp) && xl->xl_state == XLS_CONECTED && 191 (xl->xl_flags & XL_DGRAM) && --(xl->xl_timer) <= 0) 192 xc->xc_disconnect(xl); 193 splx(s); 194 } 195 196 /* 197 * Process a x25 packet as datagram; 198 */ 199 x25_ifinput(xq, m) 200 struct xq *xq; 201 struct mbuf *m; 202 { 203 struct rtentry *rt = (struct rtentry *)xq->xq_next; 204 struct x25lcb *xl = (struct x25lcb *)rt->rt_llinfo; 205 register struct ifnet *ifp = &xl->xl_xc.xc_if; 206 register struct llc *l; 207 int s; 208 209 ifp->if_lastchange = time; 210 211 switch (rt_dst(rt)->sa_family) { 212 #ifdef INET 213 case AF_INET: 214 schednetisr(NETISR_IP); 215 inq = &ipintrq; 216 break; 217 218 #endif 219 #ifdef NS 220 case AF_NS: 221 schednetisr(NETISR_NS); 222 inq = &nsintrq; 223 break; 224 225 #endif 226 #ifdef ISO 227 case AF_ISO: 228 /* XXXX need to find out about tearing off COSNS 229 headers if any */ 230 schednetisr(NETISR_ISO); 231 inq = &clnlintrq; 232 break; 233 #endif 234 default: 235 m_freem(m); 236 ifp->if_noproto++; 237 return; 238 } 239 s = splimp(); 240 if (IF_QFULL(inq)) { 241 IF_DROP(inq); 242 m_freem(m); 243 } else { 244 IF_ENQUEUE(inq, m); 245 ifp->if_ibytes += m->m_pkthdr.len; 246 } 247 splx(s); 248 } 249 250 union imp_addr { 251 struct in_addr ip; 252 struct imp { 253 u_char s_net; 254 u_char s_host; 255 u_char s_lh; 256 u_char s_impno; 257 } imp; 258 }; 259 static struct sockaddr_x25 blank_x25 = {sizeof blank_x25, AF_CCITT}; 260 /* 261 * IP to X25 address routine copyright ACC, used by permission. 262 */ 263 x25_ddnip_to_ccitt(src, dst) 264 struct sockaddr_in *src; 265 register struct sockaddr_x25 *dst; 266 { 267 union imp_addr imp_addr; 268 int imp_no, imp_port; 269 char *x25addr = dst->x25_x25addr; 270 271 272 imp_addr.ip = src->sin_addr.s_addr; 273 *dst = blank_x25; 274 if ((imp_addr.imp.s_net & 0x80) == 0x00) { /* class A */ 275 imp_no = imp_addr.imp.s_impno; 276 imp_port = imp_addr.imp.s_host; 277 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { /* class B */ 278 imp_no = imp_addr.imp.s_impno; 279 imp_port = imp_addr.imp.s_lh; 280 } else { /* class C */ 281 imp_no = imp_addr.imp.s_impno / 32; 282 imp_port = imp_addr.imp.s_impno % 32; 283 } 284 285 x25addr[0] = 12; /* length */ 286 /* DNIC is cleared by struct copy above */ 287 288 if (imp_port < 64) { /* Physical: 0000 0 IIIHH00 [SS] *//* s_impno 289 * -> III, s_host -> HH */ 290 x25addr[5] = 0; /* set flag bit */ 291 x25addr[6] = imp_no / 100; 292 x25addr[7] = (imp_no % 100) / 10; 293 x25addr[8] = imp_no % 10; 294 x25addr[9] = imp_port / 10; 295 x25addr[10] = imp_port % 10; 296 } else { /* Logical: 0000 1 RRRRR00 [SS] *//* s 297 * _host * 256 + s_impno -> RRRRR */ 298 temp = (imp_port << 8) + imp_no; 299 x25addr[5] = 1; 300 x25addr[6] = temp / 10000; 301 x25addr[7] = (temp % 10000) / 1000; 302 x25addr[8] = (temp % 1000) / 100; 303 x25addr[9] = (temp % 100) / 10; 304 x25addr[10] = temp % 10; 305 } 306 } 307 308 #ifdef caseof 309 #undef caseof 310 #endif 311 #define caseof(a, b) (b + 8 * a) 312 #define SA(p) ((struct sockaddr *)(p)) 313 314 /* 315 * This routine gets called when validing new routes or deletions of old 316 * ones. 317 */ 318 x25_ifrtchange(cmd, rt, dst) 319 register struct rtentry *rt; 320 struct sockaddr *dst; 321 { 322 register struct x25lcb *xl = (struct x25lcb *)rt->rt_llinfo; 323 register struct x25com *xc; 324 register struct sockaddr_x25 *sa =(struct sockaddr_x25 *)rt->rt_gateway; 325 register struct sockaddr *sa2; 326 struct mbuf *m, *mold; 327 328 if (xl == 0) 329 return; 330 xc = xl->xl_xc; 331 switch (caseof(xl->xl_state, cmd)) { 332 case caseof(XLS_CONNECTED, RTM_DELETE): 333 case caseof(XLS_CONNECTED, RTM_CHANGE): 334 case caseof(XLS_CONNECTING, RTM_DELETE): 335 case caseof(XLS_CONNECTING, RTM_CHANGE): 336 xc->xc_disconnect(xl); 337 break; 338 339 case caseof(XLS_CONNECTED, RTM_ADD): 340 case caseof(XLS_CONNECTING, RTM_ADD): 341 case caseof(XLS_RESOLVING, RTM_ADD): 342 printf("ifrtchange: impossible transition, should panic\n"); 343 break; 344 345 case caseof(XLS_RESOLVING, RTM_DELETE): 346 for (m = xl->xl_downq.xq_data; m;) { 347 mold = m; 348 m = m->m_nextpkt; 349 m_freem(mold); 350 } 351 break; 352 353 case caseof(XLS_RESOLVING, RTM_CHANGE): 354 xc->xc_if.if_start(xl, 0, dst); 355 break; 356 } 357 if (xc->xc_if.if_type == IFT_DDN) 358 return; /* reverse name table not necessary */ 359 sa2 = SA(rt->rt_key); 360 if (cmd == RTM_CHANGE) { 361 if (sa->sa_family == AF_CCITT) { 362 sa->sa_rfamily = sa2->sa_family; 363 (void) rtrequest(RTM_DELETE, SA(sa), sa2, 364 SA(0), RTF_HOST, (struct rtentry **)0); 365 } 366 sa = (struct sockaddr_x25 *)dst; 367 cmd = RTM_ADD; 368 } 369 if (sa->sa_family == AF_CCITT) { 370 sa->sa_rfamily = sa2->sa_family; 371 (void) rtrequest(cmd, SA(sa), sa2, SA(0), RTF_HOST, 372 (struct rtentry **)0); 373 sa->sa_rfamily = 0; 374 } 375 } 376 static struct sockaddr sin = {sizeof(sin), AF_INET}; 377 /* 378 * This is a utility routine to be called by x25 devices when a 379 * call request is honored with the intent of starting datagram forwarding. 380 */ 381 x25_dg_rtinit(dst, xc, af) 382 struct sockaddr_x25 *dst; 383 register struct x25com *xc; 384 { 385 struct sockaddr *sa = 0; 386 if (xc->xc_if.if_type == IFT_DDN && af == AF_INET) { 387 /* 388 * Inverse X25 to IPP mapping copyright and courtesy ACC. 389 */ 390 int imp_no, imp_port, temp; 391 union imp_addr imp_addr; 392 { 393 /* 394 * First determine our IP addr for network 395 */ 396 register struct in_ifaddr *ia; 397 extern struct in_ifaddr *in_ifaddr; 398 for (ia = in_ifaddr; ia; ia = ia->ia_next) 399 if (ia->ia_ifp == &xc->xc_if) { 400 imp_addr.ip = ia->ia_addr.sin_addr; 401 break; 402 } 403 } 404 { 405 406 register char *x25addr = dst->x25_addr; 407 408 switch (x25addr[5] & 0x0f) { 409 case 0: /* Physical: 0000 0 IIIHH00 [SS] */ 410 imp_no = 411 ((int) (x25addr[6] & 0x0f) * 100) + 412 ((int) (x25addr[7] & 0x0f) * 10) + 413 ((int) (x25addr[8] & 0x0f)); 414 415 416 imp_port = 417 ((int) (x25addr[9] & 0x0f) * 10) + 418 ((int) (x25addr[10] & 0x0f)); 419 break; 420 case 1: /* Logical: 0000 1 RRRRR00 [SS] */ 421 temp = ((int) (x25addr[6] & 0x0f) * 10000) 422 + ((int) (x25addr[7] & 0x0f) * 1000) 423 + ((int) (x25addr[8] & 0x0f) * 100) 424 + ((int) (x25addr[9] & 0x0f) * 10) 425 + ((int) (x25addr[10] & 0x0f)); 426 427 imp_port = temp >> 8; 428 imp_no = temp & 0xff; 429 break; 430 default: 431 return (0L); 432 } 433 imp_addr.ip.s_addr = my_addr; 434 if ((imp_addr.imp.s_net & 0x80) == 0x00) { 435 /* class A */ 436 imp_addr.imp.s_host = imp_port; 437 imp_addr.imp.s_impno = imp_no; 438 imp_addr.imp.s_lh = 0; 439 } else if ((imp_addr.imp.s_net & 0xc0) == 0x80) { 440 /* class B */ 441 imp_addr.imp.s_lh = imp_port; 442 imp_addr.imp.s_impno = imp_no; 443 } else { 444 /* class C */ 445 imp_addr.imp.s_impno = (imp_no << 5) + imp_port; 446 } 447 } 448 sin.sin_addr = imp_addr.ip; 449 sa = (struct sockaddr *)&sin; 450 } else { 451 /* 452 * This uses the X25 routing table to do inverse 453 * lookup of x25 address to sockaddr. 454 */ 455 dst->sa_rfamily = af; 456 if (rt = rtalloc1(dst, 0)) { 457 sa = rt->rt_gateway; 458 rt->rt_refcnt--; 459 } 460 dst->sa_rfamily = 0; 461 } 462 /* 463 * Call to rtalloc1 will create rtentry for reverse path 464 * to callee by virtue of cloning magic and will allocate 465 * space for local control block. 466 */ 467 if (sa && rt = rtalloc1(sa, 1)) 468 rt->rt_refcnt--; 469 } 470