Deleted Added
full compact
alias_skinny.c (124621) alias_skinny.c (127094)
1/*-
2 * alias_skinny.c
3 *
4 * Copyright (c) 2002, 2003 MarcusCom, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions

--- 13 unchanged lines hidden (view full) ---

22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * Author: Joe Marcus Clarke <marcus@FreeBSD.org>
29 *
1/*-
2 * alias_skinny.c
3 *
4 * Copyright (c) 2002, 2003 MarcusCom, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions

--- 13 unchanged lines hidden (view full) ---

22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * Author: Joe Marcus Clarke <marcus@FreeBSD.org>
29 *
30 * $FreeBSD: head/sys/netinet/libalias/alias_skinny.c 124621 2004-01-17 10:52:21Z phk $
30 * $FreeBSD: head/sys/netinet/libalias/alias_skinny.c 127094 2004-03-16 21:30:41Z des $
31 */
32
33#include <stdio.h>
34#include <string.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <netinet/in_systm.h>
38#include <netinet/in.h>

--- 16 unchanged lines hidden (view full) ---

55 * same packet), the phone sends an IP port message. This message indicates
56 * the TCP port over which it will communicate.
57 *
58 * When a call is placed from the phone, the Call Manager will send an
59 * Open Receive Channel message to the phone to let the caller know someone
60 * has answered. The phone then sends back an Open Receive Channel
61 * Acknowledgement. In this packet, the phone sends its IP address again,
62 * and the UDP port over which the voice traffic should flow. These values
31 */
32
33#include <stdio.h>
34#include <string.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <netinet/in_systm.h>
38#include <netinet/in.h>

--- 16 unchanged lines hidden (view full) ---

