1 /* route.c 4.1 82/03/27 */ 2 3 #include "../h/param.h" 4 #include "../h/mbuf.h" 5 #include "../h/protosw.h" 6 #include "../h/socket.h" 7 #include "../h/socketvar.h" 8 #include "../net/in.h" 9 #include "../net/in_systm.h" 10 #include "../net/af.h" 11 #include "../net/route.h" 12 #include <errno.h> 13 14 /* 15 * Packet routing routines. 16 */ 17 18 /* 19 * With much ado about nothing... 20 * route the cars that climb halfway to the stars... 21 */ 22 route(ro) 23 register struct route *ro; 24 { 25 register struct rtentry *rt, *rtmin; 26 register struct mbuf *m; 27 struct afhash h; 28 struct sockaddr *dst = &ro->ro_dst; 29 int af = dst->sa_family; 30 31 COUNT(ROUTE); 32 if (ro->ro_ifp) /* ??? */ 33 return; 34 (*afswitch[af].af_hash)(dst, &h); 35 m = routehash[h.afh_hosthash % RTHASHSIZ]; 36 key = h.afh_hostkey; 37 rtmin = 0, doinghost = 1; 38 again: 39 for (; m; m = m->m_next) { 40 rt = mtod(m, struct rtentry *); 41 #define equal(a1, a2) \ 42 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0) 43 if (rt->rt_key != key) 44 continue; 45 if (doinghost) { 46 if (!equal(&rt->rt_dst, dst)) 47 continue; 48 } else { 49 if (rt->rt_dst.sa_family != af) 50 continue; 51 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, dst) == 0) 52 continue; 53 } 54 if (rtmin == 0 || rt->rt_use < rtmin->rt_use) 55 rtmin = rt; 56 } 57 if (rtmin) { 58 ro->ro_dst = rt->rt_dst; 59 ro->ro_rt = rt; 60 rt->rt_refcnt++; 61 return; 62 } 63 if (doinghost) { 64 doinghost = 0; 65 m = routethash[h.afh_nethash % RTHASHSIZ]; 66 key = h.afh_netkey; 67 goto again; 68 } 69 ro->ro_ifp = 0; 70 ro->ro_rt = 0; 71 } 72 73 struct rtentry * 74 reroute(sa) 75 register struct sockaddr *sa; 76 { 77 register struct rtentry *rt; 78 register struct mbuf *m; 79 struct afhash h; 80 81 COUNT(REROUTE); 82 (*afswitch[sa->sa_family].af_hash)(sa, &h); 83 m = routehash[h.afh_hosthash]; 84 key = h.afh_hostkey; 85 for (; m; m = m->m_next) { 86 rt = mtod(m, struct rtentry *); 87 if (rt->rt_key != key) 88 continue; 89 if (equal(&rt->rt_gateway, sa)) 90 return (rt); 91 } 92 return (0); 93 } 94 95 /* 96 * Routing control calls allow a routing daemon 97 * to consistenly access the routing data base for updates. 98 */ 99 rtcontrol(req, addr) 100 caddr_t addr; 101 { 102 register struct rtreq rq; 103 int x = splimp(), err = 0; 104 105 COUNT(RTCONTROL); 106 if (suser()) 107 goto bad; 108 if (copyin(addr, (caddr_t)&rq, sizeof(struct rtreq))) { 109 u.u_error = EFAULT; 110 goto bad; 111 } 112 err = rtrequest(req, &rq); 113 bad: 114 splx(x); 115 return (err); 116 } 117 118 /* 119 * Carry out a user request to modify the data base. 120 */ 121 rtrequest(req, new) 122 int req; 123 register struct rtentry *new; 124 { 125 register struct rtentry *rt; 126 register struct mbuf *m, **mprev; 127 struct sockaddr *sa = &new->rt_dst; 128 struct afhash h; 129 int af = sa->sa_family; 130 131 (*afswitch[af].af_hash)(sa, &h); 132 mprev = &routehash[h.afh_hosthash % RTHASHSIZ]; 133 key = h.afh_hostkey; 134 doinghost = 1; 135 again: 136 for (; m = *mprev; mprev = &m->m_next) { 137 rt = mtod(m, struct rtentry *); 138 if (rt->rt_key != key) 139 continue; 140 if (doinghost) { 141 if (!equal(&rt->rt_dst, dst)) 142 continue; 143 } else { 144 if (rt->rt_dst.sa_family != af) 145 continue; 146 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, sa) == 0) 147 continue; 148 } 149 break; 150 } 151 if (m == 0 && doinghost) { 152 doinghost = 0; 153 mprev = &routehash[h.afh_nethash % RTHASHSIZ]; 154 key = h.afh_netkey; 155 goto again; 156 } 157 158 if (m == 0 && req != SIOCADDRT) 159 return (ESEARCH); 160 switch (req) { 161 162 case SIOCDELRT: 163 rt->rt_flags &= ~RTF_UP; 164 if (rt->rt_refcnt > 0) /* should we notify protocols? */ 165 break; 166 *mprev = m_free(m); 167 break; 168 169 case SIOCCHGRT: 170 rt->rt_flags = new->rt_flags; 171 if (rt->rt_refcnt > 0) 172 return (EINUSE); 173 if (!equal(&rt->rt_gateway, &new->rt_gateway)) 174 goto newneighbor; 175 break; 176 177 case SIOCADDRT: 178 m = m_getclr(M_DONTWAIT); 179 if (m == 0) 180 return (ENOBUFS); 181 m->m_off = MMINOFF; 182 *mprev = m; 183 rt = mtod(m, struct rtentry *); 184 *rt = *new; 185 rt->rt_key = h.afh_nethash | h.afh_hosthash; 186 newneighbor: 187 rt->rt_ifp = if_ifonnetof(&new->rt_gateway); 188 if (rt->rt_ifp == 0) 189 rt->rt_flags &= ~RTF_UP; 190 rt->rt_refcnt = 0; 191 break; 192 } 193 return (0); 194 } 195