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