1 /* 2 * Copyright (c) 1982, 1986 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 this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 * 12 * @(#)ip_output.c 7.7 (Berkeley) 12/07/87 13 */ 14 15 #include "param.h" 16 #include "mbuf.h" 17 #include "errno.h" 18 #include "protosw.h" 19 #include "socket.h" 20 #include "socketvar.h" 21 22 #include "../net/if.h" 23 #include "../net/route.h" 24 25 #include "in.h" 26 #include "in_pcb.h" 27 #include "in_systm.h" 28 #include "in_var.h" 29 #include "ip.h" 30 #include "ip_var.h" 31 32 #ifdef vax 33 #include "../machine/mtpr.h" 34 #endif 35 36 struct mbuf *ip_insertoptions(); 37 38 /* 39 * IP output. The packet in mbuf chain m contains a skeletal IP 40 * header (with len, off, ttl, proto, tos, src, dst). 41 * The mbuf chain containing the packet will be freed. 42 * The mbuf opt, if present, will not be freed. 43 */ 44 ip_output(m, opt, ro, flags) 45 struct mbuf *m; 46 struct mbuf *opt; 47 struct route *ro; 48 int flags; 49 { 50 register struct ip *ip; 51 register struct ifnet *ifp; 52 int len, hlen = sizeof (struct ip), off, error = 0; 53 struct route iproute; 54 struct sockaddr_in *dst; 55 56 if (opt) 57 m = ip_insertoptions(m, opt, &hlen); 58 ip = mtod(m, struct ip *); 59 /* 60 * Fill in IP header. 61 */ 62 if ((flags & IP_FORWARDING) == 0) { 63 ip->ip_v = IPVERSION; 64 ip->ip_off &= IP_DF; 65 ip->ip_id = htons(ip_id++); 66 ip->ip_hl = hlen >> 2; 67 } else 68 hlen = ip->ip_hl << 2; 69 70 /* 71 * Route packet. 72 */ 73 if (ro == 0) { 74 ro = &iproute; 75 bzero((caddr_t)ro, sizeof (*ro)); 76 } 77 dst = (struct sockaddr_in *)&ro->ro_dst; 78 /* 79 * If there is a cached route, 80 * check that it is to the same destination 81 * and is still up. If not, free it and try again. 82 */ 83 if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || 84 dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { 85 RTFREE(ro->ro_rt); 86 ro->ro_rt = (struct rtentry *)0; 87 } 88 if (ro->ro_rt == 0) { 89 dst->sin_family = AF_INET; 90 dst->sin_addr = ip->ip_dst; 91 } 92 /* 93 * If routing to interface only, 94 * short circuit routing lookup. 95 */ 96 if (flags & IP_ROUTETOIF) { 97 struct in_ifaddr *ia; 98 99 ia = (struct in_ifaddr *)ifa_ifwithdstaddr(dst); 100 if (ia == 0) 101 ia = in_iaonnetof(in_netof(ip->ip_dst)); 102 if (ia == 0) { 103 error = ENETUNREACH; 104 goto bad; 105 } 106 ifp = ia->ia_ifp; 107 } else { 108 if (ro->ro_rt == 0) 109 rtalloc(ro); 110 if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { 111 if (in_localaddr(ip->ip_dst)) 112 error = EHOSTUNREACH; 113 else 114 error = ENETUNREACH; 115 goto bad; 116 } 117 ro->ro_rt->rt_use++; 118 if (ro->ro_rt->rt_flags & RTF_GATEWAY) 119 dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; 120 } 121 #ifndef notdef 122 /* 123 * If source address not specified yet, use address 124 * of outgoing interface. 125 */ 126 if (ip->ip_src.s_addr == INADDR_ANY) { 127 register struct in_ifaddr *ia; 128 129 for (ia = in_ifaddr; ia; ia = ia->ia_next) 130 if (ia->ia_ifp == ifp) { 131 ip->ip_src = IA_SIN(ia)->sin_addr; 132 break; 133 } 134 } 135 #endif 136 /* 137 * Look for broadcast address and 138 * and verify user is allowed to send 139 * such a packet. 140 */ 141 if (in_broadcast(dst->sin_addr)) { 142 if ((ifp->if_flags & IFF_BROADCAST) == 0) { 143 error = EADDRNOTAVAIL; 144 goto bad; 145 } 146 if ((flags & IP_ALLOWBROADCAST) == 0) { 147 error = EACCES; 148 goto bad; 149 } 150 /* don't allow broadcast messages to be fragmented */ 151 if (ip->ip_len > ifp->if_mtu) { 152 error = EMSGSIZE; 153 goto bad; 154 } 155 } 156 157 /* 158 * If small enough for interface, can just send directly. 159 */ 160 if (ip->ip_len <= ifp->if_mtu) { 161 ip->ip_len = htons((u_short)ip->ip_len); 162 ip->ip_off = htons((u_short)ip->ip_off); 163 ip->ip_sum = 0; 164 ip->ip_sum = in_cksum(m, hlen); 165 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); 166 goto done; 167 } 168 169 /* 170 * Too large for interface; fragment if possible. 171 * Must be able to put at least 8 bytes per fragment. 172 */ 173 if (ip->ip_off & IP_DF) { 174 error = EMSGSIZE; 175 goto bad; 176 } 177 len = (ifp->if_mtu - hlen) &~ 7; 178 if (len < 8) { 179 error = EMSGSIZE; 180 goto bad; 181 } 182 183 /* 184 * Discard IP header from logical mbuf for m_copy's sake. 185 * Loop through length of segment, make a copy of each 186 * part and output. 187 */ 188 m->m_len -= sizeof (struct ip); 189 m->m_off += sizeof (struct ip); 190 for (off = 0; off < ip->ip_len-hlen; off += len) { 191 struct mbuf *mh = m_get(M_DONTWAIT, MT_HEADER); 192 struct ip *mhip; 193 194 if (mh == 0) { 195 error = ENOBUFS; 196 goto bad; 197 } 198 mh->m_off = MMAXOFF - hlen; 199 mhip = mtod(mh, struct ip *); 200 *mhip = *ip; 201 if (hlen > sizeof (struct ip)) { 202 int olen = ip_optcopy(ip, mhip, off); 203 mh->m_len = sizeof (struct ip) + olen; 204 } else 205 mh->m_len = sizeof (struct ip); 206 mhip->ip_off = (off >> 3) + (ip->ip_off & ~IP_MF); 207 if (ip->ip_off & IP_MF) 208 mhip->ip_off |= IP_MF; 209 if (off + len >= ip->ip_len-hlen) 210 len = mhip->ip_len = ip->ip_len - hlen - off; 211 else { 212 mhip->ip_len = len; 213 mhip->ip_off |= IP_MF; 214 } 215 mhip->ip_len += sizeof (struct ip); 216 mhip->ip_len = htons((u_short)mhip->ip_len); 217 mh->m_next = m_copy(m, off, len); 218 if (mh->m_next == 0) { 219 (void) m_free(mh); 220 error = ENOBUFS; /* ??? */ 221 goto bad; 222 } 223 mhip->ip_off = htons((u_short)mhip->ip_off); 224 mhip->ip_sum = 0; 225 mhip->ip_sum = in_cksum(mh, hlen); 226 if (error = (*ifp->if_output)(ifp, mh, (struct sockaddr *)dst)) 227 break; 228 } 229 bad: 230 m_freem(m); 231 done: 232 if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) 233 RTFREE(ro->ro_rt); 234 return (error); 235 } 236 237 /* 238 * Insert IP options into preformed packet. 239 * Adjust IP destination as required for IP source routing, 240 * as indicated by a non-zero in_addr at the start of the options. 241 */ 242 struct mbuf * 243 ip_insertoptions(m, opt, phlen) 244 register struct mbuf *m; 245 struct mbuf *opt; 246 int *phlen; 247 { 248 register struct ipoption *p = mtod(opt, struct ipoption *); 249 struct mbuf *n; 250 register struct ip *ip = mtod(m, struct ip *); 251 unsigned optlen; 252 253 optlen = opt->m_len - sizeof(p->ipopt_dst); 254 if (p->ipopt_dst.s_addr) 255 ip->ip_dst = p->ipopt_dst; 256 if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) { 257 MGET(n, M_DONTWAIT, MT_HEADER); 258 if (n == 0) 259 return (m); 260 m->m_len -= sizeof(struct ip); 261 m->m_off += sizeof(struct ip); 262 n->m_next = m; 263 m = n; 264 m->m_off = MMAXOFF - sizeof(struct ip) - optlen; 265 m->m_len = optlen + sizeof(struct ip); 266 bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 267 } else { 268 m->m_off -= optlen; 269 m->m_len += optlen; 270 ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); 271 } 272 ip = mtod(m, struct ip *); 273 bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); 274 *phlen = sizeof(struct ip) + optlen; 275 ip->ip_len += optlen; 276 return (m); 277 } 278 279 /* 280 * Copy options from ip to jp. 281 * If off is 0 all options are copied 282 * otherwise copy selectively. 283 */ 284 ip_optcopy(ip, jp, off) 285 struct ip *ip, *jp; 286 int off; 287 { 288 register u_char *cp, *dp; 289 int opt, optlen, cnt; 290 291 cp = (u_char *)(ip + 1); 292 dp = (u_char *)(jp + 1); 293 cnt = (ip->ip_hl << 2) - sizeof (struct ip); 294 for (; cnt > 0; cnt -= optlen, cp += optlen) { 295 opt = cp[0]; 296 if (opt == IPOPT_EOL) 297 break; 298 if (opt == IPOPT_NOP) 299 optlen = 1; 300 else 301 optlen = cp[IPOPT_OLEN]; 302 if (optlen > cnt) /* XXX */ 303 optlen = cnt; /* XXX */ 304 if (off == 0 || IPOPT_COPIED(opt)) { 305 bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); 306 dp += optlen; 307 } 308 } 309 for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 310 *dp++ = IPOPT_EOL; 311 return (optlen); 312 } 313 314 /* 315 * IP socket option processing. 316 */ 317 ip_ctloutput(op, so, level, optname, m) 318 int op; 319 struct socket *so; 320 int level, optname; 321 struct mbuf **m; 322 { 323 int error = 0; 324 struct inpcb *inp = sotoinpcb(so); 325 326 if (level != IPPROTO_IP) 327 error = EINVAL; 328 else switch (op) { 329 330 case PRCO_SETOPT: 331 switch (optname) { 332 case IP_OPTIONS: 333 return (ip_pcbopts(&inp->inp_options, *m)); 334 335 default: 336 error = EINVAL; 337 break; 338 } 339 break; 340 341 case PRCO_GETOPT: 342 switch (optname) { 343 case IP_OPTIONS: 344 *m = m_get(M_WAIT, MT_SOOPTS); 345 if (inp->inp_options) { 346 (*m)->m_off = inp->inp_options->m_off; 347 (*m)->m_len = inp->inp_options->m_len; 348 bcopy(mtod(inp->inp_options, caddr_t), 349 mtod(*m, caddr_t), (unsigned)(*m)->m_len); 350 } else 351 (*m)->m_len = 0; 352 break; 353 default: 354 error = EINVAL; 355 break; 356 } 357 break; 358 } 359 if (op == PRCO_SETOPT && *m) 360 (void)m_free(*m); 361 return (error); 362 } 363 364 /* 365 * Set up IP options in pcb for insertion in output packets. 366 * Store in mbuf with pointer in pcbopt, adding pseudo-option 367 * with destination address if source routed. 368 */ 369 ip_pcbopts(pcbopt, m) 370 struct mbuf **pcbopt; 371 register struct mbuf *m; 372 { 373 register cnt, optlen; 374 register u_char *cp; 375 u_char opt; 376 377 /* turn off any old options */ 378 if (*pcbopt) 379 (void)m_free(*pcbopt); 380 *pcbopt = 0; 381 if (m == (struct mbuf *)0 || m->m_len == 0) { 382 /* 383 * Only turning off any previous options. 384 */ 385 if (m) 386 (void)m_free(m); 387 return (0); 388 } 389 390 #ifndef vax 391 if (m->m_len % sizeof(long)) 392 goto bad; 393 #endif 394 /* 395 * IP first-hop destination address will be stored before 396 * actual options; move other options back 397 * and clear it when none present. 398 */ 399 #if MAX_IPOPTLEN >= MMAXOFF - MMINOFF 400 if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN) 401 goto bad; 402 #else 403 if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF) 404 goto bad; 405 #endif 406 cnt = m->m_len; 407 m->m_len += sizeof(struct in_addr); 408 cp = mtod(m, u_char *) + sizeof(struct in_addr); 409 ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); 410 bzero(mtod(m, caddr_t), sizeof(struct in_addr)); 411 412 for (; cnt > 0; cnt -= optlen, cp += optlen) { 413 opt = cp[IPOPT_OPTVAL]; 414 if (opt == IPOPT_EOL) 415 break; 416 if (opt == IPOPT_NOP) 417 optlen = 1; 418 else { 419 optlen = cp[IPOPT_OLEN]; 420 if (optlen <= IPOPT_OLEN || optlen > cnt) 421 goto bad; 422 } 423 switch (opt) { 424 425 default: 426 break; 427 428 case IPOPT_LSRR: 429 case IPOPT_SSRR: 430 /* 431 * user process specifies route as: 432 * ->A->B->C->D 433 * D must be our final destination (but we can't 434 * check that since we may not have connected yet). 435 * A is first hop destination, which doesn't appear in 436 * actual IP option, but is stored before the options. 437 */ 438 if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) 439 goto bad; 440 m->m_len -= sizeof(struct in_addr); 441 cnt -= sizeof(struct in_addr); 442 optlen -= sizeof(struct in_addr); 443 cp[IPOPT_OLEN] = optlen; 444 /* 445 * Move first hop before start of options. 446 */ 447 bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), 448 sizeof(struct in_addr)); 449 /* 450 * Then copy rest of options back 451 * to close up the deleted entry. 452 */ 453 ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + 454 sizeof(struct in_addr)), 455 (caddr_t)&cp[IPOPT_OFFSET+1], 456 (unsigned)cnt + sizeof(struct in_addr)); 457 break; 458 } 459 } 460 *pcbopt = m; 461 return (0); 462 463 bad: 464 (void)m_free(m); 465 return (EINVAL); 466 } 467