55 * same packet), the phone sends an IP port message. This message indicates
56 * the TCP port over which it will communicate.
57 *
58 * When a call is placed from the phone, the Call Manager will send an
59 * Open Receive Channel message to the phone to let the caller know someone
60 * has answered. The phone then sends back an Open Receive Channel
61 * Acknowledgement. In this packet, the phone sends its IP address again,
62 * and the UDP port over which the voice traffic should flow. These values
63 * need translation. Right after the Open Receive Channel Acknowledgement,
63 * need translation. Right after the Open Receive Channel Acknowledgement,
64 * the Call Manager sends a Start Media Transmission message indicating the
64 * the Call Manager sends a Start Media Transmission message indicating the
65 * call is connected. This message contains the IP address and UDP port
66 * number of the remote (called) party. Once this message is translated, the
65 * call is connected. This message contains the IP address and UDP port
66 * number of the remote (called) party. Once this message is translated, the
67 * call can commence. The called part sends the first UDP packet to the
68 * calling phone at the pre-arranged UDP port in the Open Receive Channel
69 * Acknowledgement.
70 *
71 * Skinny is a Cisco-proprietary protocol and is a trademark of Cisco Systems,
72 * Inc. All rights reserved.
73*/
74
75/* #define DEBUG 1 */
76
77/* Message types that need translating */
78#define REG_MSG 0x00000001
79#define IP_PORT_MSG 0x00000002
80#define OPNRCVCH_ACK 0x00000022
81#define START_MEDIATX 0x0000008a
82
83struct skinny_header {
67 * call can commence. The called part sends the first UDP packet to the
68 * calling phone at the pre-arranged UDP port in the Open Receive Channel
69 * Acknowledgement.
70 *
71 * Skinny is a Cisco-proprietary protocol and is a trademark of Cisco Systems,
72 * Inc. All rights reserved.
73*/
74
75/* #define DEBUG 1 */
76
77/* Message types that need translating */
78#define REG_MSG 0x00000001
79#define IP_PORT_MSG 0x00000002
80#define OPNRCVCH_ACK 0x00000022
81#define START_MEDIATX 0x0000008a
82
83struct skinny_header {
84 u_int32_t len;
85 u_int32_t reserved;
86 u_int32_t msgId;
84 u_int32_t len;
85 u_int32_t reserved;
86 u_int32_t msgId;
87};
88
89struct RegisterMessage {
87};
88
89struct RegisterMessage {
90 u_int32_t msgId;
91 char devName[16];
92 u_int32_t uid;
93 u_int32_t instance;
94 u_int32_t ipAddr;
95 u_char devType;
96 u_int32_t maxStreams;
90 u_int32_t msgId;
91 char devName [16];
92 u_int32_t uid;
93 u_int32_t instance;
94 u_int32_t ipAddr;
95 u_char devType;
96 u_int32_t maxStreams;
97};
98
99struct IpPortMessage {
97};
98
99struct IpPortMessage {
100 u_int32_t msgId;
101 u_int32_t stationIpPort; /* Note: Skinny uses 32-bit port
102 * numbers */
100 u_int32_t msgId;
101 u_int32_t stationIpPort; /* Note: Skinny uses 32-bit port
102 * numbers */
103};
104
105struct OpenReceiveChannelAck {
103};
104
105struct OpenReceiveChannelAck {
106 u_int32_t msgId;
107 u_int32_t status;
108 u_int32_t ipAddr;
109 u_int32_t port;
110 u_int32_t passThruPartyID;
106 u_int32_t msgId;
107 u_int32_t status;
108 u_int32_t ipAddr;
109 u_int32_t port;
110 u_int32_t passThruPartyID;
111};
112
113struct StartMediaTransmission {
111};
112
113struct StartMediaTransmission {
114 u_int32_t msgId;
115 u_int32_t conferenceID;
116 u_int32_t passThruPartyID;
117 u_int32_t remoteIpAddr;
118 u_int32_t remotePort;
119 u_int32_t MSPacket;
120 u_int32_t payloadCap;
121 u_int32_t precedence;
122 u_int32_t silenceSuppression;
123 u_short maxFramesPerPacket;
124 u_int32_t G723BitRate;
114 u_int32_t msgId;
115 u_int32_t conferenceID;
116 u_int32_t passThruPartyID;
117 u_int32_t remoteIpAddr;
118 u_int32_t remotePort;
119 u_int32_t MSPacket;
120 u_int32_t payloadCap;
121 u_int32_t precedence;
122 u_int32_t silenceSuppression;
123 u_short maxFramesPerPacket;
124 u_int32_t G723BitRate;
125};
126
127typedef enum {
125};
126
127typedef enum {
128 ClientToServer = 0,
129 ServerToClient = 1
128 ClientToServer = 0,
129 ServerToClient = 1
130} ConvDirection;
131
132
133static int
134alias_skinny_reg_msg(struct RegisterMessage *reg_msg, struct ip *pip,
130} ConvDirection;
131
132
133static int
134alias_skinny_reg_msg(struct RegisterMessage *reg_msg, struct ip *pip,
135 struct tcphdr *tc, struct alias_link *link,
136 ConvDirection direction)
135 struct tcphdr *tc, struct alias_link *link,
136 ConvDirection direction)
137{
137{
138 reg_msg->ipAddr = (u_int32_t) GetAliasAddress(link).s_addr;
138 reg_msg->ipAddr = (u_int32_t) GetAliasAddress(link).s_addr;
139
139
140 tc->th_sum = 0;
141 tc->th_sum = TcpChecksum(pip);
140 tc->th_sum = 0;
141 tc->th_sum = TcpChecksum(pip);
142
142
143 return 0;
143 return 0;
144}
145
146static int
147alias_skinny_startmedia(struct StartMediaTransmission *start_media,
144}
145
146static int
147alias_skinny_startmedia(struct StartMediaTransmission *start_media,
148 struct ip *pip, struct tcphdr *tc,
149 struct alias_link *link, u_int32_t localIpAddr,
150 ConvDirection direction)
148 struct ip *pip, struct tcphdr *tc,
149 struct alias_link *link, u_int32_t localIpAddr,
150 ConvDirection direction)
151{
151{
152 struct in_addr dst, src;
152 struct in_addr dst, src;
153
153
154 dst.s_addr = start_media->remoteIpAddr;
155 src.s_addr = localIpAddr;
154 dst.s_addr = start_media->remoteIpAddr;
155 src.s_addr = localIpAddr;
156
156
157 /* XXX I should probably handle in bound global translations as well. */
157 /*
158 * XXX I should probably handle in bound global translations as
159 * well.
160 */
158
161
159 return 0;
162 return 0;
160}
161
162static int
163alias_skinny_port_msg(struct IpPortMessage *port_msg, struct ip *pip,
163}
164
165static int
166alias_skinny_port_msg(struct IpPortMessage *port_msg, struct ip *pip,
164 struct tcphdr *tc, struct alias_link *link,
165 ConvDirection direction)
167 struct tcphdr *tc, struct alias_link *link,
168 ConvDirection direction)
166{
169{
167 port_msg->stationIpPort = (u_int32_t) ntohs(GetAliasPort(link));
170 port_msg->stationIpPort = (u_int32_t) ntohs(GetAliasPort(link));
168
171
169 tc->th_sum = 0;
170 tc->th_sum = TcpChecksum(pip);
172 tc->th_sum = 0;
173 tc->th_sum = TcpChecksum(pip);
171
174
172 return 0;
175 return 0;
173}
174
175static int
176alias_skinny_opnrcvch_ack(struct libalias *la, struct OpenReceiveChannelAck *opnrcvch_ack,
176}
177
178static int
179alias_skinny_opnrcvch_ack(struct libalias *la, struct OpenReceiveChannelAck *opnrcvch_ack,
177 struct ip * pip, struct tcphdr *tc,
178 struct alias_link *link, u_int32_t *localIpAddr,
179 ConvDirection direction)
180 struct ip *pip, struct tcphdr *tc,
181 struct alias_link *link, u_int32_t * localIpAddr,
182 ConvDirection direction)
180{
183{
181 struct in_addr null_addr;
182 struct alias_link *opnrcv_link;
183 u_int32_t localPort;
184 struct in_addr null_addr;
185 struct alias_link *opnrcv_link;
186 u_int32_t localPort;
184
187
185 *localIpAddr = (u_int32_t) opnrcvch_ack->ipAddr;
186 localPort = opnrcvch_ack->port;
188 *localIpAddr = (u_int32_t) opnrcvch_ack->ipAddr;
189 localPort = opnrcvch_ack->port;
187
190
188 null_addr.s_addr = INADDR_ANY;
189 opnrcv_link = FindUdpTcpOut(la, pip->ip_src, null_addr,
190 htons((u_short) opnrcvch_ack->port), 0,
191 IPPROTO_UDP, 1);
192 opnrcvch_ack->ipAddr = (u_int32_t) GetAliasAddress(opnrcv_link).s_addr;
193 opnrcvch_ack->port = (u_int32_t) ntohs(GetAliasPort(opnrcv_link));
191 null_addr.s_addr = INADDR_ANY;
192 opnrcv_link = FindUdpTcpOut(la, pip->ip_src, null_addr,
193 htons((u_short) opnrcvch_ack->port), 0,
194 IPPROTO_UDP, 1);
195 opnrcvch_ack->ipAddr = (u_int32_t) GetAliasAddress(opnrcv_link).s_addr;
196 opnrcvch_ack->port = (u_int32_t) ntohs(GetAliasPort(opnrcv_link));
194
197
195 tc->th_sum = 0;
196 tc->th_sum = TcpChecksum(pip);
198 tc->th_sum = 0;
199 tc->th_sum = TcpChecksum(pip);
197
200
198 return 0;
201 return 0;
199}
200
201void
202AliasHandleSkinny(struct libalias *la, struct ip *pip, struct alias_link *link)
203{
202}
203
204void
205AliasHandleSkinny(struct libalias *la, struct ip *pip, struct alias_link *link)
206{
204 int hlen, tlen, dlen;
205 struct tcphdr *tc;
206 u_int32_t msgId, len, t, lip;
207 struct skinny_header *sd;
208 int orig_len, skinny_hdr_len = sizeof(struct skinny_header);
209 ConvDirection direction;
207 int hlen, tlen, dlen;
208 struct tcphdr *tc;
209 u_int32_t msgId, len, t, lip;
210 struct skinny_header *sd;
211 int orig_len, skinny_hdr_len = sizeof(struct skinny_header);
212 ConvDirection direction;
210
213
211 tc = (struct tcphdr *) ((char *)pip + (pip->ip_hl << 2));
212 hlen = (pip->ip_hl + tc->th_off) << 2;
213 tlen = ntohs(pip->ip_len);
214 dlen = tlen - hlen;
214 tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
215 hlen = (pip->ip_hl + tc->th_off) << 2;
216 tlen = ntohs(pip->ip_len);
217 dlen = tlen - hlen;
215
218
216 sd = (struct skinny_header *) ((char *)pip + hlen);
219 sd = (struct skinny_header *)((char *)pip + hlen);
217
220
218 /*
219 * XXX This direction is reserved for future use. I still need to
220 * handle the scenario where the call manager is on the inside, and
221 * the calling phone is on the global outside.
222 */
223 if (ntohs(tc->th_dport) == la->skinnyPort) {
224 direction = ClientToServer;
225 } else if (ntohs(tc->th_sport) == la->skinnyPort) {
226 direction = ServerToClient;
227 } else {
221 /*
222 * XXX This direction is reserved for future use. I still need to
223 * handle the scenario where the call manager is on the inside, and
224 * the calling phone is on the global outside.
225 */
226 if (ntohs(tc->th_dport) == la->skinnyPort) {
227 direction = ClientToServer;
228 } else if (ntohs(tc->th_sport) == la->skinnyPort) {
229 direction = ServerToClient;
230 } else {
228#ifdef DEBUG
231#ifdef DEBUG
229 fprintf(stderr,
230 "PacketAlias/Skinny: Invalid port number, not a Skinny packet\n");
232 fprintf(stderr,
233 "PacketAlias/Skinny: Invalid port number, not a Skinny packet\n");
231#endif
234#endif
232 return;
233 }
235 return;
236 }
234
237
235 orig_len = dlen;
236 /*
237 * Skinny packets can contain many messages. We need to loop through
238 * the packet using len to determine message boundaries. This comes
239 * into play big time with port messages being in the same packet as
240 * register messages. Also, open receive channel acks are
241 * usually buried in a pakcet some 400 bytes long.
242 */
243 while (dlen >= skinny_hdr_len) {
244 len = (sd->len);
245 msgId = (sd->msgId);
246 t = len;
238 orig_len = dlen;
239 /*
240 * Skinny packets can contain many messages. We need to loop
241 * through the packet using len to determine message boundaries.
242 * This comes into play big time with port messages being in the
243 * same packet as register messages. Also, open receive channel
244 * acks are usually buried in a pakcet some 400 bytes long.
245 */
246 while (dlen >= skinny_hdr_len) {
247 len = (sd->len);
248 msgId = (sd->msgId);
249 t = len;
247
250
248 if (t < 0 || t > orig_len || t > dlen) {
251 if (t < 0 || t > orig_len || t > dlen) {
249#ifdef DEBUG
252#ifdef DEBUG
250 fprintf(stderr,
251 "PacketAlias/Skinny: Not a skinny packet, invalid length \n");
253 fprintf(stderr,
254 "PacketAlias/Skinny: Not a skinny packet, invalid length \n");
252#endif
255#endif
253 return;
254 }
255 switch (msgId) {
256 case REG_MSG:
257 {
258 struct RegisterMessage *reg_mesg;
256 return;
257 }
258 switch (msgId) {
259 case REG_MSG: {
260 struct RegisterMessage *reg_mesg;
259
261
260 if (len < sizeof(struct RegisterMessage)) {
262 if (len < sizeof(struct RegisterMessage)) {
261#ifdef DEBUG
263#ifdef DEBUG
262 fprintf(stderr,
263 "PacketAlias/Skinny: Not a skinny packet, bad registration message\n");
264 fprintf(stderr,
265 "PacketAlias/Skinny: Not a skinny packet, bad registration message\n");
264#endif
266#endif
265 return;
266 }
267 reg_mesg = (struct RegisterMessage *) & sd->msgId;
267 return;
268 }
269 reg_mesg = (struct RegisterMessage *)&sd->msgId;
268#ifdef DEBUG
270#ifdef DEBUG
269 fprintf(stderr,
270 "PacketAlias/Skinny: Received a register message");
271 fprintf(stderr,
272 "PacketAlias/Skinny: Received a register message");
271#endif
273#endif
272 alias_skinny_reg_msg(reg_mesg, pip, tc, link, direction);
273 }
274 break;
275 case IP_PORT_MSG:
276 {
277 struct IpPortMessage *port_mesg;
278 if (len < sizeof(struct IpPortMessage)) {
274 alias_skinny_reg_msg(reg_mesg, pip, tc, link, direction);
275 break;
276 }
277 case IP_PORT_MSG: {
278 struct IpPortMessage *port_mesg;
279
280 if (len < sizeof(struct IpPortMessage)) {
279#ifdef DEBUG
281#ifdef DEBUG
280 fprintf(stderr,
281 "PacketAlias/Skinny: Not a skinny packet, port message\n");
282 fprintf(stderr,
283 "PacketAlias/Skinny: Not a skinny packet, port message\n");
282#endif
284#endif
283 return;
284 }
285 return;
286 }
285#ifdef DEBUG
287#ifdef DEBUG
286 fprintf(stderr
287 "PacketAlias/Skinny: Received ipport message\n");
288 fprintf(stderr
289 "PacketAlias/Skinny: Received ipport message\n");
288#endif
290#endif
289 port_mesg = (struct IpPortMessage *) & sd->msgId;
290 alias_skinny_port_msg(port_mesg, pip, tc, link, direction);
291 }
292 break;
293 case OPNRCVCH_ACK:
294 {
295 struct OpenReceiveChannelAck *opnrcvchn_ack;
291 port_mesg = (struct IpPortMessage *)&sd->msgId;
292 alias_skinny_port_msg(port_mesg, pip, tc, link, direction);
293 break;
294 }
295 case OPNRCVCH_ACK: {
296 struct OpenReceiveChannelAck *opnrcvchn_ack;
296
297
297 if (len < sizeof(struct OpenReceiveChannelAck)) {
298 if (len < sizeof(struct OpenReceiveChannelAck)) {
298#ifdef DEBUG
299#ifdef DEBUG
299 fprintf(stderr,
300 "PacketAlias/Skinny: Not a skinny packet, packet,OpnRcvChnAckMsg\n");
300 fprintf(stderr,
301 "PacketAlias/Skinny: Not a skinny packet, packet,OpnRcvChnAckMsg\n");
301#endif
302#endif
302 return;
303 }
303 return;
304 }
304#ifdef DEBUG
305#ifdef DEBUG
305 fprintf(stderr,
306 "PacketAlias/Skinny: Received open rcv channel msg\n");
306 fprintf(stderr,
307 "PacketAlias/Skinny: Received open rcv channel msg\n");
307#endif
308#endif
308 opnrcvchn_ack = (struct OpenReceiveChannelAck *) & sd->msgId;
309 alias_skinny_opnrcvch_ack(la, opnrcvchn_ack, pip, tc, link, &lip, direction);
310 }
311 break;
312 case START_MEDIATX:
313 {
314 struct StartMediaTransmission *startmedia_tx;
309 opnrcvchn_ack = (struct OpenReceiveChannelAck *)&sd->msgId;
310 alias_skinny_opnrcvch_ack(la, opnrcvchn_ack, pip, tc, link, &lip, direction);
311 break;
312 }
313 case START_MEDIATX: {
314 struct StartMediaTransmission *startmedia_tx;
315
315
316 if (len < sizeof(struct StartMediaTransmission)) {
316 if (len < sizeof(struct StartMediaTransmission)) {
317#ifdef DEBUG
317#ifdef DEBUG
318 fprintf(stderr,
319 "PacketAlias/Skinny: Not a skinny packet,StartMediaTx Message\n");
318 fprintf(stderr,
319 "PacketAlias/Skinny: Not a skinny packet,StartMediaTx Message\n");
320#endif
320#endif
321 return;
322 }
321 return;
322 }
323#ifdef DEBUG
323#ifdef DEBUG
324 fprintf(stderr,
325 "PacketAlias/Skinny: Received start media trans msg\n");
324 fprintf(stderr,
325 "PacketAlias/Skinny: Received start media trans msg\n");
326#endif
326#endif
327 startmedia_tx = (struct StartMediaTransmission *) & sd->msgId;
328 alias_skinny_startmedia(startmedia_tx, pip, tc, link, lip, direction);
329 }
330 break;
331 default:
332 break;
333 }
334 /* Place the pointer at the next message in the packet. */
335 dlen -= len + (skinny_hdr_len - sizeof(msgId));
336 sd = (struct skinny_header *) (((char *)&sd->msgId) + len);
337 }
327 startmedia_tx = (struct StartMediaTransmission *)&sd->msgId;
328 alias_skinny_startmedia(startmedia_tx, pip, tc, link, lip, direction);
329 break;
330 }
331 default:
332 break;
333 }
334 /* Place the pointer at the next message in the packet. */
335 dlen -= len + (skinny_hdr_len - sizeof(msgId));
336 sd = (struct skinny_header *)(((char *)&sd->msgId) + len);
337 }
338}
338}