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