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