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