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