1 /* ip_output.c 1.14 81/11/18 */ 2 3 #include "../h/param.h" 4 #include "../h/mbuf.h" 5 #include "../h/mtpr.h" 6 #include "../h/socket.h" 7 #include "../h/socketvar.h" 8 #include "../net/inet.h" 9 #include "../net/inet_systm.h" 10 #include "../net/imp.h" 11 #include "../net/inet_host.h" 12 #include "../net/ip.h" 13 #include "../net/ip_var.h" 14 15 ip_output(m) 16 struct mbuf *m; 17 { 18 register struct ip *ip = mtod(m, struct ip *); 19 int len, hlen = ip->ip_hl << 2, off; 20 21 COUNT(IP_OUTPUT); 22 /* 23 * Fill in IP header. 24 */ 25 ip->ip_v = IPVERSION; 26 ip->ip_hl = hlen >> 2; 27 ip->ip_off &= IP_DF; 28 ip->ip_ttl = MAXTTL; 29 ip->ip_id = ip_id++; 30 31 /* 32 * If small enough for interface, can just send directly. 33 */ 34 if (ip->ip_len <= MTU) { 35 ip_send(ip); 36 return; 37 } 38 39 /* 40 * Too large for interface; fragment if possible. 41 * Must be able to put at least 8 bytes per fragment. 42 */ 43 if (ip->ip_off & IP_DF) 44 goto bad; 45 len = (MTU-hlen) &~ 7; 46 if (len < 8) 47 goto bad; 48 49 /* 50 * Discard IP header from logical mbuf for m_copy's sake. 51 * Loop through length of segment, make a copy of each 52 * part and output. 53 */ 54 m->m_len -= sizeof (struct ip); 55 m->m_off += sizeof (struct ip); 56 for (off = 0; off < ip->ip_len; off += len) { 57 struct mbuf *mh = m_get(0); 58 struct ip *mhip; 59 60 if (mh == 0) 61 goto bad; 62 mh->m_off = MMAXOFF - hlen; 63 mhip = mtod(mh, struct ip *); 64 *mhip = *ip; 65 if (ip->ip_hl > sizeof (struct ip) >> 2) { 66 int olen = ip_optcopy(ip, mhip, off); 67 mh->m_len = sizeof (struct ip) + olen; 68 } else 69 mh->m_len = sizeof (struct ip); 70 mhip->ip_off = off; 71 if (off + len >= ip->ip_len) 72 mhip->ip_len = ip->ip_len - off; 73 else { 74 mhip->ip_len = len; 75 mhip->ip_off |= IP_MF; 76 } 77 mh->m_next = m_copy(m, off, len); 78 if (mh->m_next == 0) { 79 m_free(mh); 80 goto bad; 81 } 82 ip_send(mh); 83 } 84 bad: 85 m_freem(m); 86 } 87 88 /* 89 * Copy options from ip to jp. 90 * If off is 0 all options are copies 91 * otherwise copy selectively. 92 */ 93 ip_optcopy(ip, jp, off) 94 struct ip *ip, *jp; 95 int off; 96 { 97 register u_char *cp, *dp; 98 int opt, optlen, cnt; 99 100 cp = (u_char *)(ip + 1); 101 dp = (u_char *)(jp + 1); 102 cnt = (ip->ip_hl << 2) - sizeof (struct ip); 103 for (; cnt > 0; cnt -= optlen, cp += optlen) { 104 opt = cp[0]; 105 if (opt == IPOPT_EOL) 106 break; 107 if (opt == IPOPT_NOP) 108 optlen = 1; 109 else 110 optlen = cp[1]; 111 if (optlen > cnt) /* XXX */ 112 optlen = cnt; /* XXX */ 113 if (off == 0 || IPOPT_COPIED(opt)) { 114 bcopy(cp, dp, optlen); 115 dp += optlen; 116 } 117 } 118 for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) 119 *dp++ = IPOPT_EOL; 120 return (optlen); 121 } 122 123 ip_send(ip) 124 register struct ip *ip; 125 { 126 register struct mbuf *m; 127 register struct imp *l; 128 int hlen = ip->ip_hl << 2; 129 int s; 130 COUNT(IP_SEND); 131 132 m = dtom(ip); 133 l = (struct imp *)(mtod(m, caddr_t) - L1822); 134 l->i_shost = ip->ip_src.s_host; 135 l->i_dhost = ip->ip_dst.s_host; 136 l->i_type = IPTYPE; 137 ip->ip_sum = 0; 138 ip->ip_len = htons((u_short)ip->ip_len); 139 ip->ip_id = htons(ip->ip_id); 140 ip->ip_off = htons((u_short)ip->ip_off); 141 ip->ip_sum = inet_cksum(m, hlen); 142 m->m_off -= L1822; 143 m->m_len += L1822; 144 m->m_act = NULL; 145 #ifndef IMPLOOP 146 s = splimp(); 147 if (imp_stat.outq_head != NULL) 148 imp_stat.outq_tail->m_act = m; 149 else 150 imp_stat.outq_head = m; 151 imp_stat.outq_tail = m; 152 splx(s); 153 if (!imp_stat.outactive) 154 enstart(0); 155 #else 156 if (imp_stat.inq_head != NULL) 157 imp_stat.inq_tail->m_act = m; 158 else 159 imp_stat.inq_head = m; 160 imp_stat.inq_tail = m; 161 setsoftnet(); 162 #endif IMPLOOP 163 } 164