1 /* route.c 4.3 82/03/29 */ 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 /* 21 * With much ado about nothing... 22 * route the cars that climb halfway to the stars... 23 */ 24 allocroute(ro) 25 register struct route *ro; 26 { 27 register struct rtentry *rt, *rtmin; 28 register struct mbuf *m; 29 register int key; 30 struct afhash h; 31 struct sockaddr *dst = &ro->ro_dst; 32 int af = dst->sa_family, doinghost; 33 34 COUNT(ALLOCROUTE); 35 if (ro->ro_rt && ro->ro_rt->rt_ifp) /* can't happen */ 36 return; 37 (*afswitch[af].af_hash)(dst, &h); 38 m = routehash[h.afh_hosthash % RTHASHSIZ]; 39 key = h.afh_hostkey; 40 rtmin = 0, doinghost = 1; 41 again: 42 for (; m; m = m->m_next) { 43 rt = mtod(m, struct rtentry *); 44 if (rt->rt_key != key) 45 continue; 46 if (doinghost) { 47 #define equal(a1, a2) \ 48 (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof(struct sockaddr)) == 0) 49 if (!equal(&rt->rt_dst, dst)) 50 continue; 51 } else { 52 if (rt->rt_dst.sa_family != af) 53 continue; 54 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, dst) == 0) 55 continue; 56 } 57 if (rtmin == 0 || rt->rt_use < rtmin->rt_use) 58 rtmin = rt; 59 } 60 if (rtmin) { 61 ro->ro_dst = rt->rt_dst; 62 ro->ro_rt = rt; 63 rt->rt_refcnt++; 64 return (rt->rt_flags & RTF_DIRECT); 65 } 66 if (doinghost) { 67 doinghost = 0; 68 m = routehash[h.afh_nethash % RTHASHSIZ]; 69 key = h.afh_netkey; 70 goto again; 71 } 72 ro->ro_rt = 0; 73 return (0); 74 } 75 76 freeroute(rt) 77 register struct rtentry *rt; 78 { 79 COUNT(FREEROUTE); 80 if (rt == 0) 81 panic("freeroute"); 82 rt->rt_refcnt--; 83 /* on refcnt == 0 reclaim? notify someone? */ 84 } 85 86 #ifdef notdef 87 struct rtentry * 88 reroute(sa) 89 register struct sockaddr *sa; 90 { 91 register struct rtentry *rt; 92 register struct mbuf *m; 93 register int key; 94 struct afhash h; 95 96 COUNT(REROUTE); 97 (*afswitch[sa->sa_family].af_hash)(sa, &h); 98 m = routehash[h.afh_hosthash]; 99 key = h.afh_hostkey; 100 for (; m; m = m->m_next) { 101 rt = mtod(m, struct rtentry *); 102 if (rt->rt_key != key) 103 continue; 104 if (equal(&rt->rt_gateway, sa)) 105 return (rt); 106 } 107 return (0); 108 } 109 #endif 110 111 /* 112 * Carry out a request to change the routing table. Called by 113 * interfaces at boot time to make their ``local routes'' known 114 * and for ioctl's. 115 */ 116 rtrequest(req, new) 117 int req; 118 register struct rtentry *new; 119 { 120 register struct rtentry *rt; 121 register struct mbuf *m, **mprev; 122 register int key; 123 struct sockaddr *sa = &new->rt_dst; 124 struct afhash h; 125 int af = sa->sa_family, doinghost, s, error = 0; 126 127 COUNT(RTREQUEST); 128 (*afswitch[af].af_hash)(sa, &h); 129 mprev = &routehash[h.afh_hosthash % RTHASHSIZ]; 130 key = h.afh_hostkey; 131 doinghost = 1; 132 s = splimp(); 133 again: 134 for (; m = *mprev; mprev = &m->m_next) { 135 rt = mtod(m, struct rtentry *); 136 if (rt->rt_key != key) 137 continue; 138 if (doinghost) { 139 if (!equal(&rt->rt_dst, &new->rt_dst)) 140 continue; 141 } else { 142 if (rt->rt_dst.sa_family != af) 143 continue; 144 if ((*afswitch[af].af_netmatch)(&rt->rt_dst, sa) == 0) 145 continue; 146 } 147 /* require full match on deletions */ 148 if (req == SIOCDELRT && 149 !equal(&rt->rt_gateway, &new->rt_gateway)) 150 continue; 151 /* don't keep multiple identical entries */ 152 if (req == SIOCADDRT && 153 equal(&rt->rt_gateway, &new->rt_gateway)) { 154 error = EEXIST; 155 goto bad; 156 } 157 break; 158 } 159 if (m == 0 && doinghost) { 160 doinghost = 0; 161 mprev = &routehash[h.afh_nethash % RTHASHSIZ]; 162 key = h.afh_netkey; 163 goto again; 164 } 165 166 if (m == 0 && req != SIOCADDRT) { 167 error = ESRCH; 168 goto bad; 169 } 170 switch (req) { 171 172 case SIOCDELRT: 173 rt->rt_flags &= ~RTF_UP; 174 if (rt->rt_refcnt > 0) /* should we notify protocols? */ 175 error = EBUSY; 176 else 177 *mprev = m_free(m); 178 break; 179 180 case SIOCCHGRT: 181 rt->rt_flags = new->rt_flags; 182 if (rt->rt_refcnt > 0) 183 error = EBUSY; 184 else if (!equal(&rt->rt_gateway, &new->rt_gateway)) 185 goto newneighbor; 186 break; 187 188 case SIOCADDRT: 189 m = m_getclr(M_DONTWAIT); 190 if (m == 0) { 191 error = ENOBUFS; 192 break; 193 } 194 m->m_off = MMINOFF; 195 *mprev = m; 196 rt = mtod(m, struct rtentry *); 197 *rt = *new; 198 rt->rt_key = h.afh_nethash | h.afh_hosthash; 199 newneighbor: 200 rt->rt_ifp = if_ifonnetof(&new->rt_gateway); 201 if (rt->rt_ifp == 0) 202 rt->rt_flags &= ~RTF_UP; 203 rt->rt_refcnt = 0; 204 break; 205 } 206 bad: 207 splx(s); 208 return (error); 209 } 210