1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)rtsock.c 7.13 (Berkeley) 07/24/90 8 */ 9 10 #include "param.h" 11 #include "mbuf.h" 12 #include "user.h" 13 #include "proc.h" 14 #include "socket.h" 15 #include "socketvar.h" 16 #include "domain.h" 17 #include "protosw.h" 18 #include "errno.h" 19 20 #include "af.h" 21 #include "if.h" 22 #include "route.h" 23 #include "raw_cb.h" 24 25 #include "machine/mtpr.h" 26 27 struct sockaddr route_dst = { 2, PF_ROUTE, }; 28 struct sockaddr route_src = { 2, PF_ROUTE, }; 29 struct sockproto route_proto = { PF_ROUTE, }; 30 31 /*ARGSUSED*/ 32 route_usrreq(so, req, m, nam, control) 33 register struct socket *so; 34 int req; 35 struct mbuf *m, *nam, *control; 36 { 37 register int error = 0; 38 register struct rawcb *rp = sotorawcb(so); 39 int s; 40 if (req == PRU_ATTACH) { 41 MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); 42 if (so->so_pcb = (caddr_t)rp) 43 bzero(so->so_pcb, sizeof(*rp)); 44 45 } 46 if (req == PRU_DETACH && rp) { 47 int af = rp->rcb_proto.sp_protocol; 48 if (af == AF_INET) 49 route_cb.ip_count--; 50 else if (af == AF_NS) 51 route_cb.ns_count--; 52 else if (af == AF_ISO) 53 route_cb.iso_count--; 54 route_cb.any_count--; 55 } 56 s = splnet(); 57 error = raw_usrreq(so, req, m, nam, control); 58 rp = sotorawcb(so); 59 if (req == PRU_ATTACH && rp) { 60 int af = rp->rcb_proto.sp_protocol; 61 if (error) { 62 free((caddr_t)rp, M_PCB); 63 splx(s); 64 return (error); 65 } 66 if (af == AF_INET) 67 route_cb.ip_count++; 68 else if (af == AF_NS) 69 route_cb.ns_count++; 70 else if (af == AF_ISO) 71 route_cb.iso_count++; 72 rp->rcb_faddr = &route_src; 73 route_cb.any_count++; 74 soisconnected(so); 75 so->so_options |= SO_USELOOPBACK; 76 } 77 splx(s); 78 return (error); 79 } 80 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 81 82 /*ARGSUSED*/ 83 route_output(m, so) 84 register struct mbuf *m; 85 struct socket *so; 86 { 87 register struct rt_msghdr *rtm = 0; 88 register struct rtentry *rt = 0; 89 struct rtentry *saved_nrt = 0; 90 struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0; 91 struct sockaddr *ifpaddr = 0; 92 caddr_t cp, lim; 93 int len, error = 0; 94 struct ifnet *ifp = 0; 95 struct ifaddr *ifa; 96 extern struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute(); 97 98 #define senderr(e) { error = e; goto flush;} 99 if (m == 0 || m->m_len < sizeof(long)) 100 return (ENOBUFS); 101 if ((m = m_pullup(m, sizeof(long))) == 0) 102 return (ENOBUFS); 103 if ((m->m_flags & M_PKTHDR) == 0) 104 panic("route_output"); 105 len = m->m_pkthdr.len; 106 if (len < sizeof(*rtm) || 107 len != mtod(m, struct rt_msghdr *)->rtm_msglen) 108 senderr(EINVAL); 109 R_Malloc(rtm, struct rt_msghdr *, len); 110 if (rtm == 0) 111 senderr(ENOBUFS); 112 m_copydata(m, 0, len, (caddr_t)rtm); 113 if (rtm->rtm_version != RTM_VERSION) 114 senderr(EPROTONOSUPPORT); 115 rtm->rtm_pid = u.u_procp->p_pid; 116 lim = len + (caddr_t) rtm; 117 cp = (caddr_t) (rtm + 1); 118 if (rtm->rtm_addrs & RTA_DST) { 119 dst = (struct sockaddr *)cp; 120 cp += ROUNDUP(dst->sa_len); 121 } else 122 senderr(EINVAL); 123 if ((rtm->rtm_addrs & RTA_GATEWAY) && cp < lim) { 124 gate = (struct sockaddr *)cp; 125 cp += ROUNDUP(gate->sa_len); 126 } 127 if ((rtm->rtm_addrs & RTA_NETMASK) && cp < lim) { 128 netmask = (struct sockaddr *)cp; 129 if (*cp) 130 cp += ROUNDUP(netmask->sa_len); 131 else 132 cp += sizeof(long); 133 134 } 135 if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim) { 136 struct radix_node *t, *rn_addmask(); 137 genmask = (struct sockaddr *)cp; 138 if (*cp) 139 cp += ROUNDUP(netmask->sa_len); 140 else 141 cp += sizeof(long); 142 t = rn_addmask(genmask, 1, 2); 143 if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0) 144 genmask = (struct sockaddr *)(t->rn_key); 145 else 146 senderr(ENOBUFS); 147 } 148 if ((rtm->rtm_addrs & RTA_IFP) && cp < lim) { 149 ifpaddr = (struct sockaddr *)cp; 150 } 151 switch (rtm->rtm_type) { 152 case RTM_ADD: 153 if (gate == 0) 154 senderr(EINVAL); 155 error = rtrequest(RTM_ADD, dst, gate, netmask, 156 rtm->rtm_flags, &saved_nrt); 157 if (error == 0 && saved_nrt) { 158 rt_setmetrics(rtm->rtm_inits, 159 &rtm->rtm_rmx, &saved_nrt->rt_rmx); 160 saved_nrt->rt_refcnt--; 161 saved_nrt->rt_genmask = genmask; 162 } 163 break; 164 165 case RTM_DELETE: 166 error = rtrequest(RTM_DELETE, dst, gate, netmask, 167 rtm->rtm_flags, (struct rtentry **)0); 168 break; 169 170 case RTM_GET: 171 case RTM_CHANGE: 172 case RTM_LOCK: 173 rt = rtalloc1(dst, 0); 174 if (rt == 0) 175 senderr(ESRCH); 176 switch(rtm->rtm_type) { 177 struct sockaddr *outmask; 178 179 case RTM_GET: 180 netmask = rt_mask(rt); 181 len = sizeof(*rtm) + ROUNDUP(rt_key(rt)->sa_len); 182 rtm->rtm_addrs = RTA_DST; 183 if (rt->rt_gateway) { 184 len += ROUNDUP(rt->rt_gateway->sa_len); 185 rtm->rtm_addrs |= RTA_GATEWAY; 186 } 187 if (netmask) { 188 len += netmask->sa_len; 189 rtm->rtm_addrs |= RTA_NETMASK; 190 } 191 if (len > rtm->rtm_msglen) { 192 struct rt_msghdr *new_rtm; 193 R_Malloc(new_rtm, struct rt_msghdr *, len); 194 if (new_rtm == 0) 195 senderr(ENOBUFS); 196 Bcopy(rtm, new_rtm, rtm->rtm_msglen); 197 Free(rtm); rtm = new_rtm; 198 gate = (struct sockaddr *) 199 (ROUNDUP(rt->rt_gateway->sa_len) 200 + (char *)dst); 201 Bcopy(&rt->rt_gateway, gate, 202 rt->rt_gateway->sa_len); 203 rtm->rtm_flags = rt->rt_flags; 204 if (netmask) { 205 outmask = (struct sockaddr *) 206 (ROUNDUP(netmask->sa_len)+(char *)gate); 207 Bcopy(netmask, outmask, netmask->sa_len); 208 } 209 } 210 break; 211 212 case RTM_CHANGE: 213 if (gate == 0 || netmask != 0) 214 senderr(EINVAL); 215 if (gate->sa_len > (len = rt->rt_gateway->sa_len)) 216 senderr(EDQUOT); 217 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 218 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, gate); 219 /* new gateway could require new ifaddr, ifp; 220 flags may also be different; ifp may be specified 221 by ll sockaddr when protocol address is ambiguous */ 222 if (ifpaddr && 223 (ifa = ifa_ifwithnet(ifpaddr)) && 224 (ifp = ifa->ifa_ifp) && 225 (ifa = ifaof_ifpforaddr(gate, ifp))) { 226 /* We got it */ 227 } else { 228 ifa = 0; ifp = 0; 229 } 230 Bcopy(gate, rt->rt_gateway, len); 231 rt->rt_gateway->sa_len = len; 232 rt_setmetrics(rtm->rtm_inits, 233 &rtm->rtm_rmx, &rt->rt_rmx); 234 if (ifa == 0) 235 ifa = ifa_ifwithroute(rt->rt_flags, rt_key(rt), 236 gate); 237 if (ifa) { 238 if (rt->rt_ifa != ifa) { 239 rt->rt_ifa = ifa; 240 rt->rt_ifp = ifa->ifa_ifp; 241 } 242 } 243 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) 244 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate); 245 if (genmask) 246 rt->rt_genmask = genmask; 247 /* 248 * Fall into 249 */ 250 case RTM_LOCK: 251 rt->rt_rmx.rmx_locks |= 252 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); 253 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); 254 break; 255 } 256 goto cleanup; 257 258 default: 259 senderr(EOPNOTSUPP); 260 } 261 262 flush: 263 if (rtm) { 264 if (error) 265 rtm->rtm_errno = error; 266 else 267 rtm->rtm_flags |= RTF_DONE; 268 } 269 cleanup: 270 if (rt) 271 rtfree(rt); 272 { 273 register struct rawcb *rp = 0; 274 /* 275 * Check to see if we don't want our own messages. 276 */ 277 if ((so->so_options & SO_USELOOPBACK) == 0) { 278 if (route_cb.any_count <= 1) { 279 if (rtm) 280 Free(rtm); 281 m_freem(m); 282 return (error); 283 } 284 /* There is another listener, so construct message */ 285 rp = sotorawcb(so); 286 } 287 if (cp = (caddr_t)rtm) { 288 m_copyback(m, 0, len, cp); 289 Free(rtm); 290 } 291 if (rp) 292 rp->rcb_proto.sp_family = 0; /* Avoid us */ 293 route_proto.sp_protocol = dst->sa_family; 294 raw_input(m, &route_proto, &route_src, &route_dst); 295 if (rp) 296 rp->rcb_proto.sp_family = PF_ROUTE; 297 } 298 return (error); 299 } 300 301 rt_setmetrics(which, in, out) 302 u_long which; 303 register struct rt_metrics *in, *out; 304 { 305 #define metric(f, e) if (which & (f)) out->e = in->e; 306 metric(RTV_RPIPE, rmx_recvpipe); 307 metric(RTV_SPIPE, rmx_sendpipe); 308 metric(RTV_SSTHRESH, rmx_ssthresh); 309 metric(RTV_RTT, rmx_rtt); 310 metric(RTV_RTTVAR, rmx_rttvar); 311 metric(RTV_HOPCOUNT, rmx_hopcount); 312 metric(RTV_MTU, rmx_mtu); 313 #undef metric 314 } 315 316 /* 317 * Copy data from a buffer back into the indicated mbuf chain, 318 * starting "off" bytes from the beginning, extending the mbuf 319 * chain if necessary. 320 */ 321 m_copyback(m0, off, len, cp) 322 struct mbuf *m0; 323 register int off; 324 register int len; 325 caddr_t cp; 326 327 { 328 register int mlen; 329 register struct mbuf *m = m0, *n; 330 int totlen = 0; 331 332 if (m0 == 0) 333 return; 334 while (off >= (mlen = m->m_len)) { 335 off -= mlen; 336 totlen += mlen; 337 if (m->m_next == 0) { 338 n = m_getclr(M_DONTWAIT, m->m_type); 339 if (n == 0) 340 goto out; 341 n->m_len = min(MLEN, len + off); 342 m->m_next = n; 343 } 344 m = m->m_next; 345 } 346 while (len > 0) { 347 mlen = min (m->m_len - off, len); 348 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 349 cp += mlen; 350 len -= mlen; 351 mlen += off; 352 off = 0; 353 totlen += mlen; 354 if (len == 0) 355 break; 356 if (m->m_next == 0) { 357 n = m_get(M_DONTWAIT, m->m_type); 358 if (n == 0) 359 break; 360 n->m_len = min(MLEN, len); 361 m->m_next = n; 362 } 363 m = m->m_next; 364 } 365 out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 366 m->m_pkthdr.len = totlen; 367 } 368 369 /* 370 * The miss message and losing message are very similar. 371 */ 372 373 rt_missmsg(type, dst, gate, mask, src, flags, error) 374 register struct sockaddr *dst; 375 struct sockaddr *gate, *mask, *src; 376 { 377 register struct rt_msghdr *rtm; 378 register struct mbuf *m; 379 int dlen = ROUNDUP(dst->sa_len); 380 int len = dlen + sizeof(*rtm); 381 382 if (route_cb.any_count == 0) 383 return; 384 m = m_gethdr(M_DONTWAIT, MT_DATA); 385 if (m == 0) 386 return; 387 m->m_pkthdr.len = m->m_len = min(len, MHLEN); 388 m->m_pkthdr.rcvif = 0; 389 rtm = mtod(m, struct rt_msghdr *); 390 bzero((caddr_t)rtm, sizeof(*rtm)); /*XXX assumes sizeof(*rtm) < MHLEN*/ 391 rtm->rtm_flags = RTF_DONE | flags; 392 rtm->rtm_msglen = len; 393 rtm->rtm_version = RTM_VERSION; 394 rtm->rtm_type = type; 395 rtm->rtm_addrs = RTA_DST; 396 if (type == RTM_OLDADD || type == RTM_OLDDEL) { 397 rtm->rtm_pid = u.u_procp->p_pid; 398 } 399 m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst); 400 if (gate) { 401 dlen = ROUNDUP(gate->sa_len); 402 m_copyback(m, len , dlen, (caddr_t)gate); 403 len += dlen; 404 rtm->rtm_addrs |= RTA_GATEWAY; 405 } 406 if (mask) { 407 if (mask->sa_len) 408 dlen = ROUNDUP(mask->sa_len); 409 else 410 dlen = sizeof(long); 411 m_copyback(m, len , dlen, (caddr_t)mask); 412 len += dlen; 413 rtm->rtm_addrs |= RTA_NETMASK; 414 } 415 if (src) { 416 dlen = ROUNDUP(src->sa_len); 417 m_copyback(m, len , dlen, (caddr_t)src); 418 len += dlen; 419 rtm->rtm_addrs |= RTA_AUTHOR; 420 } 421 if (m->m_pkthdr.len != len) { 422 m_freem(m); 423 return; 424 } 425 rtm->rtm_errno = error; 426 rtm->rtm_msglen = len; 427 route_proto.sp_protocol = dst->sa_family; 428 raw_input(m, &route_proto, &route_src, &route_dst); 429 } 430 431 #include "kinfo.h" 432 struct walkarg { 433 int w_op, w_arg; 434 int w_given, w_needed; 435 caddr_t w_where; 436 struct { 437 struct rt_msghdr m_rtm; 438 char m_sabuf[128]; 439 } w_m; 440 #define w_rtm w_m.m_rtm 441 }; 442 /* 443 * This is used in dumping the kernel table via getkinfo(). 444 */ 445 rt_dumpentry(rn, w) 446 struct radix_node *rn; 447 register struct walkarg *w; 448 { 449 register struct sockaddr *sa; 450 int n, error; 451 452 for (; rn; rn = rn->rn_dupedkey) { 453 int count = 0, size = sizeof(w->w_rtm); 454 register struct rtentry *rt = (struct rtentry *)rn; 455 456 if (rn->rn_flags & RNF_ROOT) 457 continue; 458 if (w->w_op == KINFO_RT_FLAGS && !(rt->rt_flags & w->w_arg)) 459 continue; 460 #define next(a, l) {size += (l); w->w_rtm.rtm_addrs |= (a); } 461 w->w_rtm.rtm_addrs = 0; 462 if (sa = rt_key(rt)) 463 next(RTA_DST, ROUNDUP(sa->sa_len)); 464 if (sa = rt->rt_gateway) 465 next(RTA_GATEWAY, ROUNDUP(sa->sa_len)); 466 if (sa = rt_mask(rt)) 467 next(RTA_NETMASK, 468 sa->sa_len ? ROUNDUP(sa->sa_len) : sizeof(long)); 469 if (sa = rt->rt_genmask) 470 next(RTA_GENMASK, ROUNDUP(sa->sa_len)); 471 w->w_needed += size; 472 if (w->w_where == NULL || w->w_needed > 0) 473 continue; 474 w->w_rtm.rtm_msglen = size; 475 w->w_rtm.rtm_flags = rt->rt_flags; 476 w->w_rtm.rtm_use = rt->rt_use; 477 w->w_rtm.rtm_rmx = rt->rt_rmx; 478 w->w_rtm.rtm_index = rt->rt_ifp->if_index; 479 #undef next 480 #define next(l) {n = (l); Bcopy(sa, cp, n); cp += n;} 481 if (size <= sizeof(w->w_m)) { 482 register caddr_t cp = (caddr_t)(w->w_m.m_sabuf); 483 if (sa = rt_key(rt)) 484 next(ROUNDUP(sa->sa_len)); 485 if (sa = rt->rt_gateway) 486 next(ROUNDUP(sa->sa_len)); 487 if (sa = rt_mask(rt)) 488 next(sa->sa_len ? ROUNDUP(sa->sa_len) : sizeof(long)); 489 if (sa = rt->rt_genmask) 490 next(ROUNDUP(sa->sa_len)); 491 #undef next 492 #define next(s, l) {n = (l); \ 493 if (error = copyout((caddr_t)(s), w->w_where, n)) return (error); \ 494 w->w_where += n;} 495 496 next(&w->w_m, size); /* Copy rtmsg and sockaddrs back */ 497 continue; 498 } 499 next(&w->w_rtm, sizeof(w->w_rtm)); 500 if (sa = rt_key(rt)) 501 next(sa, ROUNDUP(sa->sa_len)); 502 if (sa = rt->rt_gateway) 503 next(sa, ROUNDUP(sa->sa_len)); 504 if (sa = rt_mask(rt)) 505 next(sa, sa->sa_len ? ROUNDUP(sa->sa_len) : sizeof(long)); 506 if (sa = rt->rt_genmask) 507 next(sa, ROUNDUP(sa->sa_len)); 508 } 509 return (0); 510 #undef next 511 } 512 513 kinfo_rtable(op, where, given, arg, needed) 514 int op, arg; 515 caddr_t where; 516 int *given, *needed; 517 { 518 register struct radix_node_head *rnh; 519 int s, error = 0; 520 u_char af = ki_af(op); 521 struct walkarg w; 522 523 op &= 0xffff; 524 if (op != KINFO_RT_DUMP && op != KINFO_RT_FLAGS) 525 return (EINVAL); 526 527 Bzero(&w, sizeof(w)); 528 if ((w.w_where = where) && given) 529 w.w_given = *given; 530 w.w_needed = 0 - w.w_given; 531 w.w_arg = arg; 532 w.w_op = op; 533 w.w_rtm.rtm_version = RTM_VERSION; 534 w.w_rtm.rtm_type = RTM_GET; 535 536 s = splnet(); 537 for (rnh = radix_node_head; rnh; rnh = rnh->rnh_next) { 538 if (rnh->rnh_af == 0) 539 continue; 540 if (af && af != rnh->rnh_af) 541 continue; 542 error = rt_walk(rnh->rnh_treetop, rt_dumpentry, &w); 543 if (error) 544 break; 545 } 546 w.w_needed += w.w_given; 547 if (where && given) 548 *given = w.w_where - where; 549 else 550 w.w_needed = (11 * w.w_needed) / 10; 551 *needed = w.w_needed; 552 splx(s); 553 return (error); 554 } 555 556 rt_walk(rn, f, w) 557 register struct radix_node *rn; 558 register int (*f)(); 559 struct walkarg *w; 560 { 561 int error; 562 for (;;) { 563 while (rn->rn_b >= 0) 564 rn = rn->rn_l; /* First time through node, go left */ 565 if (error = (*f)(rn, w)) 566 return (error); /* Process Leaf */ 567 while (rn->rn_p->rn_r == rn) { /* if coming back from right */ 568 rn = rn->rn_p; /* go back up */ 569 if (rn->rn_flags & RNF_ROOT) 570 return 0; 571 } 572 rn = rn->rn_p->rn_r; /* otherwise, go right*/ 573 } 574 } 575 576 /* 577 * Definitions of protocols supported in the ROUTE domain. 578 */ 579 580 int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput(); 581 extern struct domain routedomain; /* or at least forward */ 582 583 struct protosw routesw[] = { 584 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 585 raw_input, route_output, raw_ctlinput, 0, 586 route_usrreq, 587 raw_init, 0, 0, 0, 588 } 589 }; 590 591 int unp_externalize(), unp_dispose(); 592 593 struct domain routedomain = 594 { PF_ROUTE, "route", 0, 0, 0, 595 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 596