1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)rtsock.c 7.1 (Berkeley) 12/13/88 18 */ 19 20 #ifndef RTF_UP 21 #include "param.h" 22 #include "mbuf.h" 23 #include "dir.h" 24 #include "user.h" 25 #include "proc.h" 26 #include "socket.h" 27 #include "socketvar.h" 28 #include "domain.h" 29 #include "protosw.h" 30 #include "errno.h" 31 32 #include "af.h" 33 #include "route.h" 34 #include "raw_cb.h" 35 36 #include "../machine/mtpr.h" 37 #endif 38 39 /*ARGSUSED*/ 40 route_usrreq(so, req, m, nam, rights, control) 41 register struct socket *so; 42 int req; 43 struct mbuf *m, *nam, *rights, *control; 44 { 45 register int error = 0; 46 register struct rawcb *rp = sotorawcb(so); 47 if (req == PRU_DETACH && rp) { 48 int af = rp->rcb_proto.sp_protocol; 49 if (af == AF_INET) 50 route_cb.ip_count--; 51 else if (af == AF_NS) 52 route_cb.ns_count--; 53 #ifdef ISO 54 else if (af == AF_ISO) 55 route_cb.iso_count--; 56 #endif 57 route_cb.any_count--; 58 } 59 error = raw_usrreq(so, req, m, nam, rights, control); 60 rp = sotorawcb(so); 61 if (error == 0 && req == PRU_ATTACH && rp) { 62 int af = rp->rcb_proto.sp_protocol; 63 if (af == AF_INET) 64 route_cb.ip_count++; 65 else if (af == AF_NS) 66 route_cb.ns_count++; 67 #ifdef ISO 68 else if (af == AF_ISO) 69 route_cb.iso_count++; 70 #endif 71 rp->rcb_flags |= RAW_FADDR; 72 route_cb.any_count++; 73 soisconnected(so); 74 } 75 return (error); 76 } 77 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 78 79 struct sockaddr route_dst = { 0, PF_ROUTE, }; 80 struct sockaddr route_src = { 0, PF_ROUTE, }; 81 struct sockproto route_proto = { PF_ROUTE, }; 82 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 mbuf *m0 = m; 90 struct rtentry *saved_nrt; 91 struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *author; 92 struct rt_metrics *rmm = 0; 93 struct radix_node_head *rnh; 94 struct radix_node *rn; 95 caddr_t cp = 0; 96 int len, error = 0, s; 97 98 #define FLUSH(e) { error = e; goto flush;} 99 if (m == 0 || (m = m_pullup(m, sizeof(long))) == 0) 100 FLUSH(ENOBUFS); 101 if ((m->m_flags & M_PKTHDR) == 0) 102 return (EOPNOTSUPP); 103 len = m->m_pkthdr.len; 104 rtm = mtod(m, struct rt_msghdr *); 105 if (len < rtm->rtm_msglen) 106 FLUSH(EINVAL); 107 R_Malloc(rtm, struct rt_msghdr *, len); 108 if (rtm == 0) 109 FLUSH(ENOBUFS); 110 m_copydata(m, 0, len, (caddr_t)rtm); 111 if (rtm->rtm_version != 1) 112 FLUSH(EPROTONOSUPPORT); 113 rtm->rtm_pid = u.u_procp->p_pid; 114 cp = (caddr_t) (rtm + 1); 115 #ifdef notyet 116 switch (rtm->rtm_type) { 117 118 case RTM_ADD: case RTM_CHANGE: case RTM_GET: 119 rmm = (struct rt_metrics *)cp ; 120 cp = (caddr_t) (rmm + 1); 121 } 122 #endif 123 if (rtm->rtm_count > 0) { 124 dst = (struct sockaddr *)cp; 125 cp += ROUNDUP(dst->sa_len); 126 } 127 if (rtm->rtm_count > 1) { 128 gate = (struct sockaddr *)cp; 129 cp += ROUNDUP(gate->sa_len); 130 } 131 if (rtm->rtm_count > 2) { 132 netmask = (struct sockaddr *)cp; 133 cp += ROUNDUP(netmask->sa_len); 134 } 135 if (rtm->rtm_count > 3) { 136 author = (struct sockaddr *)cp; 137 } 138 switch (rtm->rtm_type) { 139 case RTM_ADD: 140 error = rtrequest(RTM_ADD, dst, gate, netmask, 141 rtm->rtm_flags, &saved_nrt); 142 /* XXX -- add metrics !!! */ 143 break; 144 145 case RTM_DELETE: 146 error = rtrequest(RTM_DELETE, dst, gate, netmask, 147 rtm->rtm_flags, 0); 148 break; 149 150 case RTM_GET: 151 case RTM_CHANGE: 152 case RTM_LOCK: 153 rt = rtalloc1(dst, 0); 154 if (rt == 0) 155 FLUSH(ESRCH); 156 switch(rtm->rtm_type) { 157 struct sockaddr *outmask; 158 159 case RTM_GET: 160 netmask = rt_mask(rt); 161 len = sizeof(*rtm) + ROUNDUP(rt_key(rt)->sa_len) 162 + ROUNDUP(rt->rt_gateway->sa_len); 163 if (netmask) 164 len + netmask->sa_len; 165 if (len > rtm->rtm_msglen) { 166 struct rt_msghdr *new_rtm; 167 R_Malloc(new_rtm, struct rt_msghdr *, len); 168 if (new_rtm == 0) 169 FLUSH(ENOBUFS); 170 Bcopy(rtm, new_rtm, rtm->rtm_msglen); 171 Free(rtm); rtm = new_rtm; 172 gate = (struct sockaddr *) 173 (ROUNDUP(rt->rt_gateway->sa_len) 174 + (char *)dst); 175 Bcopy(&rt->rt_gateway, gate, 176 rt->rt_gateway->sa_len); 177 rtm->rtm_flags = rt->rt_flags; 178 rtm->rtm_count = 2; 179 if (netmask) { 180 outmask = (struct sockaddr *) 181 (ROUNDUP(netmask->sa_len)+(char *)gate); 182 Bcopy(netmask, outmask, netmask->sa_len); 183 rtm->rtm_count = 3; 184 } 185 } 186 break; 187 188 case RTM_CHANGE: 189 if (gate->sa_len > (len = rt->rt_gateway->sa_len)) 190 FLUSH(EDQUOT); 191 if (gate->sa_family != rt->rt_gateway->sa_family) 192 FLUSH(EADDRINUSE); 193 Bcopy(gate, rt->rt_gateway, len); 194 rt->rt_gateway->sa_len = len; 195 196 #ifdef notdef 197 #define metric(f, e) if (rtm->rtm_inits & (f)) rt->rt_m.e = rtm->e; 198 metric(RTM_RPIPE, rtm_recvpipe); 199 metric(RTM_SPIPE, rtm_sendpipe); 200 metric(RTM_SSTHRESH, rtm_ssthresh); 201 metric(RTM_RTT, rtm_rtt); 202 metric(RTM_RTTVAR, rtm_rttvar); 203 metric(RTM_HOPCOUNT, rtm_hopcount); 204 metric(RTM_MTU, rtm_mtu); 205 /* 206 * Fall into 207 */ 208 case RTM_LOCKS: 209 rt->rt_locks |= (rtm->rtm_inits & rtm->rtm_locks); 210 rt->rt_locks &= ~(rtm->rtm_inits); 211 break; 212 #endif 213 } 214 goto cleanup; 215 216 default: 217 FLUSH(EOPNOTSUPP); 218 } 219 220 flush: 221 if (rtm) { 222 if (error) 223 rtm->rtm_errno = error; 224 else 225 rtm->rtm_flags |= RTF_DONE; 226 } 227 cleanup: 228 if (rt) 229 rtfree(rt); 230 cp = (caddr_t)rtm; 231 m_copyback(m = m0, 0, len, cp); 232 /*if (m->m_pkthdr.len != len) { 233 m_freem(m); 234 return (error); 235 } */ 236 route_proto.sp_protocol = dst->sa_family; 237 raw_input(m0, &route_proto, &route_src, &route_dst); 238 return (error); 239 } 240 241 /* 242 * Copy data from a buffer back into the indicated mbuf chain, 243 * starting "off" bytes from the beginning, extending the mbuf 244 * chain if necessary. 245 */ 246 m_copyback(m0, off, len, cp) 247 struct mbuf *m0; 248 register int off; 249 register int len; 250 caddr_t cp; 251 252 { 253 register int mlen; 254 register struct mbuf *m = m0, *n; 255 int totlen = 0; 256 257 if (m0 == 0) 258 return; 259 while (off >= (mlen = m->m_len)) { 260 off -= mlen; 261 totlen += mlen; 262 if (m->m_next == 0) { 263 n = m_getclr(M_DONTWAIT, m->m_type); 264 if (n == 0) 265 goto out; 266 n->m_len = min(MLEN, len + off); 267 m->m_next = n; 268 } 269 m = m->m_next; 270 } 271 while (len > 0) { 272 mlen = min (m->m_len - off, len); 273 bcopy(cp, off + mtod(m, caddr_t), mlen); 274 cp += mlen; 275 len -= mlen; 276 mlen += off; 277 off = 0; 278 totlen += mlen; 279 if (len == 0) 280 break; 281 if (m->m_next == 0) { 282 n = m_get(M_DONTWAIT, m->m_type); 283 if (n == 0) 284 break; 285 n->m_len = min(MLEN, len); 286 m->m_next = n; 287 } 288 m = m->m_next; 289 } 290 out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 291 m->m_pkthdr.len = totlen; 292 } 293 294 /* 295 * The miss message and losing message are very similar. 296 */ 297 298 rt_missmsg(type, dst, gate, mask, src, flags) 299 register struct sockaddr *dst; 300 struct sockaddr *gate, *mask, *src; 301 { 302 register struct rt_msghdr *rtm; 303 register struct mbuf *m; 304 int dlen = ROUNDUP(dst->sa_len); 305 int len = dlen + sizeof(*rtm); 306 caddr_t cp = (caddr_t)dst; 307 308 if (route_cb.any_count == 0) 309 return; 310 m = m_gethdr(M_DONTWAIT, MT_DATA); 311 if (m == 0) 312 return; 313 m->m_pkthdr.len = m->m_len = min(len, MHLEN); 314 m->m_pkthdr.rcvif = 0; 315 rtm = mtod(m, struct rt_msghdr *); 316 bzero((caddr_t)rtm, sizeof(*rtm)); /*XXX assumes sizeof(*rtm) < MHLEN*/ 317 rtm->rtm_flags = RTF_DONE | flags; 318 rtm->rtm_msglen = len; 319 rtm->rtm_version = 1; 320 rtm->rtm_type = type; 321 rtm->rtm_count = 1; 322 if (type == RTM_OLDADD || type == RTM_OLDDEL) { 323 int error = (int) src; 324 src = (struct sockaddr *)0; /* XXXXXXX -- I admit. (KLS) */ 325 rtm->rtm_pid = u.u_procp->p_pid; 326 rtm->rtm_errno = error; 327 if (error) 328 rtm->rtm_flags &= ~RTF_DONE; 329 } 330 m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst); 331 if (gate) { 332 dlen = ROUNDUP(gate->sa_len); 333 m_copyback(m, len , dlen, (caddr_t)gate); 334 len += dlen; 335 rtm->rtm_count++; 336 } 337 if (mask) { 338 dlen = ROUNDUP(mask->sa_len); 339 m_copyback(m, len , dlen, (caddr_t)mask); 340 len += dlen; 341 rtm->rtm_count++; 342 } 343 if (src) { 344 dlen = ROUNDUP(src->sa_len); 345 m_copyback(m, len , dlen, (caddr_t)src); 346 len += dlen; 347 rtm->rtm_count++; 348 } 349 if (m->m_pkthdr.len != len) { 350 m_freem(m); 351 return; 352 } 353 rtm->rtm_msglen = len; 354 route_proto.sp_protocol = dst->sa_family; 355 raw_input(m, &route_proto, &route_src, &route_dst); 356 } 357 358 /* 359 * Definitions of protocols supported in the ROUTE domain. 360 */ 361 362 int route_output(); 363 int raw_init(),raw_usrreq(),raw_input(),raw_ctlinput(); 364 extern struct domain routedomain; /* or at least forward */ 365 366 struct protosw routesw[] = { 367 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, 368 raw_input, route_output, raw_ctlinput, 0, 369 route_usrreq, 370 raw_init, 0, 0, 0, 371 }, 372 { 0, 0, 0, 0, 373 raw_input, 0, raw_ctlinput, 0, 374 raw_usrreq, 375 raw_init, 0, 0, 0, 376 } 377 }; 378 379 int unp_externalize(), unp_dispose(); 380 381 struct domain routedomain = 382 { PF_ROUTE, "route", 0, 0, 0, 383 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; 384