1 /* route.c 4.4 82/03/30 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/protosw.h" 7 #include "../h/socket.h" 8 #include "../h/ioctl.h" 9 #include "../net/in.h" 10 #include "../net/in_systm.h" 11 #include "../net/if.h" 12 #include "../net/af.h" 13 #include "../net/route.h" 14 #include <errno.h> 15 16 /* 17 * Packet routing routines. 18 */ 19 20 rtalloc(ro) 21 register struct route *ro; 22 { 23 register struct rtentry *rt, *rtmin; 24 register struct mbuf *m; 25 register int hash; 26 struct afhash h; 27 struct sockaddr *dst = &ro->ro_dst; 28 int af = dst->sa_family, doinghost; 29 30 COUNT(RTALLOC); 31 if (ro->ro_rt && ro->ro_rt->rt_ifp) /* XXX */ 32 return; 33 (*afswitch[af].af_hash)(dst, &h); 34 hash = h.afh_hosthash; 35 rtmin = 0, doinghost = 1; 36 again: 37 m = routehash[hash % RTHASHSIZ]; 38 for (; m; m = m->m_next) { 39 rt = mtod(m, struct rtentry *); 40 if (rt->rt_hash[doinghost] != hash) 41 continue; 42 if (doinghost) { 43 #define equal(a1, a2) \ 44 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0) 45 if (!equal(&rt->rt_dst, dst)) 46 continue; 47 } else { 48 if (rt->rt_dst.sa_family != af) 49 continue; 50 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, dst) == 0) 51 continue; 52 } 53 if (rtmin == 0 || rt->rt_use < rtmin->rt_use) 54 rtmin = rt; 55 } 56 if (rtmin) { 57 ro->ro_rt = rt; 58 rt->rt_refcnt++; 59 return; 60 } 61 if (doinghost) { 62 doinghost = 0; 63 hash = h.afh_nethash; 64 goto again; 65 } 66 ro->ro_rt = 0; 67 return; 68 } 69 70 rtfree(rt) 71 register struct rtentry *rt; 72 { 73 74 COUNT(FREEROUTE); 75 if (rt == 0) 76 panic("freeroute"); 77 rt->rt_refcnt--; 78 /* on refcnt == 0 reclaim? notify someone? */ 79 } 80 81 /* 82 * Carry out a request to change the routing table. Called by 83 * interfaces at boot time to make their ``local routes'' known 84 * and for ioctl's. 85 */ 86 rtrequest(req, new) 87 int req; 88 register struct rtentry *new; 89 { 90 register struct rtentry *rt; 91 register struct mbuf *m, **mprev; 92 register int hash; 93 struct sockaddr *sa = &new->rt_dst; 94 struct afhash h; 95 int af = sa->sa_family, doinghost, s, error = 0; 96 97 COUNT(RTREQUEST); 98 (*afswitch[af].af_hash)(sa, &h); 99 hash = h.afh_hosthash; 100 doinghost = 1; 101 s = splimp(); 102 again: 103 mprev = &routehash[hash % RTHASHSIZ]; 104 for (; m = *mprev; mprev = &m->m_next) { 105 rt = mtod(m, struct rtentry *); 106 if (rt->rt_hash[doinghost] != hash) 107 continue; 108 if (doinghost) { 109 if (!equal(&rt->rt_dst, &new->rt_dst)) 110 continue; 111 } else { 112 if (rt->rt_dst.sa_family != af) 113 continue; 114 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, sa) == 0) 115 continue; 116 } 117 /* require full match on deletions */ 118 if (req == SIOCDELRT && 119 !equal(&rt->rt_gateway, &new->rt_gateway)) 120 continue; 121 /* don't keep multiple identical entries */ 122 if (req == SIOCADDRT && 123 equal(&rt->rt_gateway, &new->rt_gateway)) { 124 error = EEXIST; 125 goto bad; 126 } 127 break; 128 } 129 if (m == 0 && doinghost) { 130 doinghost = 0; 131 hash = h.afh_nethash; 132 goto again; 133 } 134 if (m == 0 && req != SIOCADDRT) { 135 error = ESRCH; 136 goto bad; 137 } 138 switch (req) { 139 140 case SIOCDELRT: 141 rt->rt_flags &= ~RTF_UP; 142 if (rt->rt_refcnt > 0) /* should we notify protocols? */ 143 error = EBUSY; 144 else 145 *mprev = m_free(m); 146 break; 147 148 case SIOCCHGRT: 149 rt->rt_flags = new->rt_flags; 150 if (rt->rt_refcnt > 0) 151 error = EBUSY; 152 else if (!equal(&rt->rt_gateway, &new->rt_gateway)) 153 goto newneighbor; 154 break; 155 156 case SIOCADDRT: 157 m = m_get(M_DONTWAIT); 158 if (m == 0) { 159 error = ENOBUFS; 160 break; 161 } 162 m->m_off = MMINOFF; 163 m->m_len = sizeof (struct rtentry); 164 *mprev = m; 165 rt = mtod(m, struct rtentry *); 166 *rt = *new; 167 rt->rt_hash[0] = h.afh_nethash; 168 rt->rt_hash[1] = h.afh_hosthash; 169 newneighbor: 170 rt->rt_ifp = if_ifwithnet(&new->rt_gateway); 171 if (rt->rt_ifp == 0) 172 rt->rt_flags &= ~RTF_UP; 173 rt->rt_use = 0; 174 rt->rt_refcnt = 0; 175 break; 176 } 177 bad: 178 splx(s); 179 return (error); 180 } 181 182 /* 183 * Set up a routing table entry, normally 184 * for an interface. 185 */ 186 rtinit(dst, gateway, flags) 187 struct sockaddr *dst, *gateway; 188 int flags; 189 { 190 struct rtentry route; 191 struct route ro; 192 193 route.rt_dst = *dst; 194 route.rt_gateway = *gateway; 195 route.rt_flags = flags; 196 route.rt_use = 0; 197 (void) rtrequest(SIOCADDRT, &route); 198 ro.ro_rt = 0; 199 ro.ro_dst = *dst; 200 rtalloc(&ro); 201 } 202